[automerger skipped] Merge changes from topic "cherrypick-cherrypick-cherrypick-nnapi_burst_deserialize-fvwo2wt1ja-mueq5vhv8v-2ym2uz8wjy" into sc-qpr1-dev am: c63fef57a2 -s ours am: 87279d70a9 -s ours am: 8662e87ac4 -s ours am: 577961260b -s ours am: affc214eb8 -s ours
am skip reason: Merged-In I6bfb02a5cd76258284cc4d797a4508b21e672c4b with SHA-1 7a9e483f4b is already in history
Original change: https://googleplex-android-review.googlesource.com/c/platform/hardware/interfaces/+/20614826
Change-Id: I20d2cbeba0ed0e38cbecc50d4ef295683edf61d2
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/OWNERS b/OWNERS
index 3a1a038..a53d83e 100644
--- a/OWNERS
+++ b/OWNERS
@@ -9,6 +9,3 @@
# historical/backup
maco@google.com
-
-# vts tests
-guangzhu@google.com
diff --git a/audio/OWNERS b/audio/OWNERS
new file mode 100644
index 0000000..ede448c
--- /dev/null
+++ b/audio/OWNERS
@@ -0,0 +1 @@
+per-file README.md = elaurent@google.com,mnaganov@google.com
diff --git a/audio/aidl/Android.bp b/audio/aidl/Android.bp
index 0b5b993..563ee62 100644
--- a/audio/aidl/Android.bp
+++ b/audio/aidl/Android.bp
@@ -23,9 +23,18 @@
default_applicable_licenses: ["hardware_interfaces_license"],
}
+aidl_interface_defaults {
+ name: "android.hardware.audio_defaults",
+ host_supported: true,
+ vendor_available: true,
+ stability: "vintf",
+}
+
aidl_interface {
name: "android.hardware.audio.common",
- vendor_available: true,
+ defaults: [
+ "android.hardware.audio_defaults",
+ ],
srcs: [
"android/hardware/audio/common/PlaybackTrackMetadata.aidl",
"android/hardware/audio/common/RecordTrackMetadata.aidl",
@@ -33,9 +42,8 @@
"android/hardware/audio/common/SourceMetadata.aidl",
],
imports: [
- "android.media.audio.common.types-V1",
+ "android.media.audio.common.types-V2",
],
- stability: "vintf",
backend: {
cpp: {
enabled: true,
@@ -49,12 +57,9 @@
],
},
ndk: {
- vndk: {
- enabled: true,
- },
apex_available: [
"//apex_available:platform",
- "com.android.bluetooth",
+ "com.android.btservices",
],
min_sdk_version: "31",
},
@@ -62,8 +67,158 @@
versions_with_info: [
{
version: "1",
- imports: ["android.media.audio.common.types-V1"],
+ imports: ["android.media.audio.common.types-V2"],
},
+ // IMPORTANT: Update latest_android_hardware_audio_common every time you
+ // add the latest frozen version to versions_with_info
],
}
+
+// Note: This should always be one version ahead of the last frozen version
+latest_android_hardware_audio_common = "android.hardware.audio.common-V1"
+
+// Modules that depend on android.hardware.audio.common directly can include
+// the following cc_defaults to avoid explicitly managing dependency versions
+// across many scattered files.
+cc_defaults {
+ name: "latest_android_hardware_audio_common_cpp_static",
+ static_libs: [
+ latest_android_hardware_audio_common + "-cpp",
+ ],
+}
+
+cc_defaults {
+ name: "latest_android_hardware_audio_common_ndk_static",
+ static_libs: [
+ latest_android_hardware_audio_common + "-ndk",
+ ],
+}
+
+cc_defaults {
+ name: "latest_android_hardware_audio_common_ndk_shared",
+ shared_libs: [
+ latest_android_hardware_audio_common + "-ndk",
+ ],
+}
+
+aidl_interface {
+ name: "android.hardware.audio.core",
+ defaults: [
+ "android.hardware.audio_defaults",
+ ],
+ srcs: [
+ "android/hardware/audio/core/AudioMode.aidl",
+ "android/hardware/audio/core/AudioPatch.aidl",
+ "android/hardware/audio/core/AudioRoute.aidl",
+ "android/hardware/audio/core/IConfig.aidl",
+ "android/hardware/audio/core/IModule.aidl",
+ "android/hardware/audio/core/IStreamCallback.aidl",
+ "android/hardware/audio/core/IStreamIn.aidl",
+ "android/hardware/audio/core/IStreamOut.aidl",
+ "android/hardware/audio/core/ITelephony.aidl",
+ "android/hardware/audio/core/MmapBufferDescriptor.aidl",
+ "android/hardware/audio/core/ModuleDebug.aidl",
+ "android/hardware/audio/core/StreamDescriptor.aidl",
+ "android/hardware/audio/core/SurroundSoundConfig.aidl",
+ ],
+ imports: [
+ "android.hardware.common-V2",
+ "android.hardware.common.fmq-V1",
+ "android.hardware.audio.common-V1",
+ "android.media.audio.common.types-V2",
+ ],
+ backend: {
+ // The C++ backend is disabled transitively due to use of FMQ.
+ cpp: {
+ enabled: false,
+ },
+ java: {
+ sdk_version: "module_current",
+ },
+ },
+ versions_with_info: [
+ // IMPORTANT: Update latest_android_hardware_audio_core every time you
+ // add the latest frozen version to versions_with_info
+ ],
+}
+
+// Note: This should always be one version ahead of the last frozen version
+latest_android_hardware_audio_core = "android.hardware.audio.core-V1"
+
+// Modules that depend on android.hardware.audio.core directly can include
+// the following cc_defaults to avoid explicitly managing dependency versions
+// across many scattered files.
+cc_defaults {
+ name: "latest_android_hardware_audio_core_ndk_shared",
+ shared_libs: [
+ latest_android_hardware_audio_core + "-ndk",
+ ],
+}
+
+cc_defaults {
+ name: "latest_android_hardware_audio_core_ndk_static",
+ static_libs: [
+ latest_android_hardware_audio_core + "-ndk",
+ ],
+}
+
+aidl_interface {
+ name: "android.hardware.audio.effect",
+ defaults: [
+ "android.hardware.audio_defaults",
+ ],
+ srcs: [
+ "android/hardware/audio/effect/BassBoost.aidl",
+ "android/hardware/audio/effect/Capability.aidl",
+ "android/hardware/audio/effect/CommandId.aidl",
+ "android/hardware/audio/effect/Descriptor.aidl",
+ "android/hardware/audio/effect/Downmix.aidl",
+ "android/hardware/audio/effect/DynamicsProcessing.aidl",
+ "android/hardware/audio/effect/Equalizer.aidl",
+ "android/hardware/audio/effect/Flags.aidl",
+ "android/hardware/audio/effect/HapticGenerator.aidl",
+ "android/hardware/audio/effect/IEffect.aidl",
+ "android/hardware/audio/effect/IFactory.aidl",
+ "android/hardware/audio/effect/LoudnessEnhancer.aidl",
+ "android/hardware/audio/effect/Parameter.aidl",
+ "android/hardware/audio/effect/Processing.aidl",
+ "android/hardware/audio/effect/Reverb.aidl",
+ "android/hardware/audio/effect/State.aidl",
+ "android/hardware/audio/effect/VendorExtension.aidl",
+ "android/hardware/audio/effect/Virtualizer.aidl",
+ "android/hardware/audio/effect/Visualizer.aidl",
+ "android/hardware/audio/effect/Volume.aidl",
+ ],
+ imports: [
+ "android.hardware.common-V2",
+ "android.hardware.common.fmq-V1",
+ "android.hardware.audio.common-V1",
+ "android.media.audio.common.types-V2",
+ ],
+ backend: {
+ // The C++ backend is disabled transitively due to use of FMQ.
+ cpp: {
+ enabled: false,
+ },
+ java: {
+ sdk_version: "module_current",
+ },
+ },
+}
+
+latest_android_hardware_audio_effect = "android.hardware.audio.effect-V1"
+
+cc_defaults {
+ name: "latest_android_hardware_audio_effect_ndk_shared",
+ shared_libs: [
+ latest_android_hardware_audio_effect + "-ndk",
+ ],
+}
+
+cc_defaults {
+ name: "latest_android_hardware_audio_effect_ndk_static",
+ static_libs: [
+ latest_android_hardware_audio_effect + "-ndk",
+ ],
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/AudioMode.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/AudioMode.aidl
new file mode 100644
index 0000000..336f9b5
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/AudioMode.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.audio.core;
+@Backing(type="int") @VintfStability
+enum AudioMode {
+ NORMAL = 0,
+ RINGTONE = 1,
+ IN_CALL = 2,
+ IN_COMMUNICATION = 3,
+ CALL_SCREEN = 4,
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/AudioPatch.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/AudioPatch.aidl
new file mode 100644
index 0000000..078b5ea
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/AudioPatch.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.audio.core;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable AudioPatch {
+ int id;
+ int[] sourcePortConfigIds;
+ int[] sinkPortConfigIds;
+ int minimumStreamBufferSizeFrames;
+ int[] latenciesMs;
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/AudioRoute.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/AudioRoute.aidl
new file mode 100644
index 0000000..deeef87
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/AudioRoute.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.audio.core;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable AudioRoute {
+ int[] sourcePortIds;
+ int sinkPortId;
+ boolean isExclusive;
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IConfig.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IConfig.aidl
new file mode 100644
index 0000000..163b7a0
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IConfig.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.audio.core;
+@VintfStability
+interface IConfig {
+ android.hardware.audio.core.SurroundSoundConfig getSurroundSoundConfig();
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IModule.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IModule.aidl
new file mode 100644
index 0000000..7f960e0
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IModule.aidl
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.audio.core;
+@VintfStability
+interface IModule {
+ void setModuleDebug(in android.hardware.audio.core.ModuleDebug debug);
+ @nullable android.hardware.audio.core.ITelephony getTelephony();
+ android.media.audio.common.AudioPort connectExternalDevice(in android.media.audio.common.AudioPort templateIdAndAdditionalData);
+ void disconnectExternalDevice(int portId);
+ android.hardware.audio.core.AudioPatch[] getAudioPatches();
+ android.media.audio.common.AudioPort getAudioPort(int portId);
+ android.media.audio.common.AudioPortConfig[] getAudioPortConfigs();
+ android.media.audio.common.AudioPort[] getAudioPorts();
+ android.hardware.audio.core.AudioRoute[] getAudioRoutes();
+ android.hardware.audio.core.AudioRoute[] getAudioRoutesForAudioPort(int portId);
+ android.hardware.audio.core.IModule.OpenInputStreamReturn openInputStream(in android.hardware.audio.core.IModule.OpenInputStreamArguments args);
+ android.hardware.audio.core.IModule.OpenOutputStreamReturn openOutputStream(in android.hardware.audio.core.IModule.OpenOutputStreamArguments args);
+ android.hardware.audio.core.AudioPatch setAudioPatch(in android.hardware.audio.core.AudioPatch requested);
+ boolean setAudioPortConfig(in android.media.audio.common.AudioPortConfig requested, out android.media.audio.common.AudioPortConfig suggested);
+ void resetAudioPatch(int patchId);
+ void resetAudioPortConfig(int portConfigId);
+ boolean getMasterMute();
+ void setMasterMute(boolean mute);
+ float getMasterVolume();
+ void setMasterVolume(float volume);
+ boolean getMicMute();
+ void setMicMute(boolean mute);
+ void updateAudioMode(android.hardware.audio.core.AudioMode mode);
+ void updateScreenRotation(android.hardware.audio.core.IModule.ScreenRotation rotation);
+ void updateScreenState(boolean isTurnedOn);
+ @VintfStability
+ parcelable OpenInputStreamArguments {
+ int portConfigId;
+ android.hardware.audio.common.SinkMetadata sinkMetadata;
+ long bufferSizeFrames;
+ }
+ @VintfStability
+ parcelable OpenInputStreamReturn {
+ android.hardware.audio.core.IStreamIn stream;
+ android.hardware.audio.core.StreamDescriptor desc;
+ }
+ @VintfStability
+ parcelable OpenOutputStreamArguments {
+ int portConfigId;
+ android.hardware.audio.common.SourceMetadata sourceMetadata;
+ @nullable android.media.audio.common.AudioOffloadInfo offloadInfo;
+ long bufferSizeFrames;
+ @nullable android.hardware.audio.core.IStreamCallback callback;
+ }
+ @VintfStability
+ parcelable OpenOutputStreamReturn {
+ android.hardware.audio.core.IStreamOut stream;
+ android.hardware.audio.core.StreamDescriptor desc;
+ }
+ @Backing(type="int") @VintfStability
+ enum ScreenRotation {
+ DEG_0 = 0,
+ DEG_90 = 1,
+ DEG_180 = 2,
+ DEG_270 = 3,
+ }
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamCallback.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamCallback.aidl
new file mode 100644
index 0000000..5a2ab78
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamCallback.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.audio.core;
+@VintfStability
+interface IStreamCallback {
+ oneway void onTransferReady();
+ oneway void onError();
+ oneway void onDrainReady();
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamIn.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamIn.aidl
new file mode 100644
index 0000000..d5ab3e8
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamIn.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.audio.core;
+@VintfStability
+interface IStreamIn {
+ void close();
+ void updateMetadata(in android.hardware.audio.common.SinkMetadata sinkMetadata);
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamOut.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamOut.aidl
new file mode 100644
index 0000000..3021d94
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamOut.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.audio.core;
+@VintfStability
+interface IStreamOut {
+ void close();
+ void updateMetadata(in android.hardware.audio.common.SourceMetadata sourceMetadata);
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ITelephony.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ITelephony.aidl
new file mode 100644
index 0000000..a8c58c1
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ITelephony.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.audio.core;
+@VintfStability
+interface ITelephony {
+ android.hardware.audio.core.AudioMode[] getSupportedAudioModes();
+ void switchAudioMode(android.hardware.audio.core.AudioMode mode);
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/MmapBufferDescriptor.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/MmapBufferDescriptor.aidl
new file mode 100644
index 0000000..6ea1c69
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/MmapBufferDescriptor.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.audio.core;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable MmapBufferDescriptor {
+ android.hardware.common.Ashmem sharedMemory;
+ long burstSizeFrames;
+ int flags;
+ const int FLAG_INDEX_APPLICATION_SHAREABLE = 0;
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ModuleDebug.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ModuleDebug.aidl
new file mode 100644
index 0000000..467d37b
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ModuleDebug.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.audio.core;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable ModuleDebug {
+ boolean simulateDeviceConnections;
+ int streamTransientStateDelayMs;
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/StreamDescriptor.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/StreamDescriptor.aidl
new file mode 100644
index 0000000..3a4271b
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/StreamDescriptor.aidl
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.audio.core;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable StreamDescriptor {
+ android.hardware.common.fmq.MQDescriptor<android.hardware.audio.core.StreamDescriptor.Command,android.hardware.common.fmq.SynchronizedReadWrite> command;
+ android.hardware.common.fmq.MQDescriptor<android.hardware.audio.core.StreamDescriptor.Reply,android.hardware.common.fmq.SynchronizedReadWrite> reply;
+ int frameSizeBytes;
+ long bufferSizeFrames;
+ android.hardware.audio.core.StreamDescriptor.AudioBuffer audio;
+ const int LATENCY_UNKNOWN = -1;
+ @FixedSize @VintfStability
+ parcelable Position {
+ long frames = -1;
+ long timeNs = -1;
+ const long UNKNOWN = -1;
+ }
+ @Backing(type="int") @VintfStability
+ enum State {
+ STANDBY = 1,
+ IDLE = 2,
+ ACTIVE = 3,
+ PAUSED = 4,
+ DRAINING = 5,
+ DRAIN_PAUSED = 6,
+ TRANSFERRING = 7,
+ TRANSFER_PAUSED = 8,
+ ERROR = 100,
+ }
+ @Backing(type="byte") @VintfStability
+ enum DrainMode {
+ DRAIN_UNSPECIFIED = 0,
+ DRAIN_ALL = 1,
+ DRAIN_EARLY_NOTIFY = 2,
+ }
+ @FixedSize @VintfStability
+ union Command {
+ int halReservedExit;
+ android.media.audio.common.Void getStatus;
+ android.media.audio.common.Void start;
+ int burst;
+ android.hardware.audio.core.StreamDescriptor.DrainMode drain;
+ android.media.audio.common.Void standby;
+ android.media.audio.common.Void pause;
+ android.media.audio.common.Void flush;
+ }
+ @FixedSize @VintfStability
+ parcelable Reply {
+ int status;
+ int fmqByteCount;
+ android.hardware.audio.core.StreamDescriptor.Position observable;
+ android.hardware.audio.core.StreamDescriptor.Position hardware;
+ int latencyMs;
+ int xrunFrames;
+ android.hardware.audio.core.StreamDescriptor.State state = android.hardware.audio.core.StreamDescriptor.State.STANDBY;
+ }
+ @VintfStability
+ union AudioBuffer {
+ android.hardware.common.fmq.MQDescriptor<byte,android.hardware.common.fmq.SynchronizedReadWrite> fmq;
+ android.hardware.audio.core.MmapBufferDescriptor mmap;
+ }
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/SurroundSoundConfig.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/SurroundSoundConfig.aidl
new file mode 100644
index 0000000..08a1537
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/SurroundSoundConfig.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.audio.core;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable SurroundSoundConfig {
+ android.hardware.audio.core.SurroundSoundConfig.SurroundFormatFamily[] formatFamilies;
+ @VintfStability
+ parcelable SurroundFormatFamily {
+ android.media.audio.common.AudioFormatDescription primaryFormat;
+ android.media.audio.common.AudioFormatDescription[] subFormats;
+ }
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/BassBoost.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/BassBoost.aidl
new file mode 100644
index 0000000..979ebb8
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/BassBoost.aidl
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.audio.effect;
+@VintfStability
+union BassBoost {
+ android.hardware.audio.effect.VendorExtension vendor;
+ int strengthPm;
+ @VintfStability
+ union Id {
+ int vendorExtensionTag;
+ android.hardware.audio.effect.BassBoost.Tag commonTag;
+ }
+ @VintfStability
+ parcelable Capability {
+ ParcelableHolder extension;
+ boolean strengthSupported;
+ }
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Capability.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Capability.aidl
new file mode 100644
index 0000000..06f2bfe
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Capability.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.audio.effect;
+@VintfStability
+union Capability {
+ android.hardware.audio.effect.VendorExtension vendorExtension;
+ android.hardware.audio.effect.BassBoost.Capability bassBoost;
+ android.hardware.audio.effect.Downmix.Capability downmix;
+ android.hardware.audio.effect.DynamicsProcessing.Capability dynamicsProcessing;
+ android.hardware.audio.effect.Equalizer.Capability equalizer;
+ android.hardware.audio.effect.HapticGenerator.Capability hapticGenerator;
+ android.hardware.audio.effect.LoudnessEnhancer.Capability loudnessEnhancer;
+ android.hardware.audio.effect.Reverb.Capability reverb;
+ android.hardware.audio.effect.Virtualizer.Capability virtualizer;
+ android.hardware.audio.effect.Visualizer.Capability visualizer;
+ android.hardware.audio.effect.Volume.Capability volume;
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/CommandId.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/CommandId.aidl
new file mode 100644
index 0000000..79299ee
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/CommandId.aidl
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.audio.effect;
+@Backing(type="int") @VintfStability
+enum CommandId {
+ START = 0,
+ STOP = 1,
+ RESET = 2,
+ VENDOR_COMMAND_0 = 256,
+ VENDOR_COMMAND_1 = 257,
+ VENDOR_COMMAND_2 = 258,
+ VENDOR_COMMAND_3 = 259,
+ VENDOR_COMMAND_4 = 260,
+ VENDOR_COMMAND_5 = 261,
+ VENDOR_COMMAND_6 = 262,
+ VENDOR_COMMAND_7 = 263,
+ VENDOR_COMMAND_8 = 264,
+ VENDOR_COMMAND_9 = 265,
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Descriptor.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Descriptor.aidl
new file mode 100644
index 0000000..990d369
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Descriptor.aidl
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.audio.effect;
+@VintfStability
+parcelable Descriptor {
+ android.hardware.audio.effect.Descriptor.Common common;
+ android.hardware.audio.effect.Capability capability;
+ const String EFFECT_TYPE_UUID_ENV_REVERB = "c2e5d5f0-94bd-4763-9cac-4e234d06839e";
+ const String EFFECT_TYPE_UUID_PRESET_REVERB = "47382d60-ddd8-11db-bf3a-0002a5d5c51b";
+ const String EFFECT_TYPE_UUID_EQUALIZER = "0bed4300-ddd6-11db-8f34-0002a5d5c51b";
+ const String EFFECT_TYPE_UUID_BASS_BOOST = "0634f220-ddd4-11db-a0fc-0002a5d5c51b";
+ const String EFFECT_TYPE_UUID_VIRTUALIZER = "37cc2c00-dddd-11db-8577-0002a5d5c51b";
+ const String EFFECT_TYPE_UUID_AGC = "0a8abfe0-654c-11e0-ba26-0002a5d5c51b";
+ const String EFFECT_TYPE_UUID_AEC = "7b491460-8d4d-11e0-bd61-0002a5d5c51b";
+ const String EFFECT_TYPE_UUID_NS = "58b4b260-8e06-11e0-aa8e-0002a5d5c51b";
+ const String EFFECT_TYPE_UUID_LOUDNESS_ENHANCER = "fe3199be-aed0-413f-87bb-11260eb63cf1";
+ const String EFFECT_TYPE_UUID_DYNAMICS_PROCESSING = "7261676f-6d75-7369-6364-28e2fd3ac39e";
+ const String EFFECT_TYPE_UUID_HAPTIC_GENERATOR = "1411e6d6-aecd-4021-a1cf-a6aceb0d71e5";
+ const String EFFECT_TYPE_UUID_SPATIALIZER = "ccd4cf09-a79d-46c2-9aae-06a1698d6c8f";
+ const String EFFECT_TYPE_UUID_VOLUME = "09e8ede0-ddde-11db-b4f6-0002a5d5c51b";
+ @VintfStability
+ parcelable Identity {
+ android.media.audio.common.AudioUuid type;
+ android.media.audio.common.AudioUuid uuid;
+ @nullable android.media.audio.common.AudioUuid proxy;
+ }
+ @VintfStability
+ parcelable Common {
+ android.hardware.audio.effect.Descriptor.Identity id;
+ android.hardware.audio.effect.Flags flags;
+ int cpuLoad;
+ int memoryUsage;
+ @utf8InCpp String name;
+ @utf8InCpp String implementor;
+ }
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Downmix.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Downmix.aidl
new file mode 100644
index 0000000..76f8ce5
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Downmix.aidl
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.audio.effect;
+@VintfStability
+union Downmix {
+ android.hardware.audio.effect.VendorExtension vendor;
+ android.hardware.audio.effect.Downmix.Type type;
+ @VintfStability
+ union Id {
+ int vendorExtensionTag;
+ android.hardware.audio.effect.Downmix.Tag commonTag;
+ }
+ @VintfStability
+ parcelable Capability {
+ ParcelableHolder extension;
+ }
+ @VintfStability
+ enum Type {
+ STRIP = 0,
+ FOLD = 1,
+ }
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/DynamicsProcessing.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/DynamicsProcessing.aidl
new file mode 100644
index 0000000..ed4dc80
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/DynamicsProcessing.aidl
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.audio.effect;
+@VintfStability
+union DynamicsProcessing {
+ android.hardware.audio.effect.VendorExtension vendorExtension;
+ android.hardware.audio.effect.DynamicsProcessing.EngineArchitecture engineArchitecture;
+ android.hardware.audio.effect.DynamicsProcessing.BandChannelConfig preEq;
+ android.hardware.audio.effect.DynamicsProcessing.BandChannelConfig postEq;
+ android.hardware.audio.effect.DynamicsProcessing.EqBandConfig preEqBand;
+ android.hardware.audio.effect.DynamicsProcessing.EqBandConfig postEqBand;
+ android.hardware.audio.effect.DynamicsProcessing.BandChannelConfig mbc;
+ android.hardware.audio.effect.DynamicsProcessing.MbcBandConfig mbcBand;
+ android.hardware.audio.effect.DynamicsProcessing.LimiterConfig limiter;
+ float inputGainDb;
+ @VintfStability
+ union Id {
+ int vendorExtensionTag;
+ android.hardware.audio.effect.DynamicsProcessing.Tag commonTag;
+ }
+ @VintfStability
+ parcelable Capability {
+ ParcelableHolder extension;
+ }
+ enum ResolutionPreference {
+ FAVOR_FREQUENCY_RESOLUTION = 0,
+ FAVOR_TIME_RESOLUTION = 1,
+ }
+ @VintfStability
+ parcelable BandEnablement {
+ boolean inUse;
+ int bandCount;
+ }
+ @VintfStability
+ parcelable EngineArchitecture {
+ android.hardware.audio.effect.DynamicsProcessing.ResolutionPreference resolutionPreference = android.hardware.audio.effect.DynamicsProcessing.ResolutionPreference.FAVOR_FREQUENCY_RESOLUTION;
+ float preferredFrameDurationMs;
+ android.hardware.audio.effect.DynamicsProcessing.BandEnablement preEqBand;
+ android.hardware.audio.effect.DynamicsProcessing.BandEnablement postEqBand;
+ android.hardware.audio.effect.DynamicsProcessing.BandEnablement mbcBand;
+ boolean limiterInUse;
+ }
+ @VintfStability
+ parcelable BandChannelConfig {
+ int channel;
+ android.hardware.audio.effect.DynamicsProcessing.BandEnablement enablement;
+ }
+ @VintfStability
+ parcelable EqBandConfig {
+ int channel;
+ int band;
+ boolean enable;
+ float cutoffFrequency;
+ float gain;
+ }
+ @VintfStability
+ parcelable MbcBandConfig {
+ int channel;
+ int band;
+ boolean enable;
+ float cutoffFrequencyHz;
+ float gainDb;
+ float attackTimeMs;
+ float releaseTimeMs;
+ float ratio;
+ float thresholdDb;
+ float kneeWidthDb;
+ float noiseGateThresholdDb;
+ float expanderRatio;
+ float preGainDb;
+ float postGainDb;
+ }
+ @VintfStability
+ parcelable LimiterConfig {
+ int channel;
+ boolean enable;
+ boolean inUse;
+ int linkGroup;
+ float attackTimeMs;
+ float releaseTimeMs;
+ float ratio;
+ float thresholdDb;
+ float postGainDb;
+ }
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Equalizer.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Equalizer.aidl
new file mode 100644
index 0000000..d825eac
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Equalizer.aidl
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.audio.effect;
+@VintfStability
+union Equalizer {
+ android.hardware.audio.effect.VendorExtension vendorExtension;
+ android.hardware.audio.effect.Equalizer.BandLevel[] bandLevels;
+ int preset;
+ @VintfStability
+ union Id {
+ int vendorExtensionTag;
+ android.hardware.audio.effect.Equalizer.Tag commonTag;
+ }
+ @VintfStability
+ parcelable Capability {
+ ParcelableHolder extension;
+ android.hardware.audio.effect.Equalizer.BandFrequency[] bandFrequencies;
+ android.hardware.audio.effect.Equalizer.Preset[] presets;
+ }
+ @VintfStability
+ parcelable BandLevel {
+ int index;
+ int levelMb;
+ }
+ @VintfStability
+ parcelable BandFrequency {
+ int index;
+ int minMh;
+ int maxMh;
+ }
+ @VintfStability
+ parcelable Preset {
+ int index;
+ @utf8InCpp String name;
+ }
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Flags.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Flags.aidl
new file mode 100644
index 0000000..285ff18
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Flags.aidl
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.audio.effect;
+@VintfStability
+parcelable Flags {
+ android.hardware.audio.effect.Flags.Type type = android.hardware.audio.effect.Flags.Type.INSERT;
+ android.hardware.audio.effect.Flags.Insert insert = android.hardware.audio.effect.Flags.Insert.ANY;
+ android.hardware.audio.effect.Flags.Volume volume = android.hardware.audio.effect.Flags.Volume.NONE;
+ android.hardware.audio.effect.Flags.HardwareAccelerator hwAcceleratorMode = android.hardware.audio.effect.Flags.HardwareAccelerator.NONE;
+ boolean offloadIndication;
+ boolean deviceIndication;
+ boolean audioModeIndication;
+ boolean audioSourceIndication;
+ boolean noProcessing;
+ @Backing(type="byte") @VintfStability
+ enum Type {
+ INSERT = 0,
+ AUXILIARY = 1,
+ REPLACE = 2,
+ PRE_PROC = 3,
+ POST_PROC = 4,
+ }
+ @Backing(type="byte") @VintfStability
+ enum Insert {
+ ANY = 0,
+ FIRST = 1,
+ LAST = 2,
+ EXCLUSIVE = 3,
+ }
+ @Backing(type="byte") @VintfStability
+ enum Volume {
+ NONE = 0,
+ CTRL = 1,
+ IND = 2,
+ MONITOR = 3,
+ }
+ @Backing(type="byte") @VintfStability
+ enum HardwareAccelerator {
+ NONE = 0,
+ SIMPLE = 1,
+ TUNNEL = 2,
+ }
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/HapticGenerator.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/HapticGenerator.aidl
new file mode 100644
index 0000000..40a8d72
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/HapticGenerator.aidl
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.audio.effect;
+@VintfStability
+union HapticGenerator {
+ android.hardware.audio.effect.VendorExtension vendorExtension;
+ android.hardware.audio.effect.HapticGenerator.HapticScale hapticScale;
+ android.hardware.audio.effect.HapticGenerator.VibratorInformation vibratorInfo;
+ @VintfStability
+ union Id {
+ int vendorExtensionTag;
+ android.hardware.audio.effect.HapticGenerator.Tag commonTag;
+ }
+ @VintfStability
+ parcelable Capability {
+ android.hardware.audio.effect.VendorExtension extension;
+ }
+ @Backing(type="int") @VintfStability
+ enum VibratorScale {
+ MUTE = -100,
+ VERY_LOW = -2,
+ LOW = -1,
+ NONE = 0,
+ HIGH = 1,
+ VERY_HIGH = 2,
+ }
+ @VintfStability
+ parcelable HapticScale {
+ int id;
+ android.hardware.audio.effect.HapticGenerator.VibratorScale scale = android.hardware.audio.effect.HapticGenerator.VibratorScale.MUTE;
+ }
+ @VintfStability
+ parcelable VibratorInformation {
+ float resonantFrequencyHz;
+ float qFactor;
+ float maxAmplitude;
+ }
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/IEffect.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/IEffect.aidl
new file mode 100644
index 0000000..8c196e7
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/IEffect.aidl
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible 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
+interface IEffect {
+ android.hardware.audio.effect.IEffect.OpenEffectReturn open(in android.hardware.audio.effect.Parameter.Common common, in @nullable android.hardware.audio.effect.Parameter.Specific specific);
+ void close();
+ android.hardware.audio.effect.Descriptor getDescriptor();
+ void command(in android.hardware.audio.effect.CommandId commandId);
+ android.hardware.audio.effect.State getState();
+ void setParameter(in android.hardware.audio.effect.Parameter param);
+ android.hardware.audio.effect.Parameter getParameter(in android.hardware.audio.effect.Parameter.Id paramId);
+ @FixedSize @VintfStability
+ parcelable Status {
+ int status;
+ int fmqConsumed;
+ int fmqProduced;
+ }
+ @VintfStability
+ parcelable OpenEffectReturn {
+ android.hardware.common.fmq.MQDescriptor<android.hardware.audio.effect.IEffect.Status,android.hardware.common.fmq.SynchronizedReadWrite> statusMQ;
+ android.hardware.common.fmq.MQDescriptor<float,android.hardware.common.fmq.SynchronizedReadWrite> inputDataMQ;
+ android.hardware.common.fmq.MQDescriptor<float,android.hardware.common.fmq.SynchronizedReadWrite> outputDataMQ;
+ }
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/IFactory.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/IFactory.aidl
new file mode 100644
index 0000000..5b85d33
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/IFactory.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.audio.effect;
+@VintfStability
+interface IFactory {
+ android.hardware.audio.effect.Descriptor.Identity[] queryEffects(in @nullable android.media.audio.common.AudioUuid type, in @nullable android.media.audio.common.AudioUuid implementation, in @nullable android.media.audio.common.AudioUuid proxy);
+ android.hardware.audio.effect.Processing[] queryProcessing(in @nullable android.hardware.audio.effect.Processing.Type type);
+ android.hardware.audio.effect.IEffect createEffect(in android.media.audio.common.AudioUuid implUuid);
+ void destroyEffect(in android.hardware.audio.effect.IEffect handle);
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/LoudnessEnhancer.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/LoudnessEnhancer.aidl
new file mode 100644
index 0000000..5c6ca16
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/LoudnessEnhancer.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.audio.effect;
+@VintfStability
+union LoudnessEnhancer {
+ android.hardware.audio.effect.VendorExtension vendor;
+ int gainMb;
+ @VintfStability
+ union Id {
+ int vendorExtensionTag;
+ android.hardware.audio.effect.LoudnessEnhancer.Tag commonTag;
+ }
+ @VintfStability
+ parcelable Capability {
+ android.hardware.audio.effect.VendorExtension extension;
+ }
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Parameter.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Parameter.aidl
new file mode 100644
index 0000000..321c286
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Parameter.aidl
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.audio.effect;
+@VintfStability
+union Parameter {
+ android.hardware.audio.effect.Parameter.Common common;
+ android.media.audio.common.AudioDeviceDescription deviceDescription;
+ android.media.audio.common.AudioMode mode;
+ android.media.audio.common.AudioSource source;
+ android.hardware.audio.effect.Parameter.VolumeStereo volumeStereo;
+ android.hardware.audio.effect.Parameter.Specific specific;
+ @VintfStability
+ union Id {
+ int vendorEffectTag;
+ android.hardware.audio.effect.BassBoost.Id bassBoostTag;
+ android.hardware.audio.effect.Downmix.Id downmixTag;
+ android.hardware.audio.effect.DynamicsProcessing.Id dynamicsProcessingTag;
+ android.hardware.audio.effect.Equalizer.Id equalizerTag;
+ android.hardware.audio.effect.HapticGenerator.Id hapticGeneratorTag;
+ android.hardware.audio.effect.LoudnessEnhancer.Id loudnessEnhancerTag;
+ android.hardware.audio.effect.Reverb.Id reverbTag;
+ android.hardware.audio.effect.Virtualizer.Id virtualizerTag;
+ android.hardware.audio.effect.Visualizer.Id visualizerTag;
+ android.hardware.audio.effect.Volume.Id volumeTag;
+ android.hardware.audio.effect.Parameter.Tag commonTag;
+ }
+ @VintfStability
+ parcelable Common {
+ int session;
+ int ioHandle;
+ android.media.audio.common.AudioConfig input;
+ android.media.audio.common.AudioConfig output;
+ }
+ @VintfStability
+ parcelable VolumeStereo {
+ float left;
+ float right;
+ }
+ @VintfStability
+ union Specific {
+ android.hardware.audio.effect.VendorExtension vendorEffect;
+ android.hardware.audio.effect.BassBoost bassBoost;
+ android.hardware.audio.effect.Downmix downmix;
+ android.hardware.audio.effect.DynamicsProcessing dynamicsProcessing;
+ android.hardware.audio.effect.Equalizer equalizer;
+ android.hardware.audio.effect.LoudnessEnhancer loudnessEnhancer;
+ android.hardware.audio.effect.HapticGenerator hapticGenerator;
+ android.hardware.audio.effect.Reverb reverb;
+ android.hardware.audio.effect.Virtualizer virtualizer;
+ android.hardware.audio.effect.Visualizer visualizer;
+ android.hardware.audio.effect.Volume volume;
+ }
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Processing.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Processing.aidl
new file mode 100644
index 0000000..a779ae4
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Processing.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.audio.effect;
+@VintfStability
+parcelable Processing {
+ android.hardware.audio.effect.Processing.Type type;
+ android.hardware.audio.effect.Descriptor.Identity[] ids;
+ @VintfStability
+ union Type {
+ android.media.audio.common.AudioStreamType streamType = android.media.audio.common.AudioStreamType.INVALID;
+ android.media.audio.common.AudioSource source;
+ }
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
new file mode 100644
index 0000000..8ad4848
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.audio.effect;
+@VintfStability
+union Reverb {
+ android.hardware.audio.effect.VendorExtension vendor;
+ int roomLevelMb;
+ int roomHfLevelMb;
+ int decayTimeMs;
+ int decayHfRatioPm;
+ int levelMb;
+ int delayMs;
+ int diffusionPm;
+ int densityPm;
+ boolean bypass;
+ @VintfStability
+ union Id {
+ int vendorExtensionTag;
+ android.hardware.audio.effect.Reverb.Tag commonTag;
+ }
+ @VintfStability
+ parcelable Capability {
+ android.hardware.audio.effect.VendorExtension extension;
+ int maxDecayTimeMs;
+ }
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/State.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/State.aidl
new file mode 100644
index 0000000..3176b01
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/State.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.audio.effect;
+@Backing(type="byte") @VintfStability
+enum State {
+ INIT = 0,
+ IDLE = 1,
+ PROCESSING = 2,
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/VendorExtension.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/VendorExtension.aidl
new file mode 100644
index 0000000..b806334
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/VendorExtension.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.audio.effect;
+@VintfStability
+parcelable VendorExtension {
+ ParcelableHolder extension;
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Virtualizer.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Virtualizer.aidl
new file mode 100644
index 0000000..d4fb9e0
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Virtualizer.aidl
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.audio.effect;
+@VintfStability
+union Virtualizer {
+ android.hardware.audio.effect.VendorExtension vendor;
+ int strengthPm;
+ @VintfStability
+ union Id {
+ int vendorExtensionTag;
+ android.hardware.audio.effect.Virtualizer.Tag commonTag;
+ }
+ @VintfStability
+ parcelable Capability {
+ android.hardware.audio.effect.VendorExtension extension;
+ boolean strengthSupported;
+ }
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Visualizer.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Visualizer.aidl
new file mode 100644
index 0000000..9ee19f0
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Visualizer.aidl
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.audio.effect;
+@VintfStability
+union Visualizer {
+ android.hardware.audio.effect.Visualizer.Id id;
+ android.hardware.audio.effect.VendorExtension vendor;
+ android.hardware.audio.effect.Visualizer.GetOnlyParameters getOnlyParameters;
+ android.hardware.audio.effect.Visualizer.SetOnlyParameters setOnlyParameters;
+ int captureSizeBytes;
+ android.hardware.audio.effect.Visualizer.ScalingMode scalingMode;
+ android.hardware.audio.effect.Visualizer.MeasurementMode measurementMode;
+ @VintfStability
+ union Id {
+ int vendorExtensionTag;
+ android.hardware.audio.effect.Visualizer.GetOnlyParameters.Tag getOnlyParamTag;
+ android.hardware.audio.effect.Visualizer.SetOnlyParameters.Tag setOnlyParamTag;
+ android.hardware.audio.effect.Visualizer.Tag commonTag;
+ }
+ @VintfStability
+ parcelable Capability {
+ android.hardware.audio.effect.VendorExtension extension;
+ int maxLatencyMs;
+ android.hardware.audio.effect.Visualizer.CaptureSizeRange captureSizeRange;
+ }
+ @VintfStability
+ parcelable CaptureSizeRange {
+ int minBytes;
+ int maxBytes;
+ }
+ @VintfStability
+ enum ScalingMode {
+ NORMALIZED = 0,
+ AS_PLAYED = 1,
+ }
+ @VintfStability
+ enum MeasurementMode {
+ NONE = 0,
+ PEAK_RMS = 1,
+ }
+ @VintfStability
+ union GetOnlyParameters {
+ android.hardware.audio.effect.Visualizer.GetOnlyParameters.Measurement measurement;
+ byte[] captureBytes;
+ @VintfStability
+ parcelable Measurement {
+ int rms;
+ int peak;
+ }
+ }
+ @VintfStability
+ union SetOnlyParameters {
+ int latencyMs;
+ }
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Volume.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Volume.aidl
new file mode 100644
index 0000000..8c836b0
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Volume.aidl
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.audio.effect;
+@VintfStability
+union Volume {
+ android.hardware.audio.effect.VendorExtension vendor;
+ int levelDb;
+ boolean mute;
+ @VintfStability
+ union Id {
+ int vendorExtensionTag;
+ android.hardware.audio.effect.Volume.Tag commonTag;
+ }
+ @VintfStability
+ parcelable Capability {
+ android.hardware.audio.effect.VendorExtension extension;
+ int maxLevel;
+ }
+}
diff --git a/audio/aidl/android/hardware/audio/core/AudioMode.aidl b/audio/aidl/android/hardware/audio/core/AudioMode.aidl
new file mode 100644
index 0000000..0943a55
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/AudioMode.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.core;
+
+/**
+ * The audio mode describes states of the audio system of the device that
+ * can significantly affect the rules of audio routing, volume control, etc.
+ * The audio mode is controlled by the framework, however the HAL has some
+ * flexibility in the choice of modes to support, see 'IModule.updateAudioMode'.
+ */
+@VintfStability
+@Backing(type="int")
+enum AudioMode {
+ /** No active calls. */
+ NORMAL = 0,
+ /** The device is playing the ringtone. */
+ RINGTONE = 1,
+ /** The call is handled by the telephony stack ("voice call"). */
+ IN_CALL = 2,
+ /** The call is handled by an application ("VoIP call"). */
+ IN_COMMUNICATION = 3,
+ /** Call screening is in progress. */
+ CALL_SCREEN = 4,
+}
diff --git a/audio/aidl/android/hardware/audio/core/AudioPatch.aidl b/audio/aidl/android/hardware/audio/core/AudioPatch.aidl
new file mode 100644
index 0000000..005d4c0
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/AudioPatch.aidl
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.core;
+
+/**
+ * Audio patch specifies a connection between multiple audio port
+ * configurations.
+ */
+@JavaDerive(equals=true, toString=true)
+@VintfStability
+parcelable AudioPatch {
+ /** The ID of the patch, unique within the HAL module. */
+ int id;
+ /**
+ * The list of IDs of source audio port configs ('AudioPortConfig.id').
+ * There must be at least one source in a valid patch and all IDs must be
+ * unique.
+ */
+ int[] sourcePortConfigIds;
+ /**
+ * The list of IDs of sink audio port configs ('AudioPortConfig.id').
+ * There must be at least one sink in a valid patch and all IDs must be
+ * unique.
+ */
+ int[] sinkPortConfigIds;
+ /**
+ * The minimum buffer size, in frames, which streams must use for
+ * this connection configuration. This field is filled out by the
+ * HAL module on creation of the patch and must be a positive number.
+ */
+ int minimumStreamBufferSizeFrames;
+ /**
+ * Latencies, in milliseconds, associated with each sink port config from
+ * the 'sinkPortConfigIds' field. This field is filled out by the HAL module
+ * on creation or updating of the patch and must be a positive number. This
+ * is a nominal value. The current value of latency is provided via
+ * 'StreamDescriptor' command exchange on each audio I/O operation.
+ */
+ int[] latenciesMs;
+}
diff --git a/audio/aidl/android/hardware/audio/core/AudioRoute.aidl b/audio/aidl/android/hardware/audio/core/AudioRoute.aidl
new file mode 100644
index 0000000..1e7b441
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/AudioRoute.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.core;
+
+/**
+ * Audio route specifies a path from multiple audio source ports to one audio
+ * sink port. As an example, when emitting audio output, source ports typically
+ * are mix ports (audio data from the framework), the sink is a device
+ * port. When acquiring audio, source ports are device ports, the sink is a mix
+ * port.
+ */
+@JavaDerive(equals=true, toString=true)
+@VintfStability
+parcelable AudioRoute {
+ /**
+ * The list of IDs of source audio ports ('AudioPort.id').
+ * There must be at least one source in a valid route and all IDs must be
+ * unique.
+ */
+ int[] sourcePortIds;
+ /** The ID of the sink audio port ('AudioPort.id'). */
+ int sinkPortId;
+ /** If set, only one source can be active, mixing is not supported. */
+ boolean isExclusive;
+}
diff --git a/audio/aidl/android/hardware/audio/core/IConfig.aidl b/audio/aidl/android/hardware/audio/core/IConfig.aidl
new file mode 100644
index 0000000..c8ba6be
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/IConfig.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.core;
+
+import android.hardware.audio.core.SurroundSoundConfig;
+
+/**
+ * This interface provides system-wide configuration parameters for audio I/O
+ * (by "system" here we mean the device running Android).
+ */
+@VintfStability
+interface IConfig {
+ /**
+ * Returns the surround sound configuration used for the Audio Policy
+ * Manager initial configuration.
+ *
+ * This method will only be called during the initialization of the Audio
+ * Policy Manager, and must always return the same result.
+ *
+ * @return The surround sound configuration
+ */
+ SurroundSoundConfig getSurroundSoundConfig();
+}
diff --git a/audio/aidl/android/hardware/audio/core/IModule.aidl b/audio/aidl/android/hardware/audio/core/IModule.aidl
new file mode 100644
index 0000000..974e7e8
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/IModule.aidl
@@ -0,0 +1,654 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.core;
+
+import android.hardware.audio.common.SinkMetadata;
+import android.hardware.audio.common.SourceMetadata;
+import android.hardware.audio.core.AudioMode;
+import android.hardware.audio.core.AudioPatch;
+import android.hardware.audio.core.AudioRoute;
+import android.hardware.audio.core.IStreamCallback;
+import android.hardware.audio.core.IStreamIn;
+import android.hardware.audio.core.IStreamOut;
+import android.hardware.audio.core.ITelephony;
+import android.hardware.audio.core.ModuleDebug;
+import android.hardware.audio.core.StreamDescriptor;
+import android.media.audio.common.AudioOffloadInfo;
+import android.media.audio.common.AudioPort;
+import android.media.audio.common.AudioPortConfig;
+
+/**
+ * Each instance of IModule corresponds to a separate audio module. The system
+ * (the term "system" as used here applies to the entire device running Android)
+ * may have multiple modules due to the physical architecture, for example, it
+ * can have multiple DSPs or other audio I/O units which are not interconnected
+ * in hardware directly. Usually there is at least one audio module which is
+ * responsible for the "main" (or "built-in") audio functionality of the
+ * system. Even if the system lacks any physical audio I/O capabilities, there
+ * will be a "null" audio module.
+ *
+ * On a typical mobile phone there is usually a main DSP module which handles
+ * most of the phone's audio I/O via the built-in speakers and microphones. USB
+ * audio can exist as a separate module. Some audio modules can be implemented
+ * purely in software, for example, the remote submix module.
+ */
+@VintfStability
+interface IModule {
+ /**
+ * Sets debugging configuration for the HAL module. This method is only
+ * called during xTS testing and is intended for validating the aspects of
+ * the HAL module behavior that would otherwise require human intervention.
+ *
+ * The HAL module must throw an error if there is an attempt to change
+ * the debug behavior for the aspect which is currently in use, or when
+ * the value of any of the debug flags is invalid. See 'ModuleDebug' for
+ * the full list of constraints.
+ *
+ * @param debug The debug options.
+ * @throws EX_ILLEGAL_ARGUMENT If some of the configuration parameters are
+ * invalid.
+ * @throws EX_ILLEGAL_STATE If the flag(s) being changed affect functionality
+ * which is currently in use.
+ */
+ void setModuleDebug(in ModuleDebug debug);
+
+ /**
+ * Retrieve the interface to control telephony audio.
+ *
+ * If the HAL module supports telephony functions, it must return an
+ * instance of the ITelephony interface. The same instance must be returned
+ * during the lifetime of the HAL module. If the HAL module does not support
+ * telephony, a null must be returned, without throwing any errors.
+ *
+ * @return An instance of the ITelephony interface implementation.
+ * @throws EX_ILLEGAL_STATE If there was an error creating an instance.
+ */
+ @nullable ITelephony getTelephony();
+
+ /**
+ * Set a device port of an external device into connected state.
+ *
+ * This method is used to inform the HAL module that an external device has
+ * been connected to a device port selected using the 'id' field of the
+ * input AudioPort parameter. This device port must have dynamic profiles
+ * (an empty list of profiles). This port is further referenced to as "port
+ * template" because it acts as a template for creating a new instance of a
+ * "connected" device port which gets returned from this method.
+ *
+ * The input AudioPort parameter may contain any additional data obtained by
+ * the system side from other subsystems. The nature of data depends on the
+ * type of the connection. For example, for point-to-multipoint external
+ * device connections, the input parameter may contain the address of the
+ * connected external device. Another example is EDID information for HDMI
+ * connections (ExtraAudioDescriptor), which can be provided by the HDMI-CEC
+ * HAL module.
+ *
+ * It is the responsibility of the HAL module to query audio profiles
+ * supported by the connected device and return them as part of the returned
+ * AudioPort instance. In the case when the HAL is unable to query the
+ * external device, an error must be thrown.
+ *
+ * Thus, the returned audio port instance is the result of combining the
+ * following information:
+ * - a unique port ID generated by the HAL module;
+ * - static information from the port template;
+ * - list of audio profiles supported by the connected device;
+ * - additional data from the input AudioPort parameter.
+ *
+ * The HAL module must also update the list of audio routes to include the
+ * ID of the instantiated connected device port. Normally, the connected
+ * port allows the same routing as the port template.
+ *
+ * Also see notes on 'ModuleDebug.simulateDeviceConnections'.
+ *
+ * The following protocol is used by HAL module client for handling
+ * connection of an external device:
+ * 1. Obtain the list of device ports and their IDs via 'getAudioPorts'
+ * method. Select the appropriate port template using
+ * AudioDeviceDescription ('ext.device' field of AudioPort).
+ * 2. Combine the ID of the port template with any additional data and call
+ * 'connectExternalDevice'. The HAL module returns a new instance of
+ * AudioPort created using the rules explained above. Both
+ * 'getAudioPort' and 'getAudioPorts' methods will be returning the same
+ * information for this port until disconnection.
+ * 3. Configure the connected port with one of supported profiles using
+ * 'setAudioPortConfig'.
+ * 4. Query the list of AudioRoutes for the new AudioPort using
+ * 'getAudioRoutesForAudioPort' or 'getAudioRoutes' methods.
+ *
+ * External devices are distinguished by the connection type and device
+ * address. Calling this method multiple times to inform about connection of
+ * the same external device without disconnecting it first is an error.
+ *
+ * The HAL module must perform validation of the input parameter and throw
+ * an error if it is lacking required information, for example, when no
+ * device address is specified for a point-to-multipoint external device
+ * connection.
+ *
+ * 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'
+ * method. This also removes the audio routes associated with this
+ * device port.
+ *
+ * @return New instance of an audio port for the connected external device.
+ * @param templateIdAndAdditionalData Specifies port template ID and any
+ * additional data.
+ * @throws EX_ILLEGAL_ARGUMENT In the following cases:
+ * - If the template port can not be found by the ID.
+ * - If the template is not a device port, or
+ * it does not have dynamic profiles.
+ * - If the input parameter is lacking required
+ * information.
+ * @throws EX_ILLEGAL_STATE In the following cases:
+ * - If the HAL module is unable to query audio profiles.
+ * - If the external device has already been connected.
+ */
+ AudioPort connectExternalDevice(in AudioPort templateIdAndAdditionalData);
+
+ /**
+ * Set a device port of a an external device into disconnected state.
+ *
+ * This method is used to inform the HAL module that an external device has
+ * been disconnected. The 'portId' must be of a connected device port
+ * instance previously instantiated using the 'connectExternalDevice'
+ * method.
+ *
+ * @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.
+ * @throws EX_ILLEGAL_STATE If the port has active configurations.
+ */
+ void disconnectExternalDevice(int portId);
+
+ /**
+ * Return all audio patches of this module.
+ *
+ * Returns a list of audio patches, that is, established connections between
+ * audio port configurations.
+ *
+ * @return The list of audio patches.
+ */
+ AudioPatch[] getAudioPatches();
+
+ /**
+ * Return the current state of the audio port.
+ *
+ * Using the port ID provided on input, returns the current state of the
+ * audio port. The values of the AudioPort structure must be the same as
+ * currently returned by the 'getAudioPorts' method. The 'getAudioPort'
+ * method is provided to reduce overhead in the case when the client needs
+ * to check the state of one port only.
+ *
+ * @return The current state of an audio port.
+ * @param portId The ID of the audio port.
+ * @throws EX_ILLEGAL_ARGUMENT If the port can not be found by the ID.
+ */
+ AudioPort getAudioPort(int portId);
+
+ /**
+ * Return all active audio port configurations of this module.
+ *
+ * Returns a list of active configurations that are currently set for mix
+ * ports and device ports. Each returned configuration must have an unique
+ * ID within this module ('AudioPortConfig.id' field), which can coincide
+ * with an ID of an audio port, if the port only supports a single active
+ * configuration. Each returned configuration must also have a reference to
+ * an existing port ('AudioPortConfig.portId' field). All optional
+ * (nullable) fields of the configurations must be initialized by the HAL
+ * module.
+ *
+ * @return The list of active audio port configurations.
+ */
+ AudioPortConfig[] getAudioPortConfigs();
+
+ /**
+ * Return the current state of all audio ports provided by this module.
+ *
+ * Returns a list of all mix ports and device ports provided by this HAL
+ * module, reflecting their current states. Each returned port must have a
+ * unique ID within this module ('AudioPort.id' field). The list also
+ * includes "connected" ports created using 'connectExternalDevice' method.
+ *
+ * @return The list of audio ports.
+ */
+ AudioPort[] getAudioPorts();
+
+ /**
+ * Return all current audio routes of this module.
+ *
+ * Returns the current list of audio routes, that is, allowed connections
+ * between audio ports. The list can change when new device audio ports
+ * get created as a result of connecting or disconnecting of external
+ * devices.
+ *
+ * @return The list of audio routes.
+ */
+ AudioRoute[] getAudioRoutes();
+
+ /**
+ * Return audio routes related to the specified audio port.
+ *
+ * Returns the list of audio routes that include the specified port ID
+ * as a source or as a sink. The returned list is a subset of the result
+ * returned by the 'getAudioRoutes' method, filtered by the port ID.
+ * An empty list can be returned, indicating that the audio port can not
+ * be used for creating audio patches.
+ *
+ * @return The list of audio routes.
+ * @param portId The ID of the audio port.
+ * @throws EX_ILLEGAL_ARGUMENT If the port can not be found by the ID.
+ */
+ AudioRoute[] getAudioRoutesForAudioPort(int portId);
+
+ /**
+ * Open an input stream using an existing audio mix port configuration.
+ *
+ * The audio port configuration ID must be obtained by calling
+ * 'setAudioPortConfig' method. Existence of an audio patch involving this
+ * port configuration is not required for successful opening of a stream.
+ *
+ * The requested buffer size is expressed in frames, thus the actual size
+ * in bytes depends on the audio port configuration. Also, the HAL module
+ * may end up providing a larger buffer, thus the requested size is treated
+ * as the minimum size that the client needs. The minimum buffer size
+ * suggested by the HAL is in the 'AudioPatch.minimumStreamBufferSizeFrames'
+ * field, returned as a result of calling the 'setAudioPatch' method.
+ *
+ * Only one stream is allowed per audio port configuration. HAL module can
+ * also set a limit on how many output streams can be opened for a particular
+ * mix port by using its 'AudioPortMixExt.maxOpenStreamCount' field.
+ *
+ * Note that although it's not prohibited to open a stream on a mix port
+ * configuration which is not connected (using a patch) to any device port,
+ * and set up a patch afterwards, this sequence of calls is not recommended,
+ * because setting up of a patch might fail due to an insufficient stream
+ * buffer size. Another consequence of having a stream on an unconnected mix
+ * port is that capture positions can not be determined because there is no
+ * "external observer," thus read operations done via StreamDescriptor will
+ * be completing with an error, although data (zero filled) will still be
+ * provided.
+ *
+ * After the stream has been opened, it remains in the STANDBY state, see
+ * StreamDescriptor for more details.
+ *
+ * @return An opened input stream and the associated descriptor.
+ * @param args The pack of arguments, see 'OpenInputStreamArguments' parcelable.
+ * @throws EX_ILLEGAL_ARGUMENT In the following cases:
+ * - If the port config can not be found by the ID.
+ * - If the port config is not of an input mix port.
+ * - If a buffer of the requested size can not be provided.
+ * @throws EX_ILLEGAL_STATE In the following cases:
+ * - If the port config already has a stream opened on it.
+ * - If the limit on the open stream count for the port has
+ * been reached.
+ * - If the HAL module failed to initialize the stream.
+ */
+ @VintfStability
+ parcelable OpenInputStreamArguments {
+ /** The ID of the audio mix port config. */
+ int portConfigId;
+ /** Description of the audio that will be recorded. */
+ SinkMetadata sinkMetadata;
+ /** Requested audio I/O buffer minimum size, in frames. */
+ long bufferSizeFrames;
+ }
+ @VintfStability
+ parcelable OpenInputStreamReturn {
+ IStreamIn stream;
+ StreamDescriptor desc;
+ }
+ OpenInputStreamReturn openInputStream(in OpenInputStreamArguments args);
+
+ /**
+ * Open an output stream using an existing audio mix port configuration.
+ *
+ * The audio port configuration ID must be obtained by calling
+ * 'setAudioPortConfig' method. Existence of an audio patch involving this
+ * port configuration is not required for successful opening of a stream.
+ *
+ * If the port configuration has the 'COMPRESS_OFFLOAD' output flag set,
+ * the client must provide additional information about the encoded
+ * audio stream in the 'offloadInfo' argument.
+ *
+ * If the port configuration has the 'NON_BLOCKING' output flag set,
+ * the client must provide a callback for asynchronous notifications
+ * in the 'callback' argument.
+ *
+ * The requested buffer size is expressed in frames, thus the actual size
+ * in bytes depends on the audio port configuration. Also, the HAL module
+ * may end up providing a larger buffer, thus the requested size is treated
+ * as the minimum size that the client needs. The minimum buffer size
+ * suggested by the HAL is in the 'AudioPatch.minimumStreamBufferSizeFrames'
+ * field, returned as a result of calling the 'setAudioPatch' method.
+ *
+ * Only one stream is allowed per audio port configuration. HAL module can
+ * also set a limit on how many output streams can be opened for a particular
+ * mix port by using its 'AudioPortMixExt.maxOpenStreamCount' field.
+ * Only one stream can be opened on the audio port with 'PRIMARY' output
+ * flag. This rule can not be overridden with 'maxOpenStreamCount' field.
+ *
+ * Note that although it's not prohibited to open a stream on a mix port
+ * configuration which is not connected (using a patch) to any device port,
+ * and set up a patch afterwards, this sequence of calls is not recommended,
+ * because setting up of a patch might fail due to an insufficient stream
+ * buffer size. Another consequence of having a stream on an unconnected mix
+ * port is that presentation positions can not be determined because there
+ * is no "external observer," thus write operations done via
+ * StreamDescriptor will be completing with an error, although the data
+ * will still be accepted and immediately discarded.
+ *
+ * After the stream has been opened, it remains in the STANDBY state, see
+ * StreamDescriptor for more details.
+ *
+ * @return An opened output stream and the associated descriptor.
+ * @param args The pack of arguments, see 'OpenOutputStreamArguments' parcelable.
+ * @throws EX_ILLEGAL_ARGUMENT In the following cases:
+ * - If the port config can not be found by the ID.
+ * - If the port config is not of an output mix port.
+ * - If the offload info is not provided for an offload
+ * port configuration.
+ * - If a buffer of the requested size can not be provided.
+ * - If the callback is not provided for a non-blocking
+ * port configuration.
+ * @throws EX_ILLEGAL_STATE In the following cases:
+ * - If the port config already has a stream opened on it.
+ * - If the limit on the open stream count for the port has
+ * been reached.
+ * - If another opened stream already exists for the 'PRIMARY'
+ * output port.
+ * - If the HAL module failed to initialize the stream.
+ */
+ @VintfStability
+ parcelable OpenOutputStreamArguments {
+ /** The ID of the audio mix port config. */
+ int portConfigId;
+ /** Description of the audio that will be played. */
+ SourceMetadata sourceMetadata;
+ /** Additional information used for offloaded playback only. */
+ @nullable AudioOffloadInfo offloadInfo;
+ /** Requested audio I/O buffer minimum size, in frames. */
+ long bufferSizeFrames;
+ /** Client callback interface for the non-blocking output mode. */
+ @nullable IStreamCallback callback;
+ }
+ @VintfStability
+ parcelable OpenOutputStreamReturn {
+ IStreamOut stream;
+ StreamDescriptor desc;
+ }
+ OpenOutputStreamReturn openOutputStream(in OpenOutputStreamArguments args);
+
+ /**
+ * Set an audio patch.
+ *
+ * This method creates new or updates an existing audio patch. If the
+ * requested audio patch does not have a specified id, then a new patch is
+ * created and an ID is allocated for it by the HAL module. Otherwise an
+ * attempt to update an existing patch is made.
+ *
+ * The operation of updating an existing audio patch must not change
+ * playback state of audio streams opened on the audio port configurations
+ * of the patch. That is, the HAL module must still be able to consume or
+ * to provide data from / to streams continuously during the patch
+ * switching. Natural intermittent audible loss of some audio frames due to
+ * switching between device ports which does not affect stream playback is
+ * allowed. If the HAL module is unable to avoid playback or recording
+ * state change when updating a certain patch, it must return an error. In
+ * that case, the client must take care of changing port configurations,
+ * patches, and recreating streams in a way which provides an acceptable
+ * user experience.
+ *
+ * Audio port configurations specified in the patch must be obtained by
+ * calling 'setAudioPortConfig' method. There must be an audio route which
+ * allows connection between the audio ports whose configurations are used.
+ *
+ * When updating an existing audio patch, nominal latency values may change
+ * and must be provided by the HAL module in the returned 'AudioPatch'
+ * structure.
+ *
+ * @return Resulting audio patch.
+ * @param requested Requested audio patch.
+ * @throws EX_ILLEGAL_ARGUMENT In the following cases:
+ * - If the patch is invalid (see AudioPatch).
+ * - If a port config can not be found from the specified IDs.
+ * - If there are no routes satisfying the patch.
+ * - If an existing patch can not be found by the ID.
+ * @throws EX_ILLEGAL_STATE In the following cases:
+ * - If application of the patch can only use a route with an
+ * exclusive use the sink port, and it is already patched.
+ * - If updating an existing patch will cause interruption
+ * of audio, or requires re-opening of streams due to
+ * change of minimum audio I/O buffer size.
+ * @throws EX_UNSUPPORTED_OPERATION If the patch can not be established because
+ * the HAL module does not support this otherwise valid
+ * patch configuration. For example, if it's a patch
+ * between multiple sources and sinks, and the HAL module
+ * does not support this.
+ */
+ AudioPatch setAudioPatch(in AudioPatch requested);
+
+ /**
+ * Set the active configuration of an audio port.
+ *
+ * This method is used to create or update an active configuration for a mix
+ * port or a device port. The port is specified using the
+ * 'AudioPortConfig.portId' field. If the requested audio port
+ * configuration does not have a specified id in the 'AudioPortConfig.id'
+ * field, then a new configuration is created and an ID is allocated for it
+ * by the HAL module. Otherwise an attempt to update an existing port
+ * configuration is made. The HAL module returns the resulting audio port
+ * configuration. Depending on the port and on the capabilities of the HAL
+ * module, it can either update an existing port configuration (same port
+ * configuration ID remains), or create a new one. The resulting port
+ * configuration ID is returned in the 'id' field of the 'suggested'
+ * argument.
+ *
+ * If the specified port configuration can not be set, this method must
+ * return 'false' and provide its own suggestion in the output
+ * parameter. The framework can then set the suggested configuration on a
+ * subsequent retry call to this method.
+ *
+ * Device ports with dynamic audio profiles (an empty list of profiles)
+ * can not be used with this method. The list of profiles must be filled in
+ * as a result of calling 'connectExternalDevice' method.
+ *
+ * @return Whether the requested configuration has been applied.
+ * @param requested Requested audio port configuration.
+ * @param suggested Same as requested configuration, if it was applied.
+ * Suggested audio port configuration if the requested
+ * configuration can't be applied.
+ * @throws EX_ILLEGAL_ARGUMENT In the following cases:
+ * - If neither port config ID, nor port ID are specified.
+ * - If an existing port config can not be found by the ID.
+ * - If the port can not be found by the port ID.
+ * - If it is not possible to generate a suggested port
+ * configuration, for example, if the port only has dynamic
+ * profiles.
+ */
+ boolean setAudioPortConfig(in AudioPortConfig requested, out AudioPortConfig suggested);
+
+ /**
+ * Reset the audio patch.
+ *
+ * Resets previously created audio patch using its ID ('AudioPatch.id'). It
+ * is allowed to reset a patch which uses audio port configurations having
+ * associated streams. In this case the mix port becomes disconnected from
+ * the hardware, but the stream does not close.
+ *
+ * @param patchId The ID of the audio patch.
+ * @throws EX_ILLEGAL_ARGUMENT If an existing patch can not be found by the ID.
+ */
+ void resetAudioPatch(int patchId);
+
+ /**
+ * Reset the audio port configuration.
+ *
+ * Resets the specified audio port configuration, discarding all changes
+ * previously done by the framework. That means, if a call to this method is
+ * a success, the effect of all previous calls to 'setAudioPortConfig' which
+ * used or initially have generated the provided 'portConfigId', since the
+ * module start, or since the last call to this method, has been canceled.
+ *
+ * Audio port configurations of mix ports with streams opened on them can
+ * not be reset. Also can not be reset port configurations currently used by
+ * any patches.
+ *
+ * @param portConfigId The ID of the audio port config.
+ * @throws EX_ILLEGAL_ARGUMENT If the port config can not be found by the ID.
+ * @throws EX_ILLEGAL_STATE In the following cases:
+ * - If the port config has a stream opened on it;
+ * - If the port config is used by a patch.
+ */
+ void resetAudioPortConfig(int portConfigId);
+
+ /**
+ * Get the current state of audio output muting.
+ *
+ * If the HAL module supports muting its combined output completely,
+ * this method returns whether muting is currently enabled.
+ *
+ * Note that muting operates independently from the master volume.
+ *
+ * @return Whether the output from the module is muted.
+ * @throws EX_UNSUPPORTED_OPERATION If muting of combined output
+ * is not supported by the module.
+ */
+ boolean getMasterMute();
+
+ /**
+ * Set the current value of the audio output muting.
+ *
+ * If the HAL module supports muting its combined output completely, this
+ * method controls the mute. Note that for modules supporting telephony,
+ * muting does not affect the voice call.
+ *
+ * For HAL modules not supporting this operation, it's functionality is
+ * typically emulated by the client, in the digital domain.
+ *
+ * @param mute Whether the output from the module is muted.
+ * @throws EX_UNSUPPORTED_OPERATION If muting of combined output
+ * is not supported by the module.
+ */
+ void setMasterMute(boolean mute);
+
+ /**
+ * Get the current value of the audio output attenuation.
+ *
+ * If the HAL module supports attenuating the level its combined output,
+ * this method returns the current attenuation value.
+ *
+ * @return Volume 1.0f means no attenuation (unity), 0.0f is mute.
+ * @throws EX_UNSUPPORTED_OPERATION If attenuation of combined output
+ * is not supported by the module.
+ */
+ float getMasterVolume();
+
+ /**
+ * Set the current value of the audio output attenuation.
+ *
+ * If the HAL module supports attenuating the level its combined output,
+ * this method sets the attenuation value. Note that for modules supporting
+ * telephony, the attenuation of the voice call volume is set separately
+ * via ITelephony interface.
+ *
+ * For HAL modules not supporting this operation, it's functionality is
+ * typically emulated by the client, in the digital domain.
+ *
+ * @param volume The new value, 1.0f means no attenuation (unity), 0.0f is mute.
+ * @throws EX_ILLEGAL_ARGUMENT If the value of the volume is outside of
+ * accepted range.
+ * @throws EX_UNSUPPORTED_OPERATION If attenuation of combined output
+ * is not supported by the module.
+ */
+ void setMasterVolume(float volume);
+
+ /**
+ * Get the current state of audio input muting.
+ *
+ * If the HAL module supports muting its external input, this method returns
+ * whether muting is currently enabled.
+ *
+ * @return Whether the input is muted.
+ * @throws EX_UNSUPPORTED_OPERATION If muting of input is not supported by
+ * the module.
+ */
+ boolean getMicMute();
+
+ /**
+ * Set the current value of the audio input muting.
+ *
+ * If the HAL module supports muting its external input, this method
+ * controls the mute.
+ *
+ * For HAL modules not supporting this operation, it's functionality is
+ * emulated by the client.
+ *
+ * @param mute Whether input is muted.
+ * @throws EX_UNSUPPORTED_OPERATION If muting of input is not supported by
+ * the module.
+ */
+ void setMicMute(boolean mute);
+
+ /**
+ * Notify the HAL module on the change of the current audio mode.
+ *
+ * The current audio mode is always controlled by the client. This is an
+ * informative notification sent to all modules, no reply is needed. The HAL
+ * module should silently ignore this notification if it does not need to
+ * be aware of the current audio mode.
+ *
+ * The client sends this notification to all HAL modules after successfully
+ * switching the telephony module by calling the 'ITelephony.switchAudioMode'
+ * method.
+ *
+ * @param mode The current mode.
+ */
+ void updateAudioMode(AudioMode mode);
+
+ @VintfStability
+ @Backing(type="int")
+ enum ScreenRotation {
+ /** Natural orientation. */
+ DEG_0 = 0,
+ DEG_90 = 1,
+ /** Upside down. */
+ DEG_180 = 2,
+ DEG_270 = 3,
+ }
+ /**
+ * Notify the HAL module on the change of the screen rotation.
+ *
+ * Informs the HAL of the current orientation of the device screen. This
+ * information can be used to optimize the output of built-in speakers.
+ * This is an informative notification sent to all modules, no reply is
+ * needed.
+ *
+ * @param rotation The current rotation.
+ */
+ void updateScreenRotation(ScreenRotation rotation);
+
+ /**
+ * Notify the HAL module on the change of the screen state.
+ *
+ * Informs the HAL whether the screen of the device is turned on. This is an
+ * informative notification sent to all modules, no reply is needed.
+ *
+ * @param isTurnedOn True if the screen is turned on.
+ */
+ void updateScreenState(boolean isTurnedOn);
+}
diff --git a/audio/aidl/android/hardware/audio/core/IStreamCallback.aidl b/audio/aidl/android/hardware/audio/core/IStreamCallback.aidl
new file mode 100644
index 0000000..440ab25
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/IStreamCallback.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.core;
+
+/**
+ * This interface is used to indicate completion of asynchronous operations.
+ * See the state machines referenced by StreamDescriptor for details.
+ */
+@VintfStability
+oneway interface IStreamCallback {
+ /**
+ * Indicate that the stream is ready for next data exchange.
+ */
+ void onTransferReady();
+ /**
+ * Indicate that an irrecoverable error has occurred during the last I/O
+ * operation. After sending this callback, the stream enters the 'ERROR'
+ * state.
+ */
+ void onError();
+ /**
+ * Indicate that the stream has finished draining. This is only used
+ * for output streams because for input streams draining is performed
+ * by the client.
+ */
+ void onDrainReady();
+}
diff --git a/audio/aidl/android/hardware/audio/core/IStreamIn.aidl b/audio/aidl/android/hardware/audio/core/IStreamIn.aidl
new file mode 100644
index 0000000..0c3e3d1
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/IStreamIn.aidl
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.core;
+
+import android.hardware.audio.common.SinkMetadata;
+
+/**
+ * This interface provides means for receiving audio data from input devices.
+ */
+@VintfStability
+interface IStreamIn {
+ /**
+ * Close the stream.
+ *
+ * Releases any resources allocated for this stream on the HAL module side.
+ * This includes the fast message queues and shared memories returned via
+ * the StreamDescriptor. Thus, the stream can not be operated anymore after
+ * it has been closed. The client needs to release the audio data I/O
+ * objects after the call to this method returns.
+ *
+ * Methods of this interface throw EX_ILLEGAL_STATE for a closed stream.
+ *
+ * @throws EX_ILLEGAL_STATE If the stream has already been closed.
+ */
+ void close();
+
+ /**
+ * Update stream metadata.
+ *
+ * Updates the metadata initially provided at the stream creation.
+ *
+ * @param sinkMetadata Updated metadata.
+ * @throws EX_ILLEGAL_STATE If the stream is closed.
+ */
+ void updateMetadata(in SinkMetadata sinkMetadata);
+}
diff --git a/audio/aidl/android/hardware/audio/core/IStreamOut.aidl b/audio/aidl/android/hardware/audio/core/IStreamOut.aidl
new file mode 100644
index 0000000..9fdb37d
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/IStreamOut.aidl
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.core;
+
+import android.hardware.audio.common.SourceMetadata;
+
+/**
+ * This interface provides means for sending audio data to output devices.
+ */
+@VintfStability
+interface IStreamOut {
+ /**
+ * Close the stream.
+ *
+ * Releases any resources allocated for this stream on the HAL module side.
+ * This includes the fast message queues and shared memories returned via
+ * the StreamDescriptor. Thus, the stream can not be operated anymore after
+ * it has been closed. The client needs to release the audio data I/O
+ * objects after the call to this method returns.
+ *
+ * Methods of this interface throw EX_ILLEGAL_STATE for a closed stream.
+ *
+ * @throws EX_ILLEGAL_STATE If the stream has already been closed.
+ */
+ void close();
+
+ /**
+ * Update stream metadata.
+ *
+ * Updates the metadata initially provided at the stream creation.
+ *
+ * @param sourceMetadata Updated metadata.
+ * @throws EX_ILLEGAL_STATE If the stream is closed.
+ */
+ void updateMetadata(in SourceMetadata sourceMetadata);
+}
diff --git a/audio/aidl/android/hardware/audio/core/ITelephony.aidl b/audio/aidl/android/hardware/audio/core/ITelephony.aidl
new file mode 100644
index 0000000..a872c7c
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/ITelephony.aidl
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.core;
+
+import android.hardware.audio.core.AudioMode;
+
+/**
+ * An instance of ITelephony manages settings which are specific to voice calls
+ * and SMS messaging functionality. This interface is optional to implement and
+ * provide by the vendor. It needs to be provided only if the device actually
+ * supports telephony.
+ */
+@VintfStability
+interface ITelephony {
+ /**
+ * Return the list of supported audio modes.
+ *
+ * The first 4 AudioModes: NORMAL, RINGTONE, IN_CALL, IN_COMMUNICATION must
+ * be supported by all implementations.
+ *
+ * This method is only called once, during the audio system initialization,
+ * and must return the same result all the time.
+ *
+ * @return The list of supported audio modes.
+ */
+ AudioMode[] getSupportedAudioModes();
+
+ /**
+ * Switch the HAL into a new audio mode.
+ *
+ * The current audio mode is always controlled by the client. The HAL must
+ * accept all modes returned by 'getSupportedAudioModes' and reject the
+ * rest. The HAL must return from this method only after switching itself
+ * to the specified mode, or throw an error if there was a problem during
+ * switching.
+ *
+ * @param mode The mode to switch to.
+ * @throws EX_UNSUPPORTED_OPERATION If the HAL does not support the specified mode.
+ * @throws EX_ILLEGAL_STATE If there was an error during switching.
+ */
+ void switchAudioMode(AudioMode mode);
+}
diff --git a/audio/aidl/android/hardware/audio/core/MmapBufferDescriptor.aidl b/audio/aidl/android/hardware/audio/core/MmapBufferDescriptor.aidl
new file mode 100644
index 0000000..108bcbe
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/MmapBufferDescriptor.aidl
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.core;
+
+import android.hardware.common.Ashmem;
+
+/**
+ * MMap buffer descriptor is used by streams opened in MMap No IRQ mode.
+ */
+@JavaDerive(equals=true, toString=true)
+@VintfStability
+parcelable MmapBufferDescriptor {
+ /**
+ * MMap memory buffer.
+ */
+ Ashmem sharedMemory;
+ /**
+ * Transfer size granularity in frames.
+ */
+ long burstSizeFrames;
+ /**
+ * Attributes describing the buffer. Bitmask indexed by FLAG_INDEX_*
+ * constants.
+ */
+ int flags;
+
+ /**
+ * Whether the buffer can be securely shared to untrusted applications
+ * through the AAudio exclusive mode.
+ *
+ * Only set this flag if applications are restricted from accessing the
+ * memory surrounding the audio data buffer by a kernel mechanism.
+ * See Linux kernel's dma-buf
+ * (https://www.kernel.org/doc/html/v4.16/driver-api/dma-buf.html).
+ */
+ const int FLAG_INDEX_APPLICATION_SHAREABLE = 0;
+}
diff --git a/audio/aidl/android/hardware/audio/core/ModuleDebug.aidl b/audio/aidl/android/hardware/audio/core/ModuleDebug.aidl
new file mode 100644
index 0000000..871a5c9
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/ModuleDebug.aidl
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.core;
+
+/**
+ * This structure contains flags used for enabling various debugging aspects
+ * in a HAL module. By default, all debugging aspects are turned off. They
+ * can be enabled during xTS tests for functionality that, for example, would
+ * otherwise require human intervention (e.g. connection of external devices).
+ */
+@JavaDerive(equals=true, toString=true)
+@VintfStability
+parcelable ModuleDebug {
+ /**
+ * When set to 'true', HAL module must simulate connection of external
+ * devices. An external device becomes 'connected' after a call to
+ * IModule.connectExternalDevice, simulation of connection requires:
+ * - provision of at least one non-dynamic device port profile on
+ * connection (as if it was retrieved from a connected device);
+ * - simulating successful application of port configurations for reported
+ * profiles.
+ */
+ boolean simulateDeviceConnections;
+ /**
+ * Must be non-negative. When set to non-zero, HAL module must delay
+ * transition from "transient" stream states (see StreamDescriptor.aidl)
+ * by the specified amount of milliseconds. The purpose of this delay
+ * is to allow VTS to test sending of stream commands while the stream is
+ * in a transient state. The delay must apply to newly created streams,
+ * it is not required to apply the delay to already opened streams.
+ *
+ * Note: the drawback of enabling this delay for asynchronous (non-blocking)
+ * modes is that sending of callbacks will also be delayed, because
+ * callbacks are sent once the stream state machine exits a transient
+ * state. Thus, it's not recommended to use it with tests that require
+ * waiting for an async callback.
+ */
+ int streamTransientStateDelayMs;
+}
diff --git a/audio/aidl/android/hardware/audio/core/StreamDescriptor.aidl b/audio/aidl/android/hardware/audio/core/StreamDescriptor.aidl
new file mode 100644
index 0000000..65ea9ef
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/StreamDescriptor.aidl
@@ -0,0 +1,510 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.core;
+
+import android.hardware.audio.core.MmapBufferDescriptor;
+import android.hardware.common.fmq.MQDescriptor;
+import android.hardware.common.fmq.SynchronizedReadWrite;
+import android.media.audio.common.Void;
+
+/**
+ * Stream descriptor contains fast message queues and buffers used for sending
+ * and receiving audio data. The descriptor complements IStream* interfaces by
+ * providing communication channels that serve as an alternative to Binder
+ * transactions.
+ *
+ * Handling of audio data and commands must be done by the HAL module on a
+ * dedicated thread with high priority, for all modes, including MMap No
+ * IRQ. The HAL module is responsible for creating this thread and setting its
+ * priority. The HAL module is also responsible for serializing access to the
+ * internal components of the stream while serving commands invoked via the
+ * stream's AIDL interface and commands invoked via the command queue of the
+ * descriptor.
+ *
+ * There is a state machine defined for the stream, which executes on the
+ * thread handling the commands from the queue. The states are defined based
+ * on the model of idealized producer and consumer connected via a ring buffer.
+ * For input streams, the "producer" is hardware, the "consumer" is software,
+ * for outputs streams it's the opposite. When the producer is active, but
+ * the buffer is full, the following actions are possible:
+ * - if the consumer is active, the producer blocks until there is space,
+ * this behavior is only possible for software producers;
+ * - if the consumer is passive:
+ * - the producer can preserve the buffer contents—a s/w producer can
+ * keep the data on their side, while a h/w producer can only drop captured
+ * data in this case;
+ * - or the producer overwrites old data in the buffer.
+ * Similarly, when an active consumer faces an empty buffer, it can:
+ * - block until there is data (producer must be active), only possible
+ * for software consumers;
+ * - walk away with no data; when the consumer is hardware, it must emit
+ * silence in this case.
+ *
+ * The model is defined below, note the asymmetry regarding the 'IDLE' state
+ * between input and output streams:
+ *
+ * Producer | Buffer state | Consumer | Applies | State
+ * active? | | active? | to |
+ * ==========|==============|==========|=========|==============================
+ * No | Empty | No | Both | STANDBY
+ * ----------|--------------|----------|---------|-----------------------------
+ * Yes | Filling up | No | Input | IDLE, overwrite behavior
+ * ----------|--------------|----------|---------|-----------------------------
+ * No | Empty | Yes† | Output | IDLE, h/w emits silence
+ * ----------|--------------|----------|---------|-----------------------------
+ * Yes | Not empty | Yes | Both | ACTIVE, s/w x-runs counted
+ * ----------|--------------|----------|---------|-----------------------------
+ * Yes | Filling up | No | Input | PAUSED, drop behavior
+ * ----------|--------------|----------|---------|-----------------------------
+ * Yes | Filling up | No† | Output | PAUSED, s/w stops writing once
+ * | | | | the buffer is filled up;
+ * | | | | h/w emits silence.
+ * ----------|--------------|----------|---------|-----------------------------
+ * No | Not empty | Yes | Both | DRAINING
+ * ----------|--------------|----------|---------|-----------------------------
+ * No | Not empty | No† | Output | DRAIN_PAUSED,
+ * | | | | h/w emits silence.
+ *
+ * † - note that for output, "buffer empty, h/w consuming" has the same outcome
+ * as "buffer not empty, h/w not consuming", but logically these conditions
+ * are different.
+ *
+ * State machines of both input and output streams start from the 'STANDBY'
+ * state. Transitions between states happen naturally with changes in the
+ * states of the model elements. For simplicity, we restrict the change to one
+ * element only, for example, in the 'STANDBY' state, either the producer or the
+ * consumer can become active, but not both at the same time. States 'STANDBY',
+ * 'IDLE', 'READY', and '*PAUSED' are "stable"—they require an external event,
+ * whereas a change from the 'DRAINING' state can happen with time as the buffer
+ * gets empty, thus it's a "transient" state.
+ *
+ * The state machine for input streams is defined in the `stream-in-sm.gv` file,
+ * for output streams—in the `stream-out-sm.gv` file. State machines define how
+ * commands (from the enum 'CommandCode') trigger state changes. The full list
+ * of states and commands is defined by constants of the 'State' enum. Note that
+ * the 'CLOSED' state does not have a constant in the interface because the
+ * client can never observe a stream with a functioning command queue in this
+ * state. The 'ERROR' state is a special state which the state machine enters
+ * when an unrecoverable hardware error is detected by the HAL module.
+ *
+ * Non-blocking (asynchronous) modes introduce a new 'TRANSFERRING' state, which
+ * the state machine can enter after replying to the 'burst' command, instead of
+ * staying in the 'ACTIVE' state. In this case the client gets unblocked
+ * earlier, while the actual audio delivery to / from the observer is not
+ * complete yet. Once the HAL module is ready for the next transfer, it notifies
+ * the client via a oneway callback, and the machine switches to 'ACTIVE'
+ * state. The 'TRANSFERRING' state is thus "transient", similar to the
+ * 'DRAINING' state. For output streams, asynchronous transfer can be paused,
+ * and it's another new state: 'TRANSFER_PAUSED'. It differs from 'PAUSED' by
+ * the fact that no new writes are allowed. Please see 'stream-in-async-sm.gv'
+ * and 'stream-out-async-sm.gv' files for details. Below is the table summary
+ * for asynchronous only-states:
+ *
+ * Producer | Buffer state | Consumer | Applies | State
+ * active? | | active? | to |
+ * ==========|==============|==========|=========|==============================
+ * Yes | Not empty | Yes | Both | TRANSFERRING, s/w x-runs counted
+ * ----------|--------------|----------|---------|-----------------------------
+ * Yes | Not empty | No | Output | TRANSFER_PAUSED,
+ * | | | | h/w emits silence.
+ *
+ */
+@JavaDerive(equals=true, toString=true)
+@VintfStability
+parcelable StreamDescriptor {
+ /**
+ * Position binds together a position within the stream and time.
+ *
+ * The timestamp must use "monotonic" clock.
+ *
+ * The frame count must advance between consecutive I/O operations, and stop
+ * advancing when the stream was put into the 'standby' mode. On exiting the
+ * 'standby' mode, the frame count must not reset, but continue counting.
+ */
+ @VintfStability
+ @FixedSize
+ parcelable Position {
+ /**
+ * The value used when the position can not be reported by the HAL
+ * module.
+ */
+ const long UNKNOWN = -1;
+ /** Frame count. */
+ long frames = UNKNOWN;
+ /** Timestamp in nanoseconds. */
+ long timeNs = UNKNOWN;
+ }
+
+ @VintfStability
+ @Backing(type="int")
+ enum State {
+ /**
+ * 'STANDBY' is the initial state of the stream, entered after
+ * opening. Since both the producer and the consumer are inactive in
+ * this state, it allows the HAL module to put associated hardware into
+ * "standby" mode to save power.
+ */
+ STANDBY = 1,
+ /**
+ * In the 'IDLE' state the audio hardware is active. For input streams,
+ * the hardware is filling buffer with captured data, overwriting old
+ * contents on buffer wraparounds. For output streams, the buffer is
+ * still empty, and the hardware is outputting zeroes. The HAL module
+ * must not account for any under- or overruns as the client is not
+ * expected to perform audio I/O.
+ */
+ IDLE = 2,
+ /**
+ * The active state of the stream in which it handles audio I/O. The HAL
+ * module can assume that the audio I/O will be periodic, thus inability
+ * of the client to provide or consume audio data on time must be
+ * considered as an under- or overrun and indicated via the 'xrunFrames'
+ * field of the reply.
+ */
+ ACTIVE = 3,
+ /**
+ * In the 'PAUSED' state the consumer is inactive. For input streams,
+ * the hardware stops updating the buffer as soon as it fills up (this
+ * is the difference from the 'IDLE' state). For output streams,
+ * "inactivity" of hardware means that it does not consume audio data,
+ * but rather emits silence.
+ */
+ PAUSED = 4,
+ /**
+ * In the 'DRAINING' state the producer is inactive, the consumer is
+ * finishing up on the buffer contents, emptying it up. As soon as it
+ * gets empty, the stream transfers itself into the next state.
+ */
+ DRAINING = 5,
+ /**
+ * Used for output streams only, pauses draining. This state is similar
+ * to the 'PAUSED' state, except that the client is not adding any
+ * new data. If it emits a 'burst' command, this brings the stream
+ * into the regular 'PAUSED' state.
+ */
+ DRAIN_PAUSED = 6,
+ /**
+ * Used only for streams in asynchronous mode. The stream enters this
+ * state after receiving a 'burst' command and returning control back
+ * to the client, thus unblocking it.
+ */
+ TRANSFERRING = 7,
+ /**
+ * Used only for output streams in asynchronous mode only. The stream
+ * enters this state after receiving a 'pause' command while being in
+ * the 'TRANSFERRING' state. Unlike 'PAUSED' state, this state does not
+ * accept new writes.
+ */
+ TRANSFER_PAUSED = 8,
+ /**
+ * The ERROR state is entered when the stream has encountered an
+ * irrecoverable error from the lower layer. After entering it, the
+ * stream can only be closed.
+ */
+ ERROR = 100,
+ }
+
+ @VintfStability
+ @Backing(type="byte")
+ enum DrainMode {
+ /**
+ * Unspecified—used with input streams only, because the client controls
+ * draining.
+ */
+ DRAIN_UNSPECIFIED = 0,
+ /**
+ * Used with output streams only, the HAL module indicates drain
+ * completion when all remaining audio data has been consumed.
+ */
+ DRAIN_ALL = 1,
+ /**
+ * Used with output streams only, the HAL module indicates drain
+ * completion shortly before all audio data has been consumed in order
+ * to give the client an opportunity to provide data for the next track
+ * for gapless playback. The exact amount of provided time is specific
+ * to the HAL implementation.
+ */
+ DRAIN_EARLY_NOTIFY = 2,
+ }
+
+ /**
+ * Used for sending commands to the HAL module. The client writes into
+ * the queue, the HAL module reads. The queue can only contain a single
+ * command.
+ *
+ * Variants of type 'Void' correspond to commands without
+ * arguments. Variants of other types correspond to commands with an
+ * argument. Would in future a need for a command with multiple argument
+ * arise, a Parcelable type should be used for the corresponding variant.
+ */
+ @VintfStability
+ @FixedSize
+ union Command {
+ /**
+ * Reserved for the HAL implementation to allow unblocking the wait on a
+ * command and exiting the I/O thread. A command of this variant must
+ * never be sent from the client side. To prevent that, the
+ * implementation must pass a random cookie as the command argument,
+ * which is only known to the implementation.
+ */
+ int halReservedExit;
+ /**
+ * Retrieve the current state of the stream. This command must be
+ * processed by the stream in any state. The stream must provide current
+ * positions, counters, and its state in the reply. This command must be
+ * handled by the HAL module without any observable side effects.
+ */
+ Void getStatus;
+ /**
+ * See the state machines on the applicability of this command to
+ * different states.
+ */
+ Void start;
+ /**
+ * The 'burst' command used for audio I/O, see 'AudioBuffer'. The value
+ * specifies:
+ *
+ * - for output streams: the amount of bytes that the client requests the
+ * HAL module to use out of the data contained in the 'audio.fmq' queue.
+ *
+ * - for input streams: the amount of bytes requested by the client to
+ * read from the hardware into the 'audio.fmq' queue.
+ *
+ * In both cases it is allowed for this field to contain any
+ * non-negative number. Any sufficiently big value which exceeds the
+ * size of the queue's area which is currently available for reading or
+ * writing by the HAL module must be trimmed by the HAL module to the
+ * available size. Note that the HAL module is allowed to consume or
+ * provide less data than requested, and it must return the amount of
+ * actually read or written data via the 'Reply.fmqByteCount'
+ * field. Thus, only attempts to pass a negative number must be
+ * constituted as a client's error.
+ *
+ * Differences for the MMap No IRQ mode:
+ *
+ * - this command only provides updated positions and latency because
+ * actual audio I/O is done via the 'AudioBuffer.mmap' shared buffer.
+ * The client does not synchronize reads and writes into the buffer
+ * with sending of this command.
+ *
+ * - the value must always be set to 0.
+ *
+ * See the state machines on the applicability of this command to
+ * different states.
+ */
+ int burst;
+ /**
+ * See the state machines on the applicability of this command to
+ * different states.
+ */
+ DrainMode drain;
+ /**
+ * See the state machines on the applicability of this command to
+ * different states.
+ *
+ * Note that it's left on the discretion of the HAL implementation to
+ * assess all the necessary conditions that could prevent hardware from
+ * being suspended. Even if it can not be suspended, the state machine
+ * must still enter the 'STANDBY' state for consistency. Since the
+ * buffer must remain empty in this state, even if capturing hardware is
+ * still active, captured data must be discarded.
+ */
+ Void standby;
+ /**
+ * See the state machines on the applicability of this command to
+ * different states.
+ */
+ Void pause;
+ /**
+ * See the state machines on the applicability of this command to
+ * different states.
+ */
+ Void flush;
+ }
+ MQDescriptor<Command, SynchronizedReadWrite> command;
+
+ /**
+ * The value used for the 'Reply.latencyMs' field when the effective
+ * latency can not be reported by the HAL module.
+ */
+ const int LATENCY_UNKNOWN = -1;
+
+ /**
+ * Used for providing replies to commands. The HAL module writes into
+ * the queue, the client reads. The queue can only contain a single reply,
+ * corresponding to the last command sent by the client.
+ */
+ @VintfStability
+ @FixedSize
+ parcelable Reply {
+ /**
+ * One of Binder STATUS_* statuses:
+ * - STATUS_OK: the command has completed successfully;
+ * - STATUS_BAD_VALUE: invalid value in the 'Command' structure;
+ * - STATUS_INVALID_OPERATION: the command is not applicable in the
+ * current state of the stream, or to this
+ * type of the stream;
+ * - STATUS_NOT_ENOUGH_DATA: a read or write error has
+ * occurred for the 'audio.fmq' queue;
+ */
+ int status;
+ /**
+ * Used with the 'burst' command only.
+ *
+ * For output streams: the amount of bytes of data actually consumed
+ * by the HAL module.
+ * For input streams: the amount of bytes actually provided by the HAL
+ * in the 'audio.fmq' queue.
+ *
+ * The returned value must not exceed the value passed as the
+ * argument of the corresponding command, or be negative.
+ */
+ int fmqByteCount;
+ /**
+ * It is recommended to report the current position for any command. If
+ * the position can not be reported, for example because the mix port is
+ * not connected to any producer or consumer, or because the HAL module
+ * does not support positions reporting for this AudioSource (on input
+ * streams), the 'Position::UNKNOWN' value must be used.
+ *
+ * For output streams: the moment when the specified stream position
+ * was presented to an external observer (i.e. presentation position).
+ * For input streams: the moment when data at the specified stream position
+ * was acquired (i.e. capture position).
+ *
+ * The observable position must never be reset by the HAL module.
+ * The data type of the frame counter is large enough to support
+ * continuous counting for years of operation.
+ */
+ Position observable;
+ /**
+ * Used only for MMap streams to provide the hardware read / write
+ * position for audio data in the shared memory buffer 'audio.mmap'.
+ */
+ Position hardware;
+ /**
+ * Current latency reported by the hardware. It is recommended to
+ * report the current latency for any command. If the value of latency
+ * can not be determined, this field must be set to 'LATENCY_UNKNOWN'.
+ */
+ int latencyMs;
+ /**
+ * Number of frames lost due to an underrun (for input streams),
+ * or not provided on time (for output streams) for the **previous**
+ * transfer operation.
+ */
+ int xrunFrames;
+ /**
+ * The state that the stream was in while the HAL module was sending the
+ * reply.
+ */
+ State state = State.STANDBY;
+ }
+ MQDescriptor<Reply, SynchronizedReadWrite> reply;
+
+ /**
+ * The size of one frame of audio data in bytes. For PCM formats this is
+ * usually equal to the size of a sample multiplied by the number of
+ * channels used. For encoded bitstreams encapsulated into PCM the sample
+ * size of the underlying PCM stream is used. For encoded bitstreams that
+ * are passed without encapsulation, the frame size is usually 1 byte.
+ */
+ int frameSizeBytes;
+ /**
+ * Total buffer size in frames. This applies both to the size of the 'audio.fmq'
+ * queue and to the size of the shared memory buffer for MMap No IRQ streams.
+ * Note that this size may end up being slightly larger than the size requested
+ * in a call to 'IModule.openInputStream' or 'openOutputStream' due to memory
+ * alignment requirements.
+ */
+ long bufferSizeFrames;
+
+ /**
+ * Used for sending or receiving audio data to/from the stream. In the case
+ * of MMap No IRQ streams this structure only contains the information about
+ * the shared memory buffer. Audio data is sent via the shared buffer
+ * directly.
+ */
+ @VintfStability
+ union AudioBuffer {
+ /**
+ * The fast message queue used for BURST commands in all modes except
+ * MMap No IRQ. Both reads and writes into this queue are non-blocking
+ * because access to this queue is synchronized via the 'command' and
+ * 'reply' queues as described below. The queue nevertheless uses
+ * 'SynchronizedReadWrite' because there is only one reader, and the
+ * reading position must be shared.
+ *
+ * Note that the fast message queue is a transient buffer, only used for
+ * data transfer. Neither of the sides can use it to store any data
+ * outside of the 'BURST' operation. The consumer must always retrieve
+ * all data available in the fast message queue, even if it can not use
+ * it. The producer must re-send any unconsumed data on the next
+ * transfer operation. This restriction is posed in order to make the
+ * fast message queue fully transparent from the latency perspective.
+ *
+ * For output streams the following sequence of operations is used:
+ * 1. The client writes audio data into the 'audio.fmq' queue.
+ * 2. The client writes the BURST command into the 'command' queue,
+ * and hangs on waiting on a read from the 'reply' queue.
+ * 3. The high priority thread in the HAL module wakes up due to 2.
+ * 4. The HAL module reads the command and audio data. According
+ * to the statement above, the HAL module must always read
+ * from the FMQ all the data it contains. The amount of data that
+ * the HAL module has actually consumed is indicated to the client
+ * via the 'reply.fmqByteCount' field.
+ * 5. The HAL module writes the command status and current positions
+ * into 'reply' queue, and hangs on waiting on a read from
+ * the 'command' queue.
+ * 6. The client wakes up due to 5. and reads the reply.
+ * Note: in non-blocking mode, when the HAL module goes to
+ * the 'TRANSFERRING' state (as indicated by the 'reply.state'
+ * field), the client must wait for the 'IStreamCallback.onTransferReady'
+ * notification to arrive before starting the next burst.
+ *
+ * For input streams the following sequence of operations is used:
+ * 1. The client writes the BURST command into the 'command' queue,
+ * and hangs on waiting on a read from the 'reply' queue.
+ * 2. The high priority thread in the HAL module wakes up due to 1.
+ * 3. The HAL module writes audio data into the 'audio.fmq' queue.
+ * The value of 'reply.fmqByteCount' must be the equal to the amount
+ * of data in the queue.
+ * 4. The HAL module writes the command status and current positions
+ * into 'reply' queue, and hangs on waiting on a read from
+ * the 'command' queue.
+ * 5. The client wakes up due to 4.
+ * 6. The client reads the reply and audio data. The client must
+ * always read from the FMQ all the data it contains.
+ * Note: in non-blocking mode, when the HAL module goes to
+ * the 'TRANSFERRING' state (as indicated by the 'reply.state'
+ * field) the client must wait for the 'IStreamCallback.onTransferReady'
+ * notification to arrive before starting the next burst.
+ *
+ */
+ MQDescriptor<byte, SynchronizedReadWrite> fmq;
+ /**
+ * MMap buffers are shared directly with the DSP, which operates
+ * independently from the CPU. Writes and reads into these buffers are
+ * not synchronized with 'command' and 'reply' queues. However, the
+ * client still uses the same commands for controlling the audio data
+ * exchange and for obtaining current positions and latency from the HAL
+ * module.
+ */
+ MmapBufferDescriptor mmap;
+ }
+ AudioBuffer audio;
+}
diff --git a/audio/aidl/android/hardware/audio/core/SurroundSoundConfig.aidl b/audio/aidl/android/hardware/audio/core/SurroundSoundConfig.aidl
new file mode 100644
index 0000000..eeda12a
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/SurroundSoundConfig.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.core;
+
+import android.media.audio.common.AudioFormatDescription;
+
+/**
+ * SurroundSoundConfig defines the multi-channel formats that can be enabled on
+ * (primarily TV) devices.
+ */
+@JavaDerive(equals=true, toString=true)
+@VintfStability
+parcelable SurroundSoundConfig {
+ @VintfStability
+ parcelable SurroundFormatFamily {
+ /**
+ * A primaryFormat shall get an entry in the Surround Settings dialog on TV
+ * devices. There must be a corresponding Java ENCODING_... constant
+ * defined in AudioFormat.java, and a display name defined in
+ * AudioFormat.toDisplayName.
+ */
+ AudioFormatDescription primaryFormat;
+ /**
+ * List of formats that shall be equivalent to the primaryFormat from the
+ * users' point of view and don't need a dedicated Surround Settings
+ * dialog entry.
+ */
+ AudioFormatDescription[] subFormats;
+ }
+ SurroundFormatFamily[] formatFamilies;
+}
diff --git a/audio/aidl/android/hardware/audio/core/stream-in-async-sm.gv b/audio/aidl/android/hardware/audio/core/stream-in-async-sm.gv
new file mode 100644
index 0000000..818b18e
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/stream-in-async-sm.gv
@@ -0,0 +1,47 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// To render: dot -Tpng stream-in-async-sm.gv -o stream-in-async-sm.png
+digraph stream_in_async_state_machine {
+ node [shape=doublecircle style=filled fillcolor=black width=0.5] I;
+ node [shape=point width=0.5] F;
+ node [shape=oval width=1];
+ node [fillcolor=lightgreen] STANDBY; // buffer is empty
+ node [fillcolor=tomato] CLOSED;
+ node [fillcolor=tomato] ERROR;
+ node [style=dashed] ANY_STATE;
+ node [fillcolor=lightblue style=filled];
+ // Note that when the producer (h/w) is passive, "burst" operations
+ // complete synchronously, bypassing the TRANSFERRING state.
+ I -> STANDBY;
+ STANDBY -> IDLE [label="start"]; // producer -> active
+ IDLE -> STANDBY [label="standby"]; // producer -> passive, buffer is cleared
+ IDLE -> TRANSFERRING [label="burst"]; // consumer -> active
+ ACTIVE -> PAUSED [label="pause"]; // consumer -> passive
+ ACTIVE -> DRAINING [label="drain"]; // producer -> passive
+ ACTIVE -> TRANSFERRING [label="burst"];
+ TRANSFERRING -> ACTIVE [label="←IStreamCallback.onTransferReady"];
+ TRANSFERRING -> PAUSED [label="pause"]; // consumer -> passive
+ TRANSFERRING -> DRAINING [label="drain"]; // producer -> passive
+ PAUSED -> TRANSFERRING [label="burst"]; // consumer -> active
+ PAUSED -> STANDBY [label="flush"]; // producer -> passive, buffer is cleared
+ DRAINING -> DRAINING [label="burst"];
+ DRAINING -> ACTIVE [label="start"]; // producer -> active
+ DRAINING -> STANDBY [label="<empty buffer>"]; // consumer deactivates
+ IDLE -> ERROR [label="←IStreamCallback.onError"];
+ PAUSED -> ERROR [label="←IStreamCallback.onError"];
+ TRANSFERRING -> ERROR [label="←IStreamCallback.onError"];
+ ANY_STATE -> CLOSED [label="→IStream*.close"];
+ CLOSED -> F;
+}
diff --git a/audio/aidl/android/hardware/audio/core/stream-in-sm.gv b/audio/aidl/android/hardware/audio/core/stream-in-sm.gv
new file mode 100644
index 0000000..805dc32
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/stream-in-sm.gv
@@ -0,0 +1,42 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// To render: dot -Tpng stream-in-sm.gv -o stream-in-sm.png
+digraph stream_in_state_machine {
+ node [shape=doublecircle style=filled fillcolor=black width=0.5] I;
+ node [shape=point width=0.5] F;
+ node [shape=oval width=1];
+ node [fillcolor=lightgreen] STANDBY; // buffer is empty
+ node [fillcolor=tomato] CLOSED;
+ node [fillcolor=tomato] ERROR;
+ node [style=dashed] ANY_STATE;
+ node [fillcolor=lightblue style=filled];
+ I -> STANDBY;
+ STANDBY -> IDLE [label="start"]; // producer -> active
+ IDLE -> STANDBY [label="standby"]; // producer -> passive, buffer is cleared
+ IDLE -> ACTIVE [label="burst"]; // consumer -> active
+ ACTIVE -> ACTIVE [label="burst"];
+ ACTIVE -> PAUSED [label="pause"]; // consumer -> passive
+ ACTIVE -> DRAINING [label="drain"]; // producer -> passive
+ PAUSED -> ACTIVE [label="burst"]; // consumer -> active
+ PAUSED -> STANDBY [label="flush"]; // producer -> passive, buffer is cleared
+ DRAINING -> DRAINING [label="burst"];
+ DRAINING -> ACTIVE [label="start"]; // producer -> active
+ DRAINING -> STANDBY [label="<empty buffer>"]; // consumer deactivates
+ IDLE -> ERROR [label="<hardware failure>"];
+ ACTIVE -> ERROR [label="<hardware failure>"];
+ PAUSED -> ERROR [label="<hardware failure>"];
+ ANY_STATE -> CLOSED [label="→IStream*.close"];
+ CLOSED -> F;
+}
diff --git a/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv b/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv
new file mode 100644
index 0000000..e25b15a
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv
@@ -0,0 +1,57 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// To render: dot -Tpng stream-out-async-sm.gv -o stream-out-async-sm.png
+digraph stream_out_async_state_machine {
+ node [shape=doublecircle style=filled fillcolor=black width=0.5] I;
+ node [shape=point width=0.5] F;
+ node [shape=oval width=1];
+ node [fillcolor=lightgreen] STANDBY; // buffer is empty
+ node [fillcolor=lightgreen] IDLE; // buffer is empty
+ node [fillcolor=tomato] CLOSED;
+ node [fillcolor=tomato] ERROR;
+ node [style=dashed] ANY_STATE;
+ node [fillcolor=lightblue style=filled];
+ // Note that when the consumer (h/w) is passive, "burst" operations
+ // complete synchronously, bypassing the TRANSFERRING state.
+ I -> STANDBY;
+ STANDBY -> IDLE [label="start"]; // consumer -> active
+ STANDBY -> PAUSED [label="burst"]; // producer -> active
+ IDLE -> STANDBY [label="standby"]; // consumer -> passive
+ IDLE -> TRANSFERRING [label="burst"]; // producer -> active
+ ACTIVE -> PAUSED [label="pause"]; // consumer -> passive (not consuming)
+ ACTIVE -> DRAINING [label="drain"]; // producer -> passive
+ ACTIVE -> TRANSFERRING [label="burst"]; // early unblocking
+ ACTIVE -> ACTIVE [label="burst"]; // full write
+ TRANSFERRING -> ACTIVE [label="←IStreamCallback.onTransferReady"];
+ TRANSFERRING -> TRANSFER_PAUSED [label="pause"]; // consumer -> passive (not consuming)
+ TRANSFERRING -> DRAINING [label="drain"]; // producer -> passive
+ TRANSFER_PAUSED -> TRANSFERRING [label="start"]; // consumer -> active
+ TRANSFER_PAUSED -> DRAIN_PAUSED [label="drain"]; // producer -> passive
+ TRANSFER_PAUSED -> IDLE [label="flush"]; // buffer is cleared
+ PAUSED -> PAUSED [label="burst"];
+ PAUSED -> ACTIVE [label="start"]; // consumer -> active
+ PAUSED -> IDLE [label="flush"]; // producer -> passive, buffer is cleared
+ DRAINING -> IDLE [label="←IStreamCallback.onDrainReady"];
+ DRAINING -> TRANSFERRING [label="burst"]; // producer -> active
+ DRAINING -> DRAIN_PAUSED [label="pause"]; // consumer -> passive (not consuming)
+ DRAIN_PAUSED -> DRAINING [label="start"]; // consumer -> active
+ DRAIN_PAUSED -> TRANSFER_PAUSED [label="burst"]; // producer -> active
+ DRAIN_PAUSED -> IDLE [label="flush"]; // buffer is cleared
+ IDLE -> ERROR [label="←IStreamCallback.onError"];
+ DRAINING -> ERROR [label="←IStreamCallback.onError"];
+ TRANSFERRING -> ERROR [label="←IStreamCallback.onError"];
+ ANY_STATE -> CLOSED [label="→IStream*.close"];
+ CLOSED -> F;
+}
diff --git a/audio/aidl/android/hardware/audio/core/stream-out-sm.gv b/audio/aidl/android/hardware/audio/core/stream-out-sm.gv
new file mode 100644
index 0000000..6aa5c61
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/stream-out-sm.gv
@@ -0,0 +1,48 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// To render: dot -Tpng stream-out-sm.gv -o stream-out-sm.png
+digraph stream_out_state_machine {
+ node [shape=doublecircle style=filled fillcolor=black width=0.5] I;
+ node [shape=point width=0.5] F;
+ node [shape=oval width=1];
+ node [fillcolor=lightgreen] STANDBY; // buffer is empty
+ node [fillcolor=lightgreen] IDLE; // buffer is empty
+ node [fillcolor=tomato] CLOSED;
+ node [fillcolor=tomato] ERROR;
+ node [style=dashed] ANY_STATE;
+ node [fillcolor=lightblue style=filled];
+ I -> STANDBY;
+ STANDBY -> IDLE [label="start"]; // consumer -> active
+ STANDBY -> PAUSED [label="burst"]; // producer -> active
+ IDLE -> STANDBY [label="standby"]; // consumer -> passive
+ IDLE -> ACTIVE [label="burst"]; // producer -> active
+ ACTIVE -> ACTIVE [label="burst"];
+ ACTIVE -> PAUSED [label="pause"]; // consumer -> passive (not consuming)
+ ACTIVE -> DRAINING [label="drain"]; // producer -> passive
+ PAUSED -> PAUSED [label="burst"];
+ PAUSED -> ACTIVE [label="start"]; // consumer -> active
+ PAUSED -> IDLE [label="flush"]; // producer -> passive, buffer is cleared
+ DRAINING -> IDLE [label="<empty buffer>"];
+ DRAINING -> ACTIVE [label="burst"]; // producer -> active
+ DRAINING -> DRAIN_PAUSED [label="pause"]; // consumer -> passive (not consuming)
+ DRAIN_PAUSED -> DRAINING [label="start"]; // consumer -> active
+ DRAIN_PAUSED -> PAUSED [label="burst"]; // producer -> active
+ DRAIN_PAUSED -> IDLE [label="flush"]; // buffer is cleared
+ IDLE -> ERROR [label="<hardware failure>"];
+ ACTIVE -> ERROR [label="<hardware failure>"];
+ DRAINING -> ERROR [label="<hardware failure>"];
+ ANY_STATE -> CLOSED [label="→IStream*.close"];
+ CLOSED -> F;
+}
diff --git a/audio/aidl/android/hardware/audio/effect/BassBoost.aidl b/audio/aidl/android/hardware/audio/effect/BassBoost.aidl
new file mode 100644
index 0000000..810c188
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/BassBoost.aidl
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect;
+
+import android.hardware.audio.effect.VendorExtension;
+
+/**
+ * Bass boost is an audio effect to boost or amplify low frequencies of the sound. It is comparable
+ * to a simple equalizer but limited to one band amplification in the low frequency range.
+ *
+ * All parameters defined in union BassBoost must be gettable and settable. The capabilities defined
+ * in BassBoost.Capability can only acquired with IEffect.getDescriptor() and not settable.
+ */
+@VintfStability
+union BassBoost {
+ /**
+ * Effect parameter tag to identify the parameters for getParameter().
+ */
+ @VintfStability
+ union Id {
+ int vendorExtensionTag;
+ BassBoost.Tag commonTag;
+ }
+
+ /**
+ * Vendor BassBoost implementation definition for additional parameters.
+ */
+ VendorExtension vendor;
+
+ /**
+ * Capability supported by BassBoost implementation.
+ */
+ @VintfStability
+ parcelable Capability {
+ /**
+ * BassBoost capability extension, vendor can use this extension in case existing capability
+ * definition not enough.
+ */
+ ParcelableHolder extension;
+ /**
+ * Indicates whether setting strength is supported. False value indicates only one strength
+ * is supported and setParameter() method will return EX_ILLEGAL_ARGUMENT.
+ */
+ boolean strengthSupported;
+ }
+
+ /**
+ * The per mille strength of the bass boost effect.
+ *
+ * If the implementation does not support per mille accuracy for setting the strength, it is
+ * allowed to round the given strength to the nearest supported value. In this case {@link
+ * #IEffect.getParameter()} method should return the rounded value that was actually set.
+ *
+ * The valid range for strength is [0, 1000].
+ */
+ int strengthPm;
+}
diff --git a/audio/aidl/android/hardware/audio/effect/Capability.aidl b/audio/aidl/android/hardware/audio/effect/Capability.aidl
new file mode 100644
index 0000000..f741f33
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/Capability.aidl
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect;
+
+import android.hardware.audio.effect.BassBoost;
+import android.hardware.audio.effect.Downmix;
+import android.hardware.audio.effect.DynamicsProcessing;
+import android.hardware.audio.effect.Equalizer;
+import android.hardware.audio.effect.HapticGenerator;
+import android.hardware.audio.effect.LoudnessEnhancer;
+import android.hardware.audio.effect.Reverb;
+import android.hardware.audio.effect.VendorExtension;
+import android.hardware.audio.effect.Virtualizer;
+import android.hardware.audio.effect.Visualizer;
+import android.hardware.audio.effect.Volume;
+
+/**
+ * Effect capability definitions.
+ * This data structure is used as part of effect Descriptor to identify effect capabilities which
+ * not meant to change at runtime.
+ */
+@VintfStability
+union Capability {
+ /**
+ * Vendor defined effect capability.
+ * This extension can be used when vendor have a new effect implementated and need
+ * capability definition for this new type of effect.
+ * If vendor want to extend existing effect capabilities, it is recommended to expose though
+ * the ParcelableHolder in each effect capability definition. For example:
+ * Equalizer.Capability.extension.
+ */
+ VendorExtension vendorExtension;
+
+ /**
+ * Effect capabilities.
+ */
+ BassBoost.Capability bassBoost;
+ Downmix.Capability downmix;
+ DynamicsProcessing.Capability dynamicsProcessing;
+ Equalizer.Capability equalizer;
+ HapticGenerator.Capability hapticGenerator;
+ LoudnessEnhancer.Capability loudnessEnhancer;
+ Reverb.Capability reverb;
+ Virtualizer.Capability virtualizer;
+ Visualizer.Capability visualizer;
+ Volume.Capability volume;
+}
diff --git a/audio/aidl/android/hardware/audio/effect/CommandId.aidl b/audio/aidl/android/hardware/audio/effect/CommandId.aidl
new file mode 100644
index 0000000..d940b42
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/CommandId.aidl
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect;
+
+/**
+ * Defines all commands supported by the effect instance.
+ *
+ * There are three groups of commands:
+ * 1. Common part which MUST be supported by all effects.
+ * 2. Commands MUST be supported by a specific type of effect.
+ * 3. Extension commands for vendor.
+ */
+@VintfStability
+@Backing(type="int")
+enum CommandId {
+ /**
+ * Commands MUST be supported by all effects.
+ */
+ /**
+ * Start effect engine processing.
+ * An effect instance must start processing data and transfer to PROCESSING state if it is in
+ * IDLE state and have all necessary information. Otherwise it must:
+ * 1. Throw a EX_ILLEGAL_STATE exception if effect is not in IDLE state, or
+ * 2. Throw a EX_TRANSACTION_FAILED for all other errors.
+ *
+ * Depending on parameters set to the effect instance, effect may do process or reverse
+ * process after START command.
+ */
+ START = 0,
+ /**
+ * Stop effect engine processing with all resource kept.
+ * The currently processed audio data will be discarded if the effect engine is in PROCESSING
+ * state.
+ * Effect instance must do nothing and return ok when it receive STOP command in IDLE state.
+ */
+ STOP = 1,
+ /**
+ * Keep all parameter settings but reset the buffer content, stop engine processing, and transit
+ * instance state to IDLE if its in PROCESSING state.
+ * Effect instance must be able to handle RESET command at IDLE and PROCESSING states.
+ */
+ RESET = 2,
+
+ /**
+ * Commands MUST be supported by a specific type of effect.
+ */
+
+ /**
+ * Extension commands for vendor.
+ */
+ VENDOR_COMMAND_0 = 0x100,
+ VENDOR_COMMAND_1,
+ VENDOR_COMMAND_2,
+ VENDOR_COMMAND_3,
+ VENDOR_COMMAND_4,
+ VENDOR_COMMAND_5,
+ VENDOR_COMMAND_6,
+ VENDOR_COMMAND_7,
+ VENDOR_COMMAND_8,
+ VENDOR_COMMAND_9,
+}
diff --git a/audio/aidl/android/hardware/audio/effect/Descriptor.aidl b/audio/aidl/android/hardware/audio/effect/Descriptor.aidl
new file mode 100644
index 0000000..47c88dc
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/Descriptor.aidl
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.Capability;
+import android.hardware.audio.effect.Flags;
+import android.media.audio.common.AudioUuid;
+
+/**
+ * Descriptor contains all information (capabilities, attributes, etc) for an effect implementation.
+ * The client uses this information to decide when and how to apply an effect implementation.
+ *
+ * Each type of effect can have more than one implementation (differentiated by implementation
+ * UUID), the effect proxy act as a combination of two implementations (usually one software and
+ * one offload implementation), so effect processing can be seamlessly switched between
+ * implementations in same proxy depending on the configuration and/or use case. If the optional
+ * proxy UUID is specified in Descriptor.Identity, then client must consider the effect instance as
+ * part of the effect proxy.
+ */
+@VintfStability
+parcelable Descriptor {
+ /**
+ * UUID for effect types, these definitions are in sync with SDK, see @c AudioEffect.java.
+ */
+ /**
+ * UUID for environmental reverberation effect type.
+ */
+ const String EFFECT_TYPE_UUID_ENV_REVERB = "c2e5d5f0-94bd-4763-9cac-4e234d06839e";
+ /**
+ * UUID for preset reverberation effect type.
+ */
+ const String EFFECT_TYPE_UUID_PRESET_REVERB = "47382d60-ddd8-11db-bf3a-0002a5d5c51b";
+ /**
+ * UUID for equalizer effect type.
+ */
+ const String EFFECT_TYPE_UUID_EQUALIZER = "0bed4300-ddd6-11db-8f34-0002a5d5c51b";
+ /**
+ * UUID for bass boost effect type.
+ */
+ const String EFFECT_TYPE_UUID_BASS_BOOST = "0634f220-ddd4-11db-a0fc-0002a5d5c51b";
+ /**
+ * UUID for virtualizer effect type.
+ */
+ const String EFFECT_TYPE_UUID_VIRTUALIZER = "37cc2c00-dddd-11db-8577-0002a5d5c51b";
+ /**
+ * UUID for Automatic Gain Control (AGC) type.
+ */
+ const String EFFECT_TYPE_UUID_AGC = "0a8abfe0-654c-11e0-ba26-0002a5d5c51b";
+ /**
+ * UUID for Acoustic Echo Canceler (AEC) type.
+ */
+ const String EFFECT_TYPE_UUID_AEC = "7b491460-8d4d-11e0-bd61-0002a5d5c51b";
+ /**
+ * UUID for Noise Suppressor (NS) type.
+ */
+ const String EFFECT_TYPE_UUID_NS = "58b4b260-8e06-11e0-aa8e-0002a5d5c51b";
+ /**
+ * UUID for Loudness Enhancer type.
+ */
+ const String EFFECT_TYPE_UUID_LOUDNESS_ENHANCER = "fe3199be-aed0-413f-87bb-11260eb63cf1";
+ /**
+ * UUID for Dynamics Processing type.
+ */
+ const String EFFECT_TYPE_UUID_DYNAMICS_PROCESSING = "7261676f-6d75-7369-6364-28e2fd3ac39e";
+ /**
+ * UUID for Haptic Generator type.
+ */
+ const String EFFECT_TYPE_UUID_HAPTIC_GENERATOR = "1411e6d6-aecd-4021-a1cf-a6aceb0d71e5";
+ /**
+ * UUID for Spatializer type.
+ */
+ const String EFFECT_TYPE_UUID_SPATIALIZER = "ccd4cf09-a79d-46c2-9aae-06a1698d6c8f";
+ /**
+ * UUID for Volume type. The volume effect is used for automated tests only.
+ */
+ const String EFFECT_TYPE_UUID_VOLUME = "09e8ede0-ddde-11db-b4f6-0002a5d5c51b";
+
+ /**
+ * This structure completely identifies an effect implementation.
+ */
+ @VintfStability
+ parcelable Identity {
+ /**
+ * UUID for the type of effect.
+ */
+ AudioUuid type;
+ /**
+ * UUID for this particular implementation.
+ */
+ AudioUuid uuid;
+ /**
+ * Optional proxy UUID. This field must be set to the proxy effect type UUID if the effect
+ * implementation is part of a proxy effect.
+ */
+ @nullable AudioUuid proxy;
+ }
+
+ /**
+ * Common attributes of all effect implementation.
+ */
+ @VintfStability
+ parcelable Common {
+ /**
+ * Identity of effect implementation.
+ */
+ Identity id;
+ /**
+ * Capability flags defined for the effect implementation.
+ */
+ Flags flags;
+ /**
+ * CPU load indication expressed in 0.1 MIPS units as estimated on an ARM9E core (ARMv5TE)
+ * with 0 WS.
+ */
+ int cpuLoad;
+ /**
+ * Data memory usage expressed in KB and includes only dynamically allocated memory.
+ */
+ int memoryUsage;
+ /**
+ * Human readable effect name, no intended to display on UI directly.
+ */
+ @utf8InCpp String name;
+ /**
+ * Human readable effect implementor name, no intended to display on UI directly.
+ */
+ @utf8InCpp String implementor;
+ }
+ Common common;
+
+ /**
+ * Effect implementation capability.
+ */
+ Capability capability;
+}
diff --git a/audio/aidl/android/hardware/audio/effect/Downmix.aidl b/audio/aidl/android/hardware/audio/effect/Downmix.aidl
new file mode 100644
index 0000000..ee57baf
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/Downmix.aidl
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect;
+
+import android.hardware.audio.effect.VendorExtension;
+
+/**
+ * Downmix specific definitions.
+ *
+ * All parameters defined in union Downmix must be gettable and settable. The capabilities defined
+ * in Downmix.Capability can only acquired with IEffect.getDescriptor() and not settable.
+ */
+@VintfStability
+union Downmix {
+ /**
+ * Effect parameter tag to identify the parameters for getParameter().
+ */
+ @VintfStability
+ union Id {
+ int vendorExtensionTag;
+ Downmix.Tag commonTag;
+ }
+
+ /**
+ * Vendor Downmix implementation definition for additional parameters.
+ */
+ VendorExtension vendor;
+
+ /**
+ * Capability supported by Downmix implementation.
+ */
+ @VintfStability
+ parcelable Capability {
+ /**
+ * Downmix capability extension, vendor can use this extension in case existing capability
+ * definition not enough.
+ */
+ ParcelableHolder extension;
+ }
+
+ @VintfStability
+ enum Type {
+ /**
+ * Throw away the extra channels.
+ */
+ STRIP,
+ /**
+ * Mix the extra channels with FL/FR.
+ */
+ FOLD,
+ }
+
+ /**
+ * Type of downmix.
+ */
+ Type type;
+}
diff --git a/audio/aidl/android/hardware/audio/effect/DynamicsProcessing.aidl b/audio/aidl/android/hardware/audio/effect/DynamicsProcessing.aidl
new file mode 100644
index 0000000..ee5dcad
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/DynamicsProcessing.aidl
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect;
+
+import android.hardware.audio.effect.VendorExtension;
+
+/**
+ * DynamicsProcessing specific definitions.
+ *
+ * All parameters defined in union DynamicsProcessing must be gettable and settable. The
+ * capabilities defined in DynamicsProcessing.Capability can only acquired with
+ * IEffect.getDescriptor() and not settable.
+ */
+@VintfStability
+union DynamicsProcessing {
+ /**
+ * Effect parameter tag to identify the parameters for getParameter().
+ */
+ @VintfStability
+ union Id {
+ int vendorExtensionTag;
+ DynamicsProcessing.Tag commonTag;
+ }
+
+ /**
+ * Vendor DynamicsProcessing implementation definition for additional parameters.
+ */
+ VendorExtension vendorExtension;
+
+ /**
+ * Capability supported by DynamicsProcessing implementation.
+ */
+ @VintfStability
+ parcelable Capability {
+ /**
+ * DynamicsProcessing capability extension, vendor can use this extension in case existing
+ * capability definition not enough.
+ */
+ ParcelableHolder extension;
+ }
+
+ /**
+ * Resolution preference definition.
+ */
+ enum ResolutionPreference {
+ /**
+ * Favors frequency domain based implementation.
+ */
+ FAVOR_FREQUENCY_RESOLUTION,
+ /**
+ * Favors tme domain based implementation.
+ */
+ FAVOR_TIME_RESOLUTION,
+ }
+
+ /**
+ * Band enablement configuration.
+ */
+ @VintfStability
+ parcelable BandEnablement {
+ /**
+ * True if multi-band stage is in use.
+ */
+ boolean inUse;
+ /**
+ * Number of bands configured for this stage.
+ */
+ int bandCount;
+ }
+
+ /**
+ * Effect engine configuration. Set the enablement of all stages.
+ */
+ @VintfStability
+ parcelable EngineArchitecture {
+ /**
+ * Resolution preference.
+ */
+ ResolutionPreference resolutionPreference = ResolutionPreference.FAVOR_FREQUENCY_RESOLUTION;
+ /**
+ * Preferred frame duration in milliseconds (ms).
+ */
+ float preferredFrameDurationMs;
+ /**
+ * PreEq stage (Multi-band Equalizer) configuration.
+ */
+ BandEnablement preEqBand;
+ /**
+ * PostEq stage (Multi-band Equalizer) configuration.
+ */
+ BandEnablement postEqBand;
+ /**
+ * MBC stage (Multi-band Compressor) configuration.
+ */
+ BandEnablement mbcBand;
+ /**
+ * True if Limiter stage is in use.
+ */
+ boolean limiterInUse;
+ }
+
+ /**
+ * Band enablement configuration for a specific channel.
+ */
+ @VintfStability
+ parcelable BandChannelConfig {
+ /**
+ * Channel index.
+ */
+ int channel;
+ /**
+ * Channel index.
+ */
+ BandEnablement enablement;
+ }
+
+ /**
+ * Equalizer band configuration for a specific channel and band.
+ */
+ @VintfStability
+ parcelable EqBandConfig {
+ /**
+ * Channel index.
+ */
+ int channel;
+ /**
+ * Band index, must in the range of [0, bandCount-1].
+ */
+ int band;
+ /**
+ * True if EQ stage is enabled.
+ */
+ boolean enable;
+ /**
+ * Topmost frequency number (in Hz) this band will process.
+ */
+ float cutoffFrequency;
+ /**
+ * Gain factor in decibels (dB).
+ */
+ float gain;
+ }
+
+ /**
+ * MBC configuration for a specific channel and band.
+ */
+ @VintfStability
+ parcelable MbcBandConfig {
+ /**
+ * Channel index.
+ */
+ int channel;
+ /**
+ * Band index, must in the range of [0, bandCount-1].
+ */
+ int band;
+ /**
+ * True if MBC stage is enabled.
+ */
+ boolean enable;
+ /**
+ * Topmost frequency number (in Hz) this band will process.
+ */
+ float cutoffFrequencyHz;
+ /**
+ * Gain factor in decibels (dB).
+ */
+ float gainDb;
+ /**
+ * Attack Time for compressor in milliseconds (ms).
+ */
+ float attackTimeMs;
+ /**
+ * Release Time for compressor in milliseconds (ms).
+ */
+ float releaseTimeMs;
+ /**
+ * Compressor ratio (N:1) (input:output).
+ */
+ float ratio;
+ /**
+ * Compressor threshold measured in decibels (dB) from 0 dB Full Scale (dBFS).
+ */
+ float thresholdDb;
+ /**
+ * Width in decibels (dB) around compressor threshold point.
+ */
+ float kneeWidthDb;
+ /**
+ * Noise gate threshold in decibels (dB) from 0 dB Full Scale (dBFS).
+ */
+ float noiseGateThresholdDb;
+ /**
+ * Expander ratio (1:N) (input:output) for signals below the Noise Gate Threshold.
+ */
+ float expanderRatio;
+ /**
+ * Gain applied to the signal BEFORE the compression in dB.
+ */
+ float preGainDb;
+ /**
+ * Gain applied to the signal AFTER compression in dB.
+ */
+ float postGainDb;
+ }
+
+ /**
+ * Limiter configuration for a specific channel.
+ */
+ @VintfStability
+ parcelable LimiterConfig {
+ /**
+ * Channel index.
+ */
+ int channel;
+ /**
+ * True if Limiter stage is enabled.
+ */
+ boolean enable;
+ /**
+ * True if Limiter stage is in use.
+ */
+ boolean inUse;
+ /**
+ * Index of group assigned to this Limiter. Only limiters that share the same linkGroup
+ * index will react together.
+ */
+ int linkGroup;
+ /**
+ * Attack Time for compressor in milliseconds (ms).
+ */
+ float attackTimeMs;
+ /**
+ * Release Time for compressor in milliseconds (ms).
+ */
+ float releaseTimeMs;
+ /**
+ * Compressor ratio (N:1) (input:output).
+ */
+ float ratio;
+ /**
+ * Compressor threshold measured in decibels (dB) from 0 dB Full Scale (dBFS).
+ */
+ float thresholdDb;
+ /**
+ * Gain applied to the signal AFTER compression in dB.
+ */
+ float postGainDb;
+ }
+
+ /**
+ * Effect engine architecture.
+ */
+ EngineArchitecture engineArchitecture;
+ /**
+ * PreEq stage per channel configuration.
+ */
+ BandChannelConfig preEq;
+ /**
+ * PostEq stage per channel configuration.
+ */
+ BandChannelConfig postEq;
+ /**
+ * PreEq stage per band configuration.
+ */
+ EqBandConfig preEqBand;
+ /**
+ * PostEq stage per band configuration.
+ */
+ EqBandConfig postEqBand;
+ /**
+ * MBC stage per channel configuration.
+ */
+ BandChannelConfig mbc;
+ /**
+ * PostEq stage per band configuration.
+ */
+ MbcBandConfig mbcBand;
+ /**
+ * Limiter stage configuration.
+ */
+ LimiterConfig limiter;
+ /**
+ * Input gain factor in decibels (dB). 0 dB means no change in level.
+ */
+ float inputGainDb;
+}
diff --git a/audio/aidl/android/hardware/audio/effect/Equalizer.aidl b/audio/aidl/android/hardware/audio/effect/Equalizer.aidl
new file mode 100644
index 0000000..79a1c4f
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/Equalizer.aidl
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect;
+
+import android.hardware.audio.effect.VendorExtension;
+
+/**
+ * Equalizer specific definitions.
+ *
+ * All parameters defined in union Equalizer must be gettable and settable. The capabilities defined
+ * in Equalizer.Capability can only acquired with IEffect.getDescriptor() and not settable.
+ */
+@VintfStability
+union Equalizer {
+ /**
+ * Effect parameter tag to identify the parameters for getParameter().
+ */
+ @VintfStability
+ union Id {
+ int vendorExtensionTag;
+ Equalizer.Tag commonTag;
+ }
+
+ /**
+ * Vendor Equalizer implementation definition for additional parameters.
+ */
+ VendorExtension vendorExtension;
+
+ /**
+ * Capability MUST be supported by Equalizer implementation.
+ */
+ @VintfStability
+ parcelable Capability {
+ /**
+ * Equalizer capability extension, vendor can use this extension in case existing capability
+ * definition not enough.
+ */
+ ParcelableHolder extension;
+
+ /**
+ * Bands frequency ranges supported.
+ */
+ BandFrequency[] bandFrequencies;
+
+ /**
+ * Presets name and index.
+ */
+ Preset[] presets;
+ }
+
+ /**
+ * Level setting for each band in millibels.
+ */
+ @VintfStability
+ parcelable BandLevel {
+ int index;
+ int levelMb;
+ }
+
+ /**
+ * Supported minimal and maximal frequency for each band in millihertz.
+ */
+ @VintfStability
+ parcelable BandFrequency {
+ int index;
+ int minMh;
+ int maxMh;
+ }
+
+ /**
+ * Factory presets supported.
+ */
+ @VintfStability
+ parcelable Preset {
+ int index;
+ /**
+ * Preset name, used to identify presets but no intended to display on UI directly.
+ */
+ @utf8InCpp String name;
+ }
+
+ /**
+ * Level for each band.
+ */
+ BandLevel[] bandLevels;
+ /**
+ * Index of current preset.
+ */
+ int preset;
+}
diff --git a/audio/aidl/android/hardware/audio/effect/Flags.aidl b/audio/aidl/android/hardware/audio/effect/Flags.aidl
new file mode 100644
index 0000000..f449c2d
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/Flags.aidl
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect;
+
+/**
+ * Some common capability for an effect instance.
+ */
+@VintfStability
+parcelable Flags {
+ /**
+ * Type of connection.
+ */
+ @VintfStability
+ @Backing(type="byte")
+ enum Type {
+ /**
+ * After track process.
+ */
+ INSERT = 0,
+ /**
+ * Connect to track auxiliary output and use send level.
+ */
+ AUXILIARY = 1,
+ /**
+ * Rreplaces track process function; must implement SRC, volume and mono to stereo.
+ */
+ REPLACE = 2,
+ /**
+ * Applied below audio HAL on in.
+ */
+ PRE_PROC = 3,
+ /**
+ * Applied below audio HAL on out.
+ */
+ POST_PROC = 4,
+ }
+ Type type = Type.INSERT;
+
+ /**
+ * Insertion preference.
+ */
+ @VintfStability
+ @Backing(type="byte")
+ enum Insert {
+ ANY = 0,
+ /**
+ * First of the chain.
+ */
+ FIRST = 1,
+ /**
+ * Last of the chain.
+ */
+ LAST = 2,
+ /**
+ * Exclusive (only effect in the insert chain.
+ */
+ EXCLUSIVE = 3,
+ }
+ Insert insert = Insert.ANY;
+
+ @VintfStability
+ @Backing(type="byte")
+ enum Volume {
+ NONE = 0,
+ /**
+ * Implements volume control.
+ */
+ CTRL = 1,
+ /**
+ * Requires volume indication.
+ */
+ IND = 2,
+ /**
+ * Monitors requested volume.
+ */
+ MONITOR = 3,
+ }
+ Volume volume = Volume.NONE;
+
+ @VintfStability
+ @Backing(type="byte")
+ enum HardwareAccelerator {
+ /**
+ * No hardware acceleration
+ */
+ NONE = 0,
+ /**
+ * Non tunneled hw acceleration: effect reads the samples, send them to HW accelerated
+ * effect processor, reads back the processed samples and returns them to the output buffer.
+ */
+ SIMPLE = 1,
+ /**
+ * The effect interface is only used to control the effect engine. This mode is relevant for
+ * global effects actually applied by the audio hardware on the output stream.
+ */
+ TUNNEL = 2,
+ }
+ HardwareAccelerator hwAcceleratorMode = HardwareAccelerator.NONE;
+
+ /**
+ * Effect instance set this flag to true if it requires update on if the playback thread the
+ * effect attached to is offloaded or not. In this case the framework must call
+ * IEffect.setParameter(Parameter.offload) to notify effect instance when playback thread
+ * offload changes.
+ */
+ boolean offloadIndication;
+
+ /**
+ * Effect instance set this flag to true if it requires device change update. In this case the
+ * framework must call IEffect.setParameter(Parameter.device) to notify effect instance when the
+ * device changes.
+ */
+ boolean deviceIndication;
+
+ /**
+ * Effect instance set this flag to true if it requires audio mode change update. In this case
+ * the framework must call IEffect.setParameter(Parameter.mode) to notify effect instance when
+ * the audio mode changes.
+ */
+ boolean audioModeIndication;
+
+ /**
+ * Effect instance set this flag to true if it requires audio source change update. In this case
+ * the framework must call IEffect.setParameter(Parameter.source) to notify effect instance when
+ * the audio source changes.
+ */
+ boolean audioSourceIndication;
+
+ /**
+ * Set to true if no processing done for this effect instance.
+ */
+ boolean noProcessing;
+}
diff --git a/audio/aidl/android/hardware/audio/effect/HapticGenerator.aidl b/audio/aidl/android/hardware/audio/effect/HapticGenerator.aidl
new file mode 100644
index 0000000..944155f
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/HapticGenerator.aidl
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect;
+
+import android.hardware.audio.effect.VendorExtension;
+
+/**
+ * HapticGenerator specific definitions. HapticGenerator effect provide HapticGenerator control and
+ * mute/unmute functionality.
+ *
+ * All parameters defined in union HapticGenerator must be gettable and settable. The capabilities
+ * defined in HapticGenerator.Capability can only acquired with IEffect.getDescriptor() and not
+ * settable.
+ */
+@VintfStability
+union HapticGenerator {
+ /**
+ * Effect parameter tag to identify the parameters for getParameter().
+ */
+ @VintfStability
+ union Id {
+ int vendorExtensionTag;
+ HapticGenerator.Tag commonTag;
+ }
+
+ /**
+ * Vendor HapticGenerator implementation definition for additional parameters.
+ */
+ VendorExtension vendorExtension;
+
+ /**
+ * Capability supported by HapticGenerator implementation.
+ */
+ @VintfStability
+ parcelable Capability {
+ /**
+ * HapticGenerator capability extension, vendor can use this extension in case existing
+ * capability definition not enough.
+ */
+ VendorExtension extension;
+ }
+
+ @VintfStability
+ @Backing(type="int")
+ enum VibratorScale {
+ MUTE = -100,
+ VERY_LOW = -2,
+ LOW = -1,
+ NONE = 0,
+ HIGH = 1,
+ VERY_HIGH = 2,
+ }
+
+ @VintfStability
+ parcelable HapticScale {
+ /**
+ * Audio track ID.
+ */
+ int id;
+ /**
+ * Haptic intensity.
+ */
+ VibratorScale scale = VibratorScale.MUTE;
+ }
+
+ /**
+ * Vibrator information including resonant frequency, Q factor.
+ */
+ @VintfStability
+ parcelable VibratorInformation {
+ /**
+ * Resonant frequency in Hz.
+ */
+ float resonantFrequencyHz;
+ float qFactor;
+ float maxAmplitude;
+ }
+
+ HapticScale hapticScale;
+ VibratorInformation vibratorInfo;
+}
diff --git a/audio/aidl/android/hardware/audio/effect/IEffect.aidl b/audio/aidl/android/hardware/audio/effect/IEffect.aidl
new file mode 100644
index 0000000..3b957d7
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/IEffect.aidl
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect;
+
+import android.hardware.audio.effect.CommandId;
+import android.hardware.audio.effect.Descriptor;
+import android.hardware.audio.effect.Parameter;
+import android.hardware.audio.effect.State;
+import android.hardware.common.fmq.MQDescriptor;
+import android.hardware.common.fmq.SynchronizedReadWrite;
+
+/**
+ * Effect interfaces definitions to configure and control the effect instance.
+ */
+@VintfStability
+interface IEffect {
+ @VintfStability
+ @FixedSize
+ parcelable Status {
+ /**
+ * One of Binder STATUS_* statuses:
+ * - STATUS_OK: the command has completed successfully;
+ * - STATUS_BAD_VALUE: invalid value in the 'Command' structure;
+ * - STATUS_INVALID_OPERATION: the mix port is not connected
+ * to any producer or consumer, thus
+ * positions can not be reported;
+ * - STATUS_NOT_ENOUGH_DATA: a read or write error has
+ * occurred for the 'audio.fmq' queue;
+ *
+ */
+ int status;
+ /**
+ * The amount of audio data samples in the floating point format consumed by the effect
+ * instance.
+ */
+ int fmqConsumed;
+ /**
+ * The amount of audio data samples in the floating point format produced by the effect
+ * instance.
+ */
+ int fmqProduced;
+ }
+
+ /**
+ * Return data structure of IEffect.open() interface.
+ */
+ @VintfStability
+ parcelable OpenEffectReturn {
+ /**
+ * Message queue for effect processing status.
+ */
+ MQDescriptor<Status, SynchronizedReadWrite> statusMQ;
+ /**
+ * Message queue for input data buffer.
+ */
+ MQDescriptor<float, SynchronizedReadWrite> inputDataMQ;
+ /**
+ * Message queue for output data buffer.
+ */
+ MQDescriptor<float, SynchronizedReadWrite> outputDataMQ;
+ }
+
+ /**
+ * Open an effect instance, effect must not start processing data before receive
+ * CommandId::START command. All necessary information should be allocated and instance must
+ * transfer to State::IDLE state after open() call has been handled successfully. After open,
+ * the effect instance must be able to handle all IEffect interface calls.
+ *
+ * @param common Parameters which MUST pass from client at open time.
+ * @param specific Effect specific parameters which can optional pass from client at open time.
+ *
+ * @throws EX_ILLEGAL_ARGUMENT if the effect instance receive unsupported command.
+ * @throws a EX_UNSUPPORTED_OPERATION if device capability/resource is not enough or system
+ * failure happens.
+ * @note Open an already-opened effect instance should do nothing and should not throw an error.
+ */
+ OpenEffectReturn open(
+ in Parameter.Common common, in @nullable Parameter.Specific specific);
+
+ /**
+ * Called by the client to close the effect instance, processing thread should be destroyed and
+ * consume no CPU after close.
+ *
+ * It is recommended to close the effect on the client side as soon as it becomes unused, it's
+ * client responsibility to make sure all parameter/buffer is correct if client wants to reopen
+ * a closed instance.
+ *
+ * Effect instance close interface should always succeed unless:
+ * 1. The effect instance is not in a proper state to be closed, for example it's still in
+ * State::PROCESSING state.
+ * 2. There is system/hardware related failure when close.
+ *
+ * @throws EX_ILLEGAL_STATE if the effect instance is not in a proper state to be closed.
+ * @throws EX_UNSUPPORTED_OPERATION if the effect instance failed to close for any other reason.
+ * @note Close an already-closed effect should do nothing and should not throw an error.
+ */
+ void close();
+
+ /**
+ * Return the @c Descriptor of this effect instance.
+ *
+ * Must be available for the effect instance at anytime and should always succeed.
+ *
+ * @return Descriptor The @c Descriptor of this effect instance.
+ */
+ Descriptor getDescriptor();
+
+ /**
+ * Send a command (defined in enum CommandId) to the effect instance, instance state can be
+ * changed as result of command handling.
+ *
+ * Must be available for the effect instance after it has been open().
+ *
+ * @param commandId ID of the command send to the effect instance.
+ *
+ * @throws EX_ILLEGAL_STATE if the effect instance is not in a proper state to handle the
+ * command.
+ * @throws EX_ILLEGAL_ARGUMENT if the effect instance receive unsupported command.
+ */
+ void command(in CommandId commandId);
+
+ /**
+ * Get current state of the effect instance.
+ *
+ * Must be available for the effect instance at anytime and should always succeed.
+ *
+ * @return Current effect instance state.
+ */
+ State getState();
+
+ /**
+ * Set a parameter to the effect instance.
+ *
+ * Must be available for the effect instance after open().
+ *
+ * @param param Parameter data to set to the effect instance.
+ *
+ * @throws EX_ILLEGAL_ARGUMENT if the effect instance receive unsupported parameter.
+ */
+ void setParameter(in Parameter param);
+
+ /**
+ * Get a parameter from the effect instance with parameter ID.
+ *
+ * This interface must return the current parameter of the effect instance, if no parameter
+ * has been set by client yet, the default value must be returned.
+ *
+ * Must be available for the effect instance after open().
+ *
+ * @param paramId The tag enum of parameter to get.
+ * @return Parameter The parameter to get from the effect instance.
+ *
+ * @throws EX_ILLEGAL_ARGUMENT if the effect instance receive unsupported parameter tag.
+ */
+ Parameter getParameter(in Parameter.Id paramId);
+}
diff --git a/audio/aidl/android/hardware/audio/effect/IFactory.aidl b/audio/aidl/android/hardware/audio/effect/IFactory.aidl
new file mode 100644
index 0000000..5943359
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/IFactory.aidl
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect;
+
+import android.hardware.audio.effect.Descriptor;
+import android.hardware.audio.effect.IEffect;
+import android.hardware.audio.effect.Processing;
+import android.media.audio.common.AudioUuid;
+
+/**
+ * Provides system-wide effect factory interfaces.
+ *
+ * An android.hardware.audio.effect.IFactory platform service is registered with ServiceManager, and
+ * is always available on the device.
+ *
+ */
+@VintfStability
+interface IFactory {
+ /**
+ * Return a list of effect identities supported by this device, with the optional
+ * filter by type and/or by instance UUID.
+ *
+ * @param type UUID identifying the effect type.
+ * This is an optional parameter, pass in null if this parameter is not necessary; if non
+ * null, used as a filter for effect type UUIDs.
+ * @param implementation Indicates the particular implementation of the effect in that type.
+ * This is an optional parameter, pass in null if this parameter is not necessary; if
+ * non null, used as a filter for effect implementation UUIDs.
+ * @param proxy Indicates the proxy UUID filter to query.
+ * This is an optional parameter, pass in null if this parameter is not necessary; if
+ * non null, used as a filter for effect proxy UUIDs.
+ * @return List of effect identities supported and filtered by type/implementation UUID.
+ */
+ Descriptor.Identity[] queryEffects(in @nullable AudioUuid type,
+ in @nullable AudioUuid implementation, in @nullable AudioUuid proxy);
+
+ /**
+ * Return a list of defined processings, with the optional filter by Processing type.
+ * An effect can exist more than once in the returned list, which means this effect must be used
+ * in more than one processing type.
+ *
+ * @param type Type of processing to query, can be AudioStreamType, AudioSource, or null.
+ * @return list of processing defined with the optional filter by Processing.Type.
+ */
+ Processing[] queryProcessing(in @nullable Processing.Type type);
+
+ /**
+ * Called by the audio framework to create the effect (identified by the implementation UUID
+ * parameter).
+ *
+ * The effect instance should be able to maintain its own context and parameters after creation.
+ *
+ * @param implUuid UUID for the effect implementation which instance will be created based on.
+ * @return The effect instance handle created.
+ * @throws EX_ILLEGAL_ARGUMENT if the implUuid is not valid.
+ * @throws EX_TRANSACTION_FAILED if device capability/resource is not enough to create the
+ * effect instance.
+ */
+ IEffect createEffect(in AudioUuid implUuid);
+
+ /**
+ * Called by the framework to destroy the effect and free up all currently allocated resources.
+ * It is recommended to destroy the effect from the client side as soon as it is becomes unused.
+ *
+ * The client must ensure effect instance is closed before destroy.
+ *
+ * @param handle The handle of effect instance to be destroyed.
+ * @throws EX_ILLEGAL_ARGUMENT if the effect handle is not valid.
+ * @throws EX_ILLEGAL_STATE if the effect instance is not in a proper state to be destroyed.
+ */
+ void destroyEffect(in IEffect handle);
+}
diff --git a/audio/aidl/android/hardware/audio/effect/LoudnessEnhancer.aidl b/audio/aidl/android/hardware/audio/effect/LoudnessEnhancer.aidl
new file mode 100644
index 0000000..0441f10
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/LoudnessEnhancer.aidl
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect;
+
+import android.hardware.audio.effect.VendorExtension;
+
+/**
+ * LoudnessEnhancer specific definitions.
+ *
+ * All parameters defined in union LoudnessEnhancer must be gettable and settable. The capabilities
+ * defined in LoudnessEnhancer.Capability can only acquired with IEffect.getDescriptor() and not
+ * settable.
+ */
+@VintfStability
+union LoudnessEnhancer {
+ /**
+ * Effect parameter tag to identify the parameters for getParameter().
+ */
+ @VintfStability
+ union Id {
+ int vendorExtensionTag;
+ LoudnessEnhancer.Tag commonTag;
+ }
+
+ /**
+ * Vendor LoudnessEnhancer implementation definition for additional parameters.
+ */
+ VendorExtension vendor;
+
+ /**
+ * Capability supported by LoudnessEnhancer implementation.
+ */
+ @VintfStability
+ parcelable Capability {
+ /**
+ * LoudnessEnhancer capability extension, vendor can use this extension in case existing
+ * capability definition not enough.
+ */
+ VendorExtension extension;
+ }
+
+ /**
+ * The maximum gain in millibels (mB) applied to the signal to process, default value is 0 which
+ * corresponds to no amplification.
+ */
+ int gainMb;
+}
diff --git a/audio/aidl/android/hardware/audio/effect/Parameter.aidl b/audio/aidl/android/hardware/audio/effect/Parameter.aidl
new file mode 100644
index 0000000..e7d3d5e
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/Parameter.aidl
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect;
+
+import android.hardware.audio.effect.BassBoost;
+import android.hardware.audio.effect.Downmix;
+import android.hardware.audio.effect.DynamicsProcessing;
+import android.hardware.audio.effect.Equalizer;
+import android.hardware.audio.effect.HapticGenerator;
+import android.hardware.audio.effect.LoudnessEnhancer;
+import android.hardware.audio.effect.Reverb;
+import android.hardware.audio.effect.VendorExtension;
+import android.hardware.audio.effect.Virtualizer;
+import android.hardware.audio.effect.Visualizer;
+import android.hardware.audio.effect.Volume;
+import android.media.audio.common.AudioConfig;
+import android.media.audio.common.AudioDeviceDescription;
+import android.media.audio.common.AudioMode;
+import android.media.audio.common.AudioSource;
+
+/**
+ * Defines all parameters supported by the effect instance.
+ *
+ * There are three groups of parameters:
+ * 1. Common parameters are essential parameters, MUST pass to effects at open() interface.
+ * 2. Parameters defined for a specific effect type.
+ * 3. Extension parameters ParcelableHolder can be used for vendor effect definition.
+ *
+ */
+@VintfStability
+union Parameter {
+ /**
+ * Client can pass in Parameter.Id with the corresponding tag value in IEffect.getParameter()
+ * call to get android.hardware.audio.effect.Parameter.
+ *
+ * As an example, if a client want to get audio.hardware.audio.effect.Specific.Equalizer, the
+ * value of Id should be audio.hardware.audio.effect.Parameter.Specific.equalizer.
+ */
+ @VintfStability
+ union Id {
+ /**
+ * Parameter tag defined for vendor effects. Use int here so there is flexibility for vendor
+ * to define different tag.
+ */
+ int vendorEffectTag;
+ /**
+ * Parameter tag defined for nested parameters. Can be used to get any parameter defined in
+ * nested Union structure.
+ *
+ * Example:
+ * To get BassBoost strength in param from effectInstance:
+ * IEffect effectInstance;
+ * Parameter param;
+ * BassBoost::Id bassId = BassBoost::Id::make<BassBoost::Id::tag>(BassBoost::strengthPm);
+ * Parameter::Id id = Parameter::Id::make<Parameter::Id::bassBoostTag>(bassId);
+ * effectInstance.getParameter(id, ¶m);
+ *
+ */
+ BassBoost.Id bassBoostTag;
+ Downmix.Id downmixTag;
+ DynamicsProcessing.Id dynamicsProcessingTag;
+ Equalizer.Id equalizerTag;
+ HapticGenerator.Id hapticGeneratorTag;
+ LoudnessEnhancer.Id loudnessEnhancerTag;
+ Reverb.Id reverbTag;
+ Virtualizer.Id virtualizerTag;
+ Visualizer.Id visualizerTag;
+ Volume.Id volumeTag;
+ /**
+ * Non-nested parameter tag. Can be used to get any parameter defined in Union Parameter
+ * directly.
+ */
+ Parameter.Tag commonTag;
+ }
+
+ /**
+ * Common parameters MUST be supported by all effect implementations.
+ */
+ @VintfStability
+ parcelable Common {
+ /**
+ * Type of Audio device.
+ */
+ int session;
+ /**
+ * I/O Handle.
+ */
+ int ioHandle;
+ /**
+ * Input config.
+ */
+ AudioConfig input;
+ /**
+ * Output config.
+ */
+ AudioConfig output;
+ }
+ Common common;
+
+ /**
+ * Used by audio framework to set the device type to effect engine.
+ * Effect must implement setParameter(device) if Flags.deviceIndication set to true.
+ */
+ AudioDeviceDescription deviceDescription;
+ /**
+ * Used by audio framework to set the audio mode to effect engine.
+ * Effect must implement setParameter(mode) if Flags.audioModeIndication set to true.
+ */
+ AudioMode mode;
+ /**
+ * Used by audio framework to set the audio source to effect engine.
+ * Effect must implement setParameter(source) if Flags.audioSourceIndication set to true.
+ */
+ AudioSource source;
+
+ /**
+ * The volume gain for left and right channel, left and right equals to same value if it's mono.
+ */
+ @VintfStability
+ parcelable VolumeStereo {
+ float left;
+ float right;
+ }
+ /**
+ * Used by audio framework to delegate volume control to effect engine.
+ * Effect must implement setParameter(volume) if Flags.volume set to Volume.IND.
+ */
+ VolumeStereo volumeStereo;
+
+ /**
+ * Parameters MUST be supported by a Specific type of effect.
+ */
+ @VintfStability
+ union Specific {
+ VendorExtension vendorEffect;
+ BassBoost bassBoost;
+ Downmix downmix;
+ DynamicsProcessing dynamicsProcessing;
+ Equalizer equalizer;
+ LoudnessEnhancer loudnessEnhancer;
+ HapticGenerator hapticGenerator;
+ Reverb reverb;
+ Virtualizer virtualizer;
+ Visualizer visualizer;
+ Volume volume;
+ }
+ Specific specific;
+}
diff --git a/audio/aidl/android/hardware/audio/effect/Processing.aidl b/audio/aidl/android/hardware/audio/effect/Processing.aidl
new file mode 100644
index 0000000..ef32e8c
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/Processing.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect;
+
+import android.hardware.audio.effect.Descriptor;
+import android.media.audio.common.AudioSource;
+import android.media.audio.common.AudioStreamType;
+import android.media.audio.common.AudioUuid;
+
+/**
+ * List of effects which must be used for certain pre-processing or post-processing.
+ */
+@VintfStability
+parcelable Processing {
+ @VintfStability
+ union Type {
+ AudioStreamType streamType = AudioStreamType.INVALID;
+ AudioSource source;
+ }
+
+ /**
+ * Specifies the type of processing by referring to the output stream type (AudioStreamType) or
+ * the input stream source (AudioSource).
+ */
+ Type type;
+ /**
+ * List of effect identities for this processing.
+ */
+ Descriptor.Identity[] ids;
+}
diff --git a/audio/aidl/android/hardware/audio/effect/Reverb.aidl b/audio/aidl/android/hardware/audio/effect/Reverb.aidl
new file mode 100644
index 0000000..f60c2ea
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/Reverb.aidl
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect;
+
+import android.hardware.audio.effect.VendorExtension;
+
+/**
+ * Reverb specific definitions.
+ *
+ * All parameters defined in union Reverb must be gettable and settable. The capabilities defined in
+ * Reverb.Capability can only acquired with IEffect.getDescriptor() and not settable.
+ */
+@VintfStability
+union Reverb {
+ /**
+ * Effect parameter tag to identify the parameters for getParameter().
+ */
+ @VintfStability
+ union Id {
+ int vendorExtensionTag;
+ Reverb.Tag commonTag;
+ }
+
+ /**
+ * Vendor Reverb implementation definition for additional parameters.
+ */
+ VendorExtension vendor;
+
+ /**
+ * Capability supported by effect implementation.
+ */
+ @VintfStability
+ parcelable Capability {
+ VendorExtension extension;
+
+ /**
+ * Max decay time supported in millisecond.
+ */
+ int maxDecayTimeMs;
+ }
+
+ /**
+ * Room level apply to the reverb effect in millibels.
+ */
+ int roomLevelMb;
+ /**
+ * Room HF level apply to the reverb effect in millibels.
+ */
+ int roomHfLevelMb;
+ /**
+ * Delay time apply to the reverb effect in milliseconds.
+ */
+ int decayTimeMs;
+ /**
+ * HF decay ratio in permilles.
+ */
+ int decayHfRatioPm;
+ /**
+ * Reverb level in millibels.
+ */
+ int levelMb;
+ /**
+ * Reverb delay in milliseconds.
+ */
+ int delayMs;
+ /**
+ * Diffusion in permilles.
+ */
+ int diffusionPm;
+ /**
+ * Density in permilles.
+ */
+ int densityPm;
+ /**
+ * Bypass reverb and copy input to output if set to true.
+ */
+ boolean bypass;
+}
diff --git a/audio/aidl/android/hardware/audio/effect/State.aidl b/audio/aidl/android/hardware/audio/effect/State.aidl
new file mode 100644
index 0000000..85a4afc
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/State.aidl
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect;
+
+/**
+ * Possible states of an effect instance.
+ * A typical effect instance will be in INIT state when it is created with IFactory.createEffect()
+ * interface, transfer to IDLE after open(), and to PROCESSING after
+ * IEffect.command(Command.Id.START) command. When an effect instance receive STOP or RESET command,
+ * it should transfer to IDLE state after handle the command successfully. Effect instance should
+ * consume minimal resource and transfer to INIT state after it was close().
+ *
+ * Refer to State.gv for detailed state diagram.
+ */
+@VintfStability
+@Backing(type="byte")
+enum State {
+
+ /**
+ * An effect instance is in INIT state by default after it was created with
+ * IFactory.createEffect(). When an effect instance is in INIT state, it should have instance
+ * context initialized, and ready to handle IEffect.setParameter(), IEffect.open() as well as
+ * all getter interfaces.
+ *
+ * In INIT state, effect instance must:
+ * 1. Not handle any IEffect.command() and return EX_ILLEGAL_STATE with any Command.Id.
+ * 2. Be able to handle all parameter setting with IEffect.setParameter().
+ * 3. Be able to handle all getter interface calls like IEffect.getParameter() and
+ * IEffect.getState().
+ * 4. Be able to handle IEffect.open() successfully after configuration.
+ *
+ * Client is expected to do necessary configuration with IEffect.setParameter(), get all
+ * resource ready with IEffect.open(), and make sure effect instance transfer to IDLE state
+ * before sending commands with IEffect.command() interface. Effect instance must transfer
+ * from INIT to IDLE state after handle IEffect.open() call successfully.
+ */
+ INIT,
+ /**
+ * An effect instance transfer to IDLE state after it was open successfully with IEffect.open()
+ * in INIT state, or after it was stop/reset with Command.Id.STOP/RESET in PROCESSING state.
+ *
+ * In IDLE state, effect instance must:
+ * 1. Be able to start effect processing engine with IEffect.command(Command.Id.START) call.
+ * 2. Be able to handle all parameter setting with IEffect.setParameter().
+ * 3. Be able to handle all getter interface calls like IEffect.getParameter() and
+ * IEffect.getState().
+ *
+ * The following state transfer can happen in IDLE state:
+ * 1. Transfer to PROCESSING if instance receive an START command and start processing data
+ * successfully.
+ * 2. Transfer to INIT if instance receive a close() call.
+ */
+ IDLE,
+ /**
+ * An effect instance is in PROCESSING state after it receive an START command and start
+ * processing data successfully. Effect instance will transfer from PROCESSING to IDLE state if
+ * it receive an STOP or RESET command and handle the command successfully.
+ *
+ * When an instance is in PROCESSING state, client should try not to close() it directly,
+ * instead client should try to stop processing data first with STOP command before close(). In
+ * the case of a close() call received when instance in PROCESSING state, it should try to stop
+ * processing and transfer to IDLE first before close().
+ *
+ * In PROCESSING state, effect instance must:
+ * 1. Return EX_ILLEGAL_STATE if it's not able to handle any parameter settings at runtime.
+ * 2. Be able to handle STOP and RESET for IEffect.command() interface, and return
+ * EX_ILLEGAL_STATE for all other commands.
+ * 3. Must be able to handle all get* interface calls like IEffect.getParameter() and
+ * IEffect.getState().
+ */
+ PROCESSING,
+}
diff --git a/audio/aidl/android/hardware/audio/effect/VendorExtension.aidl b/audio/aidl/android/hardware/audio/effect/VendorExtension.aidl
new file mode 100644
index 0000000..c60f01a
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/VendorExtension.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect;
+
+/**
+ * Vendor exntension implementation definition, can be used for additional parameters.
+ */
+@VintfStability
+parcelable VendorExtension {
+ ParcelableHolder extension;
+}
diff --git a/audio/aidl/android/hardware/audio/effect/Virtualizer.aidl b/audio/aidl/android/hardware/audio/effect/Virtualizer.aidl
new file mode 100644
index 0000000..9d039bc
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/Virtualizer.aidl
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect;
+
+import android.hardware.audio.effect.VendorExtension;
+
+/**
+ * Virtualizer specific definitions. An audio virtualizer is a general name for an effect to
+ * spatialize audio channels.
+ *
+ * All parameters defined in union Virtualizer must be gettable and settable. The capabilities
+ * defined in Virtualizer.Capability can only acquired with IEffect.getDescriptor() and not
+ * settable.
+ */
+@VintfStability
+union Virtualizer {
+ /**
+ * Effect parameter tag to identify the parameters for getParameter().
+ */
+ @VintfStability
+ union Id {
+ int vendorExtensionTag;
+ Virtualizer.Tag commonTag;
+ }
+
+ /**
+ * Vendor Virtualizer implementation definition for additional parameters.
+ */
+ VendorExtension vendor;
+
+ /**
+ * Capability supported by Virtualizer implementation.
+ */
+ @VintfStability
+ parcelable Capability {
+ /**
+ * Virtualizer capability extension, vendor can use this extension in case existing
+ * capability definition not enough.
+ */
+ VendorExtension extension;
+ /**
+ * Indicates whether setting strength is supported. False value indicates only one strength
+ * is supported and setParameter() method will always return EX_ILLEGAL_ARGUMENT.
+ */
+ boolean strengthSupported;
+ }
+
+ /**
+ * The per mille strength of the virtualizer effect.
+ *
+ * If the implementation does not support per mille accuracy for setting the strength, it is
+ * allowed to round the given strength to the nearest supported value. In this case {@link
+ * #IEffect.getParameter()} method should return the rounded value that was actually set.
+ *
+ * The valid range for strength is [0, 1000].
+ */
+ int strengthPm;
+}
diff --git a/audio/aidl/android/hardware/audio/effect/Visualizer.aidl b/audio/aidl/android/hardware/audio/effect/Visualizer.aidl
new file mode 100644
index 0000000..4c1b71a
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/Visualizer.aidl
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect;
+
+import android.hardware.audio.effect.VendorExtension;
+
+/**
+ * Visualizer specific definitions. Visualizer enables application to retrieve part of the currently
+ * playing audio for visualization purpose
+ *
+ * All parameters defined in union Visualizer other than these in GetOnlyParameters and
+ * SetOnlyParameters must be gettable and settable. The capabilities defined in
+ * Visualizer.Capability can only acquired with IEffect.getDescriptor() and not settable.
+ *
+ */
+@VintfStability
+union Visualizer {
+ /**
+ * Effect parameter tag to identify the parameters for getParameter().
+ */
+ @VintfStability
+ union Id {
+ int vendorExtensionTag;
+ GetOnlyParameters.Tag getOnlyParamTag;
+ SetOnlyParameters.Tag setOnlyParamTag;
+ Visualizer.Tag commonTag;
+ }
+ Id id;
+
+ /**
+ * Vendor Visualizer implementation definition for additional parameters.
+ */
+ VendorExtension vendor;
+
+ /**
+ * Capability supported by Visualizer implementation.
+ */
+ @VintfStability
+ parcelable Capability {
+ /**
+ * Visualizer capability extension, vendor can use this extension in case existing
+ * capability definition not enough.
+ */
+ VendorExtension extension;
+ /**
+ * Max latency supported in millseconds.
+ */
+ int maxLatencyMs;
+ /**
+ * Capture size range.
+ */
+ CaptureSizeRange captureSizeRange;
+ }
+
+ /**
+ * Supported capture size range in bytes.
+ */
+ @VintfStability
+ parcelable CaptureSizeRange {
+ int minBytes;
+ int maxBytes;
+ }
+
+ /**
+ * Type of scaling applied on the captured visualization data.
+ */
+ @VintfStability
+ enum ScalingMode {
+ /**
+ * Defines a capture mode where amplification is applied based on the content of the
+ * captured data. This is the default Visualizer mode, and is suitable for music
+ * visualization.
+ */
+ NORMALIZED = 0,
+ /**
+ * Defines a capture mode where the playback volume will affect (scale) the range of the
+ * captured data. A low playback volume will lead to low sample and fft values, and
+ * vice-versa.
+ */
+ AS_PLAYED,
+ }
+
+ /**
+ * Measurement modes to be performed.
+ */
+ @VintfStability
+ enum MeasurementMode {
+ /**
+ * No measurements are performed.
+ */
+ NONE = 0,
+ /**
+ * Defines a measurement mode which computes the peak and RMS value in mB below the "full
+ * scale", where 0mB is normally the maximum sample value (but see the note below). Minimum
+ * value depends on the resolution of audio samples used by the audio framework. The value
+ * of -9600mB is the minimum value for 16-bit audio systems and -14400mB or below for "high
+ * resolution" systems. Values for peak and RMS can be retrieved with {@link
+ * #getMeasurementPeakRms(MeasurementPeakRms)}.
+ */
+ PEAK_RMS,
+ }
+
+ /**
+ * Any parameter defined in this union must be gettable via getParameter(), but must not
+ * settable.
+ */
+ @VintfStability
+ union GetOnlyParameters {
+ /**
+ * Get the current measurements.
+ */
+ @VintfStability
+ parcelable Measurement {
+ int rms;
+ int peak;
+ }
+ Measurement measurement;
+
+ /**
+ * Gets the latest PCM capture, size of returned vector equals to @c captureSize.
+ */
+ byte[] captureBytes;
+ }
+ GetOnlyParameters getOnlyParameters;
+
+ /**
+ * Any parameter defined in this union must be settable via setParameter(), but must not
+ * gettable.
+ */
+ @VintfStability
+ union SetOnlyParameters {
+ /**
+ * Used by framework to inform the visualizer about the downstream latency (audio hardware
+ * driver estimated latency in milliseconds).
+ */
+ int latencyMs;
+ }
+ SetOnlyParameters setOnlyParameters;
+
+ /**
+ * Current capture size in bytes. The capture size must be a power of 2 in the range
+ * Capability.captureSizeRange.
+ */
+ int captureSizeBytes;
+ /**
+ * Visualizer capture mode
+ */
+ ScalingMode scalingMode;
+ /**
+ * Visualizer measurement mode.
+ */
+ MeasurementMode measurementMode;
+}
diff --git a/audio/aidl/android/hardware/audio/effect/Volume.aidl b/audio/aidl/android/hardware/audio/effect/Volume.aidl
new file mode 100644
index 0000000..a3ce2f6
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/Volume.aidl
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect;
+
+import android.hardware.audio.effect.VendorExtension;
+
+/**
+ * Volume specific definitions. Volume effect provide volume control and mute/unmute functionality.
+ *
+ * All parameters defined in union Volume must be gettable and settable. The capabilities defined in
+ * Volume.Capability can only acquired with IEffect.getDescriptor() and not settable.
+ */
+@VintfStability
+union Volume {
+ /**
+ * Effect parameter tag to identify the parameters for getParameter().
+ */
+ @VintfStability
+ union Id {
+ int vendorExtensionTag;
+ Volume.Tag commonTag;
+ }
+
+ /**
+ * Vendor Volume implementation definition for additional parameters.
+ */
+ VendorExtension vendor;
+
+ /**
+ * Capability supported by Volume implementation.
+ */
+ @VintfStability
+ parcelable Capability {
+ /**
+ * Volume capability extension, vendor can use this extension in case existing capability
+ * definition not enough.
+ */
+ VendorExtension extension;
+
+ /**
+ * Volume strength supported in dB.
+ */
+ int maxLevel;
+ }
+
+ /**
+ * Current level in dB.
+ */
+ int levelDb;
+ /**
+ * Mute volume if true, when volume set to mute, the current level still saved and take effect
+ * when unmute.
+ */
+ boolean mute;
+}
diff --git a/audio/aidl/android/hardware/audio/effect/state.gv b/audio/aidl/android/hardware/audio/effect/state.gv
new file mode 100644
index 0000000..e19e6c7
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/state.gv
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// To render: "dot -Tpng state.gv -o state.png"
+digraph effect_state_machine {
+ node [shape=point style=filled fillcolor=black width=0.5] I;
+ node [shape=doublecircle] F;
+ node [shape=oval width=1];
+ node [fillcolor=lightgreen] INIT;
+ node [fillcolor=lightblue] IDLE;
+ node [fillcolor=lightyellow] PROCESSING;
+
+ I -> INIT [label="IFactory.createEffect" labelfontcolor="navy"];
+ INIT -> F [label="IFactory.destroyEffect"];
+ INIT -> IDLE [label="open()" labelfontcolor="lime"];
+ IDLE -> PROCESSING [label="command(START"];
+ PROCESSING -> IDLE [label="command(STOP)\ncommand(RESET)"];
+ IDLE -> INIT [label="close()"];
+
+ INIT -> INIT [label="getState\ngetDescriptor"];
+ IDLE -> IDLE [label="getXXX\nsetParameter\ncommand(RESET)"];
+ PROCESSING -> PROCESSING [label="getXXX\nsetParameter"];
+}
\ No newline at end of file
diff --git a/audio/aidl/common/Android.bp b/audio/aidl/common/Android.bp
new file mode 100644
index 0000000..a3f7f0b
--- /dev/null
+++ b/audio/aidl/common/Android.bp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library {
+ name: "libaudioaidlcommon",
+ host_supported: true,
+ vendor_available: true,
+ export_include_dirs: ["include"],
+ header_libs: [
+ "libbase_headers",
+ "libsystem_headers",
+ ],
+ export_header_lib_headers: [
+ "libbase_headers",
+ "libsystem_headers",
+ ],
+ srcs: [
+ "StreamWorker.cpp",
+ ],
+}
+
+cc_test {
+ name: "libaudioaidlcommon_test",
+ host_supported: true,
+ vendor_available: true,
+ static_libs: [
+ "android.media.audio.common.types-V1-ndk",
+ "libaudioaidlcommon",
+ ],
+ shared_libs: [
+ "liblog",
+ ],
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-Wthread-safety",
+ ],
+ srcs: [
+ "tests/streamworker_tests.cpp",
+ "tests/utils_tests.cpp",
+ ],
+ test_suites: [
+ "general-tests",
+ ],
+}
diff --git a/audio/aidl/common/StreamWorker.cpp b/audio/aidl/common/StreamWorker.cpp
new file mode 100644
index 0000000..0d2121c
--- /dev/null
+++ b/audio/aidl/common/StreamWorker.cpp
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <pthread.h>
+#include <sched.h>
+#include <sys/resource.h>
+
+#include "include/StreamWorker.h"
+
+namespace android::hardware::audio::common::internal {
+
+bool ThreadController::start(const std::string& name, int priority) {
+ mThreadName = name;
+ mThreadPriority = priority;
+ if (kTestSingleThread != name) {
+ mWorker = std::thread(&ThreadController::workerThread, this);
+ } else {
+ // Simulate the case when the workerThread completes prior
+ // to the moment when we being waiting for its start.
+ workerThread();
+ }
+ std::unique_lock<std::mutex> lock(mWorkerLock);
+ android::base::ScopedLockAssertion lock_assertion(mWorkerLock);
+ mWorkerCv.wait(lock, [&]() {
+ android::base::ScopedLockAssertion lock_assertion(mWorkerLock);
+ return mWorkerState != WorkerState::INITIAL || !mError.empty();
+ });
+ return mError.empty();
+}
+
+void ThreadController::stop() {
+ {
+ std::lock_guard<std::mutex> lock(mWorkerLock);
+ if (mWorkerState != WorkerState::STOPPED) {
+ mWorkerState = WorkerState::STOPPED;
+ mWorkerStateChangeRequest = true;
+ }
+ }
+ join();
+}
+
+void ThreadController::join() {
+ if (mWorker.joinable()) {
+ mWorker.join();
+ }
+}
+
+bool ThreadController::waitForAtLeastOneCycle() {
+ WorkerState newState;
+ switchWorkerStateSync(WorkerState::RUNNING, WorkerState::PAUSE_REQUESTED, &newState);
+ if (newState != WorkerState::PAUSED) return false;
+ switchWorkerStateSync(newState, WorkerState::RESUME_REQUESTED, &newState);
+ return newState == WorkerState::RUNNING;
+}
+
+void ThreadController::switchWorkerStateSync(WorkerState oldState, WorkerState newState,
+ WorkerState* finalState) {
+ std::unique_lock<std::mutex> lock(mWorkerLock);
+ android::base::ScopedLockAssertion lock_assertion(mWorkerLock);
+ if (mWorkerState != oldState) {
+ if (finalState) *finalState = mWorkerState;
+ return;
+ }
+ mWorkerState = newState;
+ mWorkerStateChangeRequest = true;
+ mWorkerCv.wait(lock, [&]() {
+ android::base::ScopedLockAssertion lock_assertion(mWorkerLock);
+ return mWorkerState != newState;
+ });
+ if (finalState) *finalState = mWorkerState;
+}
+
+void ThreadController::workerThread() {
+ using Status = StreamLogic::Status;
+
+ std::string error;
+ if (!mThreadName.empty()) {
+ std::string compliantName(mThreadName.substr(0, 15));
+ if (int errCode = pthread_setname_np(pthread_self(), compliantName.c_str()); errCode != 0) {
+ error.append("Failed to set thread name: ").append(strerror(errCode));
+ }
+ }
+ if (error.empty() && mThreadPriority != ANDROID_PRIORITY_DEFAULT) {
+ if (int result = setpriority(PRIO_PROCESS, 0, mThreadPriority); result != 0) {
+ int errCode = errno;
+ error.append("Failed to set thread priority: ").append(strerror(errCode));
+ }
+ }
+ if (error.empty()) {
+ error.append(mLogic->init());
+ }
+ {
+ std::lock_guard<std::mutex> lock(mWorkerLock);
+ mWorkerState = error.empty() ? WorkerState::RUNNING : WorkerState::STOPPED;
+ mError = error;
+ }
+ mWorkerCv.notify_one();
+ if (!error.empty()) return;
+
+ for (WorkerState state = WorkerState::RUNNING; state != WorkerState::STOPPED;) {
+ bool needToNotify = false;
+ if (Status status = state != WorkerState::PAUSED ? mLogic->cycle()
+ : (sched_yield(), Status::CONTINUE);
+ status == Status::CONTINUE) {
+ {
+ // See https://developer.android.com/training/articles/smp#nonracing
+ android::base::ScopedLockAssertion lock_assertion(mWorkerLock);
+ if (!mWorkerStateChangeRequest.load(std::memory_order_relaxed)) continue;
+ }
+ //
+ // Pause and resume are synchronous. One worker cycle must complete
+ // before the worker indicates a state change. This is how 'mWorkerState' and
+ // 'state' interact:
+ //
+ // mWorkerState == RUNNING
+ // client sets mWorkerState := PAUSE_REQUESTED
+ // last workerCycle gets executed, state := mWorkerState := PAUSED by us
+ // (or the workers enters the 'error' state if workerCycle fails)
+ // client gets notified about state change in any case
+ // thread is doing a busy wait while 'state == PAUSED'
+ // client sets mWorkerState := RESUME_REQUESTED
+ // state := mWorkerState (RESUME_REQUESTED)
+ // mWorkerState := RUNNING, but we don't notify the client yet
+ // first workerCycle gets executed, the code below triggers a client notification
+ // (or if workerCycle fails, worker enters 'error' state and also notifies)
+ // state := mWorkerState (RUNNING)
+ std::lock_guard<std::mutex> lock(mWorkerLock);
+ if (state == WorkerState::RESUME_REQUESTED) {
+ needToNotify = true;
+ }
+ state = mWorkerState;
+ if (mWorkerState == WorkerState::PAUSE_REQUESTED) {
+ state = mWorkerState = WorkerState::PAUSED;
+ needToNotify = true;
+ } else if (mWorkerState == WorkerState::RESUME_REQUESTED) {
+ mWorkerState = WorkerState::RUNNING;
+ }
+ } else {
+ std::lock_guard<std::mutex> lock(mWorkerLock);
+ if (state == WorkerState::RESUME_REQUESTED ||
+ mWorkerState == WorkerState::PAUSE_REQUESTED) {
+ needToNotify = true;
+ }
+ state = mWorkerState = WorkerState::STOPPED;
+ if (status == Status::ABORT) {
+ mError = "Received ABORT from the logic cycle";
+ }
+ }
+ if (needToNotify) {
+ {
+ std::lock_guard<std::mutex> lock(mWorkerLock);
+ mWorkerStateChangeRequest = false;
+ }
+ mWorkerCv.notify_one();
+ }
+ }
+}
+
+} // namespace android::hardware::audio::common::internal
diff --git a/audio/aidl/common/TEST_MAPPING b/audio/aidl/common/TEST_MAPPING
new file mode 100644
index 0000000..9dcf44e
--- /dev/null
+++ b/audio/aidl/common/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "libaudioaidlcommon_test"
+ }
+ ]
+}
diff --git a/audio/aidl/common/include/StreamWorker.h b/audio/aidl/common/include/StreamWorker.h
new file mode 100644
index 0000000..e9c1070
--- /dev/null
+++ b/audio/aidl/common/include/StreamWorker.h
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <atomic>
+#include <condition_variable>
+#include <mutex>
+#include <string>
+#include <thread>
+
+#include <android-base/thread_annotations.h>
+#include <system/thread_defs.h>
+
+namespace android::hardware::audio::common {
+
+class StreamLogic;
+
+namespace internal {
+
+class ThreadController {
+ enum class WorkerState { INITIAL, STOPPED, RUNNING, PAUSE_REQUESTED, PAUSED, RESUME_REQUESTED };
+
+ public:
+ explicit ThreadController(StreamLogic* logic) : mLogic(logic) {}
+ ~ThreadController() { stop(); }
+
+ bool start(const std::string& name, int priority);
+ // Note: 'pause' and 'resume' methods should only be used on the "driving" side.
+ // In the case of audio HAL I/O, the driving side is the client, because the HAL
+ // implementation always blocks on getting a command.
+ void pause() { switchWorkerStateSync(WorkerState::RUNNING, WorkerState::PAUSE_REQUESTED); }
+ void resume() { switchWorkerStateSync(WorkerState::PAUSED, WorkerState::RESUME_REQUESTED); }
+ bool hasError() {
+ std::lock_guard<std::mutex> lock(mWorkerLock);
+ return !mError.empty();
+ }
+ std::string getError() {
+ std::lock_guard<std::mutex> lock(mWorkerLock);
+ return mError;
+ }
+ void stop();
+ // Direct use of 'join' assumes that the StreamLogic is not intended
+ // to run forever, and is guaranteed to exit by itself. This normally
+ // only happen in tests.
+ void join();
+ bool waitForAtLeastOneCycle();
+
+ // Only used by unit tests.
+ void lockUnlockMutex(bool lock) NO_THREAD_SAFETY_ANALYSIS {
+ lock ? mWorkerLock.lock() : mWorkerLock.unlock();
+ }
+ std::thread::native_handle_type getThreadNativeHandle() { return mWorker.native_handle(); }
+
+ private:
+ void switchWorkerStateSync(WorkerState oldState, WorkerState newState,
+ WorkerState* finalState = nullptr);
+ void workerThread();
+
+ StreamLogic* const mLogic;
+ std::string mThreadName;
+ int mThreadPriority = ANDROID_PRIORITY_DEFAULT;
+ std::thread mWorker;
+ std::mutex mWorkerLock;
+ std::condition_variable mWorkerCv;
+ WorkerState mWorkerState GUARDED_BY(mWorkerLock) = WorkerState::INITIAL;
+ std::string mError GUARDED_BY(mWorkerLock);
+ // The atomic lock-free variable is used to prevent priority inversions
+ // that can occur when a high priority worker tries to acquire the lock
+ // which has been taken by a lower priority control thread which in its turn
+ // got preempted. To prevent a PI under normal operating conditions, that is,
+ // when there are no errors or state changes, the worker does not attempt
+ // taking `mWorkerLock` unless `mWorkerStateChangeRequest` is set.
+ // To make sure that updates to `mWorkerState` and `mWorkerStateChangeRequest`
+ // are serialized, they are always made under a lock.
+ static_assert(std::atomic<bool>::is_always_lock_free);
+ std::atomic<bool> mWorkerStateChangeRequest GUARDED_BY(mWorkerLock) = false;
+};
+
+// A special thread name used in tests only.
+static const std::string kTestSingleThread = "__testST__";
+
+} // namespace internal
+
+class StreamLogic {
+ public:
+ friend class internal::ThreadController;
+
+ virtual ~StreamLogic() = default;
+
+ protected:
+ enum class Status { ABORT, CONTINUE, EXIT };
+
+ /* Called once at the beginning of the thread loop. Must return
+ * an empty string to enter the thread loop, otherwise the thread loop
+ * exits and the worker switches into the 'error' state, setting
+ * the error to the returned value.
+ */
+ virtual std::string init() = 0;
+
+ /* Called for each thread loop unless the thread is in 'paused' state.
+ * Must return 'CONTINUE' to continue running, otherwise the thread loop
+ * exits. If the result from worker cycle is 'ABORT' then the worker switches
+ * into the 'error' state with a generic error message. It is recommended that
+ * the subclass reports any problems via logging facilities. Returning the 'EXIT'
+ * status is equivalent to calling 'stop()' method. This is just a way of
+ * of stopping the worker by its own initiative.
+ */
+ virtual Status cycle() = 0;
+};
+
+template <class LogicImpl>
+class StreamWorker : public LogicImpl {
+ public:
+ template <class... Args>
+ explicit StreamWorker(Args&&... args) : LogicImpl(std::forward<Args>(args)...), mThread(this) {}
+
+ // Methods of LogicImpl are available via inheritance.
+ // Forwarded methods of ThreadController follow.
+
+ // Note that 'priority' here is what is known as the 'nice number' in *nix systems.
+ // The nice number is used with the default scheduler. For threads that
+ // need to use a specialized scheduler (e.g. SCHED_FIFO) and set the priority within it,
+ // it is recommended to implement an appropriate configuration sequence within
+ // 'LogicImpl' or 'StreamLogic::init'.
+ bool start(const std::string& name = "", int priority = ANDROID_PRIORITY_DEFAULT) {
+ return mThread.start(name, priority);
+ }
+ void pause() { mThread.pause(); }
+ void resume() { mThread.resume(); }
+ bool hasError() { return mThread.hasError(); }
+ std::string getError() { return mThread.getError(); }
+ void stop() { mThread.stop(); }
+ void join() { mThread.join(); }
+ bool waitForAtLeastOneCycle() { return mThread.waitForAtLeastOneCycle(); }
+
+ // Only used by unit tests.
+ void testLockUnlockMutex(bool lock) { mThread.lockUnlockMutex(lock); }
+ std::thread::native_handle_type testGetThreadNativeHandle() {
+ return mThread.getThreadNativeHandle();
+ }
+
+ private:
+ // The ThreadController gets destroyed before LogicImpl.
+ // After the controller has been destroyed, it is guaranteed that
+ // the thread was joined, thus the 'cycle' method of LogicImpl
+ // will not be called anymore, and it is safe to destroy LogicImpl.
+ internal::ThreadController mThread;
+};
+
+} // namespace android::hardware::audio::common
diff --git a/audio/aidl/common/include/Utils.h b/audio/aidl/common/include/Utils.h
new file mode 100644
index 0000000..1026134
--- /dev/null
+++ b/audio/aidl/common/include/Utils.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <initializer_list>
+#include <type_traits>
+
+#include <aidl/android/media/audio/common/AudioChannelLayout.h>
+#include <aidl/android/media/audio/common/AudioFormatDescription.h>
+#include <aidl/android/media/audio/common/AudioInputFlags.h>
+#include <aidl/android/media/audio/common/AudioOutputFlags.h>
+#include <aidl/android/media/audio/common/PcmType.h>
+
+namespace android::hardware::audio::common {
+
+constexpr size_t getPcmSampleSizeInBytes(::aidl::android::media::audio::common::PcmType pcm) {
+ using ::aidl::android::media::audio::common::PcmType;
+ switch (pcm) {
+ case PcmType::UINT_8_BIT:
+ return 1;
+ case PcmType::INT_16_BIT:
+ return 2;
+ case PcmType::INT_32_BIT:
+ return 4;
+ case PcmType::FIXED_Q_8_24:
+ return 4;
+ case PcmType::FLOAT_32_BIT:
+ return 4;
+ case PcmType::INT_24_BIT:
+ return 3;
+ }
+ return 0;
+}
+
+constexpr size_t getChannelCount(
+ const ::aidl::android::media::audio::common::AudioChannelLayout& layout) {
+ using Tag = ::aidl::android::media::audio::common::AudioChannelLayout::Tag;
+ switch (layout.getTag()) {
+ case Tag::none:
+ return 0;
+ case Tag::invalid:
+ return 0;
+ case Tag::indexMask:
+ return __builtin_popcount(layout.get<Tag::indexMask>());
+ case Tag::layoutMask:
+ return __builtin_popcount(layout.get<Tag::layoutMask>());
+ case Tag::voiceMask:
+ return __builtin_popcount(layout.get<Tag::voiceMask>());
+ }
+ return 0;
+}
+
+constexpr size_t getFrameSizeInBytes(
+ const ::aidl::android::media::audio::common::AudioFormatDescription& format,
+ const ::aidl::android::media::audio::common::AudioChannelLayout& layout) {
+ if (format == ::aidl::android::media::audio::common::AudioFormatDescription{}) {
+ // Unspecified format.
+ return 0;
+ }
+ using ::aidl::android::media::audio::common::AudioFormatType;
+ if (format.type == AudioFormatType::PCM) {
+ return getPcmSampleSizeInBytes(format.pcm) * getChannelCount(layout);
+ } else if (format.type == AudioFormatType::NON_PCM) {
+ // For non-PCM formats always use the underlying PCM size. The default value for
+ // PCM is "UINT_8_BIT", thus non-encapsulated streams have the frame size of 1.
+ return getPcmSampleSizeInBytes(format.pcm);
+ }
+ // Something unexpected.
+ return 0;
+}
+
+// The helper functions defined below are only applicable to the case when an enum type
+// specifies zero-based bit positions, not bit masks themselves. This is why instantiation
+// is restricted to certain enum types.
+template <typename E>
+using is_bit_position_enum = std::integral_constant<
+ bool, std::is_same_v<E, ::aidl::android::media::audio::common::AudioInputFlags> ||
+ std::is_same_v<E, ::aidl::android::media::audio::common::AudioOutputFlags>>;
+
+template <typename E, typename U = std::underlying_type_t<E>,
+ typename = std::enable_if_t<is_bit_position_enum<E>::value>>
+constexpr U makeBitPositionFlagMask(E flag) {
+ return 1 << static_cast<U>(flag);
+}
+
+template <typename E, typename U = std::underlying_type_t<E>,
+ typename = std::enable_if_t<is_bit_position_enum<E>::value>>
+constexpr bool isBitPositionFlagSet(U mask, E flag) {
+ return (mask & makeBitPositionFlagMask(flag)) != 0;
+}
+
+template <typename E, typename U = std::underlying_type_t<E>,
+ typename = std::enable_if_t<is_bit_position_enum<E>::value>>
+constexpr U makeBitPositionFlagMask(std::initializer_list<E> flags) {
+ U result = 0;
+ for (const auto flag : flags) {
+ result |= makeBitPositionFlagMask(flag);
+ }
+ return result;
+}
+
+} // namespace android::hardware::audio::common
diff --git a/audio/aidl/common/tests/streamworker_tests.cpp b/audio/aidl/common/tests/streamworker_tests.cpp
new file mode 100644
index 0000000..f7a30b9
--- /dev/null
+++ b/audio/aidl/common/tests/streamworker_tests.cpp
@@ -0,0 +1,298 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <pthread.h>
+#include <sched.h>
+#include <sys/resource.h>
+#include <unistd.h>
+
+#include <atomic>
+
+#include <StreamWorker.h>
+
+#include <gtest/gtest.h>
+#define LOG_TAG "StreamWorker_Test"
+#include <log/log.h>
+
+using android::hardware::audio::common::StreamLogic;
+using android::hardware::audio::common::StreamWorker;
+
+class TestWorkerLogic : public StreamLogic {
+ public:
+ struct Stream {
+ void setErrorStatus() { status = Status::ABORT; }
+ void setStopStatus() { status = Status::EXIT; }
+ std::atomic<Status> status = Status::CONTINUE;
+ };
+
+ // Use nullptr to test error reporting from the worker thread.
+ explicit TestWorkerLogic(Stream* stream) : mStream(stream) {}
+
+ size_t getWorkerCycles() const { return mWorkerCycles; }
+ int getPriority() const { return mPriority; }
+ bool hasWorkerCycleCalled() const { return mWorkerCycles != 0; }
+ bool hasNoWorkerCycleCalled(useconds_t usec) {
+ const size_t cyclesBefore = mWorkerCycles;
+ usleep(usec);
+ return mWorkerCycles == cyclesBefore;
+ }
+
+ protected:
+ // StreamLogic implementation
+ std::string init() override { return mStream != nullptr ? "" : "Expected error"; }
+ Status cycle() override {
+ mPriority = getpriority(PRIO_PROCESS, 0);
+ do {
+ mWorkerCycles++;
+ } while (mWorkerCycles == 0);
+ return mStream->status;
+ }
+
+ private:
+ Stream* const mStream;
+ std::atomic<size_t> mWorkerCycles = 0;
+ std::atomic<int> mPriority = ANDROID_PRIORITY_DEFAULT;
+};
+using TestWorker = StreamWorker<TestWorkerLogic>;
+
+// The parameter specifies whether an extra call to 'stop' is made at the end.
+class StreamWorkerInvalidTest : public testing::TestWithParam<bool> {
+ public:
+ StreamWorkerInvalidTest() : StreamWorkerInvalidTest(nullptr) {}
+ void TearDown() override {
+ if (GetParam()) {
+ worker.stop();
+ }
+ }
+
+ protected:
+ StreamWorkerInvalidTest(TestWorker::Stream* stream)
+ : testing::TestWithParam<bool>(), worker(stream) {}
+ TestWorker worker;
+};
+
+TEST_P(StreamWorkerInvalidTest, Uninitialized) {
+ EXPECT_FALSE(worker.hasWorkerCycleCalled());
+ EXPECT_FALSE(worker.hasError());
+}
+
+TEST_P(StreamWorkerInvalidTest, UninitializedPauseIgnored) {
+ EXPECT_FALSE(worker.hasError());
+ worker.pause();
+ EXPECT_FALSE(worker.hasError());
+}
+
+TEST_P(StreamWorkerInvalidTest, UninitializedResumeIgnored) {
+ EXPECT_FALSE(worker.hasError());
+ worker.resume();
+ EXPECT_FALSE(worker.hasError());
+}
+
+TEST_P(StreamWorkerInvalidTest, Start) {
+ EXPECT_FALSE(worker.start());
+ EXPECT_FALSE(worker.hasWorkerCycleCalled());
+ EXPECT_TRUE(worker.hasError());
+}
+
+TEST_P(StreamWorkerInvalidTest, PauseIgnored) {
+ EXPECT_FALSE(worker.start());
+ EXPECT_TRUE(worker.hasError());
+ worker.pause();
+ EXPECT_TRUE(worker.hasError());
+}
+
+TEST_P(StreamWorkerInvalidTest, ResumeIgnored) {
+ EXPECT_FALSE(worker.start());
+ EXPECT_TRUE(worker.hasError());
+ worker.resume();
+ EXPECT_TRUE(worker.hasError());
+}
+
+INSTANTIATE_TEST_SUITE_P(StreamWorkerInvalid, StreamWorkerInvalidTest, testing::Bool());
+
+class StreamWorkerTest : public StreamWorkerInvalidTest {
+ public:
+ StreamWorkerTest() : StreamWorkerInvalidTest(&stream) {}
+
+ protected:
+ TestWorker::Stream stream;
+};
+
+static constexpr unsigned kWorkerIdleCheckTime = 50 * 1000;
+
+TEST_P(StreamWorkerTest, Uninitialized) {
+ EXPECT_FALSE(worker.hasWorkerCycleCalled());
+ EXPECT_FALSE(worker.hasError());
+}
+
+TEST_P(StreamWorkerTest, Start) {
+ ASSERT_TRUE(worker.start());
+ EXPECT_TRUE(worker.waitForAtLeastOneCycle());
+ EXPECT_FALSE(worker.hasError());
+}
+
+TEST_P(StreamWorkerTest, StartStop) {
+ ASSERT_TRUE(worker.start());
+ EXPECT_TRUE(worker.waitForAtLeastOneCycle());
+ EXPECT_FALSE(worker.hasError());
+ worker.stop();
+ EXPECT_FALSE(worker.hasError());
+}
+
+TEST_P(StreamWorkerTest, WorkerExit) {
+ ASSERT_TRUE(worker.start());
+ stream.setStopStatus();
+ worker.waitForAtLeastOneCycle();
+ EXPECT_FALSE(worker.hasError());
+ EXPECT_TRUE(worker.hasNoWorkerCycleCalled(kWorkerIdleCheckTime));
+}
+
+TEST_P(StreamWorkerTest, WorkerJoin) {
+ ASSERT_TRUE(worker.start());
+ stream.setStopStatus();
+ worker.join();
+ EXPECT_FALSE(worker.hasError());
+ EXPECT_TRUE(worker.hasNoWorkerCycleCalled(kWorkerIdleCheckTime));
+}
+
+TEST_P(StreamWorkerTest, WorkerError) {
+ ASSERT_TRUE(worker.start());
+ stream.setErrorStatus();
+ worker.waitForAtLeastOneCycle();
+ EXPECT_TRUE(worker.hasError());
+ EXPECT_TRUE(worker.hasNoWorkerCycleCalled(kWorkerIdleCheckTime));
+}
+
+TEST_P(StreamWorkerTest, StopAfterError) {
+ ASSERT_TRUE(worker.start());
+ stream.setErrorStatus();
+ worker.waitForAtLeastOneCycle();
+ EXPECT_TRUE(worker.hasError());
+ EXPECT_TRUE(worker.hasNoWorkerCycleCalled(kWorkerIdleCheckTime));
+ worker.stop();
+ EXPECT_TRUE(worker.hasError());
+}
+
+TEST_P(StreamWorkerTest, PauseResume) {
+ ASSERT_TRUE(worker.start());
+ EXPECT_TRUE(worker.waitForAtLeastOneCycle());
+ EXPECT_FALSE(worker.hasError());
+ worker.pause();
+ EXPECT_TRUE(worker.hasNoWorkerCycleCalled(kWorkerIdleCheckTime));
+ EXPECT_FALSE(worker.hasError());
+ const size_t workerCyclesBefore = worker.getWorkerCycles();
+ worker.resume();
+ // 'resume' is synchronous and returns after the worker has looped at least once.
+ EXPECT_GT(worker.getWorkerCycles(), workerCyclesBefore);
+ EXPECT_FALSE(worker.hasError());
+}
+
+TEST_P(StreamWorkerTest, StopPaused) {
+ ASSERT_TRUE(worker.start());
+ EXPECT_TRUE(worker.waitForAtLeastOneCycle());
+ EXPECT_FALSE(worker.hasError());
+ worker.pause();
+ worker.stop();
+ EXPECT_FALSE(worker.hasError());
+}
+
+TEST_P(StreamWorkerTest, PauseAfterErrorIgnored) {
+ ASSERT_TRUE(worker.start());
+ stream.setErrorStatus();
+ worker.waitForAtLeastOneCycle();
+ EXPECT_TRUE(worker.hasError());
+ worker.pause();
+ EXPECT_TRUE(worker.hasNoWorkerCycleCalled(kWorkerIdleCheckTime));
+ EXPECT_TRUE(worker.hasError());
+}
+
+TEST_P(StreamWorkerTest, ResumeAfterErrorIgnored) {
+ ASSERT_TRUE(worker.start());
+ stream.setErrorStatus();
+ worker.waitForAtLeastOneCycle();
+ EXPECT_TRUE(worker.hasError());
+ worker.resume();
+ EXPECT_TRUE(worker.hasNoWorkerCycleCalled(kWorkerIdleCheckTime));
+ EXPECT_TRUE(worker.hasError());
+}
+
+TEST_P(StreamWorkerTest, WorkerErrorOnResume) {
+ ASSERT_TRUE(worker.start());
+ EXPECT_TRUE(worker.waitForAtLeastOneCycle());
+ EXPECT_FALSE(worker.hasError());
+ worker.pause();
+ EXPECT_FALSE(worker.hasError());
+ stream.setErrorStatus();
+ EXPECT_FALSE(worker.hasError());
+ worker.resume();
+ worker.waitForAtLeastOneCycle();
+ EXPECT_TRUE(worker.hasError());
+ EXPECT_TRUE(worker.hasNoWorkerCycleCalled(kWorkerIdleCheckTime));
+}
+
+TEST_P(StreamWorkerTest, WaitForAtLeastOneCycle) {
+ ASSERT_TRUE(worker.start());
+ const size_t workerCyclesBefore = worker.getWorkerCycles();
+ EXPECT_TRUE(worker.waitForAtLeastOneCycle());
+ EXPECT_GT(worker.getWorkerCycles(), workerCyclesBefore);
+}
+
+TEST_P(StreamWorkerTest, WaitForAtLeastOneCycleError) {
+ ASSERT_TRUE(worker.start());
+ stream.setErrorStatus();
+ EXPECT_FALSE(worker.waitForAtLeastOneCycle());
+}
+
+TEST_P(StreamWorkerTest, MutexDoesNotBlockWorker) {
+ ASSERT_TRUE(worker.start());
+ const size_t workerCyclesBefore = worker.getWorkerCycles();
+ worker.testLockUnlockMutex(true);
+ while (worker.getWorkerCycles() == workerCyclesBefore) {
+ usleep(kWorkerIdleCheckTime);
+ }
+ worker.testLockUnlockMutex(false);
+ EXPECT_TRUE(worker.waitForAtLeastOneCycle());
+ EXPECT_FALSE(worker.hasError());
+}
+
+TEST_P(StreamWorkerTest, ThreadName) {
+ const std::string workerName = "TestWorker";
+ ASSERT_TRUE(worker.start(workerName)) << worker.getError();
+ char nameBuf[128];
+ ASSERT_EQ(0, pthread_getname_np(worker.testGetThreadNativeHandle(), nameBuf, sizeof(nameBuf)));
+ EXPECT_EQ(workerName, nameBuf);
+}
+
+TEST_P(StreamWorkerTest, ThreadPriority) {
+ const int priority = ANDROID_PRIORITY_LOWEST;
+ ASSERT_TRUE(worker.start("", priority)) << worker.getError();
+ EXPECT_TRUE(worker.waitForAtLeastOneCycle());
+ EXPECT_EQ(priority, worker.getPriority());
+}
+
+TEST_P(StreamWorkerTest, DeferredStartCheckNoError) {
+ stream.setStopStatus();
+ EXPECT_TRUE(worker.start(android::hardware::audio::common::internal::kTestSingleThread));
+ EXPECT_FALSE(worker.hasError());
+}
+
+TEST_P(StreamWorkerTest, DeferredStartCheckWithError) {
+ stream.setErrorStatus();
+ EXPECT_FALSE(worker.start(android::hardware::audio::common::internal::kTestSingleThread));
+ EXPECT_TRUE(worker.hasError());
+}
+
+INSTANTIATE_TEST_SUITE_P(StreamWorker, StreamWorkerTest, testing::Bool());
diff --git a/audio/aidl/common/tests/utils_tests.cpp b/audio/aidl/common/tests/utils_tests.cpp
new file mode 100644
index 0000000..d7f1a5d
--- /dev/null
+++ b/audio/aidl/common/tests/utils_tests.cpp
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cstdint>
+#include <limits>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include <Utils.h>
+
+#include <gtest/gtest.h>
+#define LOG_TAG "Utils_Test"
+#include <log/log.h>
+
+using aidl::android::media::audio::common::AudioChannelLayout;
+using aidl::android::media::audio::common::AudioFormatDescription;
+using aidl::android::media::audio::common::AudioFormatType;
+using aidl::android::media::audio::common::PcmType;
+using android::hardware::audio::common::getChannelCount;
+using android::hardware::audio::common::getFrameSizeInBytes;
+using android::hardware::audio::common::getPcmSampleSizeInBytes;
+
+TEST(UtilsTest, ChannelCountOddCases) {
+ using Tag = AudioChannelLayout::Tag;
+ EXPECT_EQ(0UL, getChannelCount(AudioChannelLayout{}));
+ EXPECT_EQ(0UL, getChannelCount(AudioChannelLayout::make<Tag::invalid>(0)));
+ EXPECT_EQ(0UL, getChannelCount(AudioChannelLayout::make<Tag::invalid>(-1)));
+}
+
+TEST(UtilsTest, ChannelCountForIndexMask) {
+ using Tag = AudioChannelLayout::Tag;
+ EXPECT_EQ(0UL, getChannelCount(AudioChannelLayout::make<Tag::indexMask>(0)));
+#define VERIFY_INDEX_MASK(N) \
+ { \
+ const auto l = \
+ AudioChannelLayout::make<Tag::indexMask>(AudioChannelLayout::INDEX_MASK_##N); \
+ EXPECT_EQ(N##UL, getChannelCount(l)) << l.toString(); \
+ }
+ VERIFY_INDEX_MASK(1);
+ VERIFY_INDEX_MASK(2);
+ VERIFY_INDEX_MASK(3);
+ VERIFY_INDEX_MASK(4);
+ VERIFY_INDEX_MASK(5);
+ VERIFY_INDEX_MASK(6);
+ VERIFY_INDEX_MASK(7);
+ VERIFY_INDEX_MASK(8);
+ VERIFY_INDEX_MASK(9);
+ VERIFY_INDEX_MASK(10);
+ VERIFY_INDEX_MASK(11);
+ VERIFY_INDEX_MASK(12);
+ VERIFY_INDEX_MASK(13);
+ VERIFY_INDEX_MASK(14);
+ VERIFY_INDEX_MASK(15);
+ VERIFY_INDEX_MASK(16);
+ VERIFY_INDEX_MASK(17);
+ VERIFY_INDEX_MASK(18);
+ VERIFY_INDEX_MASK(19);
+ VERIFY_INDEX_MASK(20);
+ VERIFY_INDEX_MASK(21);
+ VERIFY_INDEX_MASK(22);
+ VERIFY_INDEX_MASK(23);
+ VERIFY_INDEX_MASK(24);
+#undef VERIFY_INDEX_MASK
+}
+
+TEST(UtilsTest, ChannelCountForLayoutMask) {
+ using Tag = AudioChannelLayout::Tag;
+ const std::vector<std::pair<size_t, int32_t>> kTestLayouts = {
+ std::make_pair(0UL, 0),
+ std::make_pair(1UL, AudioChannelLayout::LAYOUT_MONO),
+ std::make_pair(2UL, AudioChannelLayout::LAYOUT_STEREO),
+ std::make_pair(6UL, AudioChannelLayout::LAYOUT_5POINT1),
+ std::make_pair(8UL, AudioChannelLayout::LAYOUT_7POINT1),
+ std::make_pair(16UL, AudioChannelLayout::LAYOUT_9POINT1POINT6),
+ std::make_pair(13UL, AudioChannelLayout::LAYOUT_13POINT_360RA),
+ std::make_pair(24UL, AudioChannelLayout::LAYOUT_22POINT2),
+ std::make_pair(3UL, AudioChannelLayout::LAYOUT_STEREO_HAPTIC_A),
+ std::make_pair(4UL, AudioChannelLayout::LAYOUT_STEREO_HAPTIC_AB)};
+ for (const auto& [expected_count, layout] : kTestLayouts) {
+ const auto l = AudioChannelLayout::make<Tag::layoutMask>(layout);
+ EXPECT_EQ(expected_count, getChannelCount(l)) << l.toString();
+ }
+}
+
+TEST(UtilsTest, ChannelCountForVoiceMask) {
+ using Tag = AudioChannelLayout::Tag;
+ // clang-format off
+ const std::vector<std::pair<size_t, int32_t>> kTestLayouts = {
+ std::make_pair(0UL, 0),
+ std::make_pair(1UL, AudioChannelLayout::VOICE_UPLINK_MONO),
+ std::make_pair(1UL, AudioChannelLayout::VOICE_DNLINK_MONO),
+ std::make_pair(2UL, AudioChannelLayout::VOICE_CALL_MONO)};
+ // clang-format on
+ for (const auto& [expected_count, layout] : kTestLayouts) {
+ const auto l = AudioChannelLayout::make<Tag::voiceMask>(layout);
+ EXPECT_EQ(expected_count, getChannelCount(l)) << l.toString();
+ }
+}
+
+namespace {
+
+AudioChannelLayout make_AudioChannelLayout_Mono() {
+ return AudioChannelLayout::make<AudioChannelLayout::Tag::layoutMask>(
+ AudioChannelLayout::LAYOUT_MONO);
+}
+
+AudioChannelLayout make_AudioChannelLayout_Stereo() {
+ return AudioChannelLayout::make<AudioChannelLayout::Tag::layoutMask>(
+ AudioChannelLayout::LAYOUT_STEREO);
+}
+
+AudioFormatDescription make_AudioFormatDescription(AudioFormatType type) {
+ AudioFormatDescription result;
+ result.type = type;
+ return result;
+}
+
+AudioFormatDescription make_AudioFormatDescription(PcmType pcm) {
+ auto result = make_AudioFormatDescription(AudioFormatType::PCM);
+ result.pcm = pcm;
+ return result;
+}
+
+AudioFormatDescription make_AudioFormatDescription(const std::string& encoding) {
+ AudioFormatDescription result;
+ result.encoding = encoding;
+ return result;
+}
+
+AudioFormatDescription make_AudioFormatDescription(PcmType transport, const std::string& encoding) {
+ auto result = make_AudioFormatDescription(encoding);
+ result.pcm = transport;
+ return result;
+}
+
+} // namespace
+
+TEST(UtilsTest, FrameSize) {
+ EXPECT_EQ(0UL, getFrameSizeInBytes(AudioFormatDescription{}, AudioChannelLayout{}));
+ EXPECT_EQ(sizeof(int16_t), getFrameSizeInBytes(make_AudioFormatDescription(PcmType::INT_16_BIT),
+ make_AudioChannelLayout_Mono()));
+ EXPECT_EQ(2 * sizeof(int16_t),
+ getFrameSizeInBytes(make_AudioFormatDescription(PcmType::INT_16_BIT),
+ make_AudioChannelLayout_Stereo()));
+ EXPECT_EQ(sizeof(int32_t), getFrameSizeInBytes(make_AudioFormatDescription(PcmType::INT_32_BIT),
+ make_AudioChannelLayout_Mono()));
+ EXPECT_EQ(2 * sizeof(int32_t),
+ getFrameSizeInBytes(make_AudioFormatDescription(PcmType::INT_32_BIT),
+ make_AudioChannelLayout_Stereo()));
+ EXPECT_EQ(sizeof(float), getFrameSizeInBytes(make_AudioFormatDescription(PcmType::FLOAT_32_BIT),
+ make_AudioChannelLayout_Mono()));
+ EXPECT_EQ(2 * sizeof(float),
+ getFrameSizeInBytes(make_AudioFormatDescription(PcmType::FLOAT_32_BIT),
+ make_AudioChannelLayout_Stereo()));
+ EXPECT_EQ(sizeof(uint8_t),
+ getFrameSizeInBytes(make_AudioFormatDescription("bitstream"), AudioChannelLayout{}));
+ EXPECT_EQ(sizeof(int16_t),
+ getFrameSizeInBytes(make_AudioFormatDescription(PcmType::INT_16_BIT, "encapsulated"),
+ AudioChannelLayout{}));
+}
+
+TEST(UtilsTest, PcmSampleSize) {
+ EXPECT_EQ(1UL, getPcmSampleSizeInBytes(PcmType{}));
+ EXPECT_EQ(sizeof(uint8_t), getPcmSampleSizeInBytes(PcmType::UINT_8_BIT));
+ EXPECT_EQ(sizeof(int16_t), getPcmSampleSizeInBytes(PcmType::INT_16_BIT));
+ EXPECT_EQ(sizeof(int32_t), getPcmSampleSizeInBytes(PcmType::INT_32_BIT));
+ EXPECT_EQ(sizeof(int32_t), getPcmSampleSizeInBytes(PcmType::FIXED_Q_8_24));
+ EXPECT_EQ(sizeof(float), getPcmSampleSizeInBytes(PcmType::FLOAT_32_BIT));
+ EXPECT_EQ(3UL, getPcmSampleSizeInBytes(PcmType::INT_24_BIT));
+ EXPECT_EQ(0UL, getPcmSampleSizeInBytes(PcmType(-1)));
+ using PcmTypeUnderlyingType = std::underlying_type_t<PcmType>;
+ EXPECT_EQ(0UL,
+ getPcmSampleSizeInBytes(PcmType(std::numeric_limits<PcmTypeUnderlyingType>::min())));
+ EXPECT_EQ(0UL,
+ getPcmSampleSizeInBytes(PcmType(std::numeric_limits<PcmTypeUnderlyingType>::max())));
+}
diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp
new file mode 100644
index 0000000..2b9ed5b
--- /dev/null
+++ b/audio/aidl/default/Android.bp
@@ -0,0 +1,136 @@
+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: "aidlaudioservice_defaults",
+ vendor: true,
+ shared_libs: [
+ "libaudioaidlcommon",
+ "libbase",
+ "libbinder_ndk",
+ "libcutils",
+ "libfmq",
+ "libstagefright_foundation",
+ "libutils",
+ "android.hardware.common-V2-ndk",
+ "android.hardware.common.fmq-V1-ndk",
+ ],
+ header_libs: [
+ "libaudioaidl_headers",
+ ],
+}
+
+cc_library_static {
+ name: "libaudioserviceexampleimpl",
+ defaults: [
+ "aidlaudioservice_defaults",
+ "latest_android_media_audio_common_types_ndk_shared",
+ "latest_android_hardware_audio_core_ndk_shared",
+ ],
+ export_include_dirs: ["include"],
+ srcs: [
+ "Config.cpp",
+ "Configuration.cpp",
+ "Module.cpp",
+ "Stream.cpp",
+ "Telephony.cpp",
+ ],
+ visibility: [
+ ":__subpackages__",
+ ],
+}
+
+cc_binary {
+ name: "android.hardware.audio.service-aidl.example",
+ relative_install_path: "hw",
+ init_rc: ["android.hardware.audio.service-aidl.example.rc"],
+ vintf_fragments: ["android.hardware.audio.service-aidl.xml"],
+ defaults: [
+ "aidlaudioservice_defaults",
+ "latest_android_media_audio_common_types_ndk_shared",
+ "latest_android_hardware_audio_core_ndk_shared",
+ ],
+ static_libs: [
+ "libaudioserviceexampleimpl",
+ ],
+ srcs: ["main.cpp"],
+}
+
+cc_defaults {
+ name: "aidlaudioeffectservice_defaults",
+ defaults: [
+ "latest_android_media_audio_common_types_ndk_shared",
+ "latest_android_hardware_audio_effect_ndk_shared",
+ ],
+ vendor: true,
+ shared_libs: [
+ "libaudioaidlcommon",
+ "libbase",
+ "libbinder_ndk",
+ "libcutils",
+ "libfmq",
+ "liblog",
+ "libutils",
+ "android.hardware.common-V2-ndk",
+ "android.hardware.common.fmq-V1-ndk",
+ ],
+ header_libs: [
+ "libaudioaidl_headers",
+ "libaudio_system_headers",
+ "libsystem_headers",
+ ],
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-Wthread-safety",
+ ],
+}
+
+filegroup {
+ name: "effectCommonFile",
+ srcs: [
+ "EffectThread.cpp",
+ "EffectImpl.cpp",
+ ],
+}
+
+cc_binary {
+ name: "android.hardware.audio.effect.service-aidl.example",
+ relative_install_path: "hw",
+ init_rc: ["android.hardware.audio.effect.service-aidl.example.rc"],
+ vintf_fragments: ["android.hardware.audio.effect.service-aidl.xml"],
+ defaults: ["aidlaudioeffectservice_defaults"],
+ shared_libs: [
+ "libbassboostsw",
+ "libbundleaidl",
+ "libdynamicsprocessingsw",
+ "libenvreverbsw",
+ "libequalizersw",
+ "libhapticgeneratorsw",
+ "libloudnessenhancersw",
+ "libpresetreverbsw",
+ "libtinyxml2",
+ "libvirtualizersw",
+ "libvisualizersw",
+ "libvolumesw",
+ ],
+ srcs: [
+ "EffectConfig.cpp",
+ "EffectFactory.cpp",
+ "EffectMain.cpp",
+ ],
+}
+
+cc_library_headers {
+ name: "libaudioaidl_headers",
+ export_include_dirs: ["include"],
+ vendor_available: true,
+ host_supported: true,
+}
diff --git a/audio/aidl/default/Config.cpp b/audio/aidl/default/Config.cpp
new file mode 100644
index 0000000..0fdd5b4
--- /dev/null
+++ b/audio/aidl/default/Config.cpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "AHAL_Module"
+#include <android-base/logging.h>
+
+#include "core-impl/Config.h"
+
+namespace aidl::android::hardware::audio::core {
+ndk::ScopedAStatus Config::getSurroundSoundConfig(SurroundSoundConfig* _aidl_return) {
+ SurroundSoundConfig surroundSoundConfig;
+ // TODO: parse from XML; for now, use empty config as default
+ *_aidl_return = std::move(surroundSoundConfig);
+ LOG(DEBUG) << __func__ << ": returning " << _aidl_return->toString();
+ return ndk::ScopedAStatus::ok();
+}
+} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/Configuration.cpp b/audio/aidl/default/Configuration.cpp
new file mode 100644
index 0000000..a3e5ff7
--- /dev/null
+++ b/audio/aidl/default/Configuration.cpp
@@ -0,0 +1,292 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <Utils.h>
+#include <aidl/android/media/audio/common/AudioChannelLayout.h>
+#include <aidl/android/media/audio/common/AudioDeviceType.h>
+#include <aidl/android/media/audio/common/AudioFormatDescription.h>
+#include <aidl/android/media/audio/common/AudioFormatType.h>
+#include <aidl/android/media/audio/common/AudioIoFlags.h>
+#include <aidl/android/media/audio/common/AudioOutputFlags.h>
+#include <media/stagefright/foundation/MediaDefs.h>
+
+#include "core-impl/Configuration.h"
+
+using aidl::android::media::audio::common::AudioChannelLayout;
+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::AudioGainConfig;
+using aidl::android::media::audio::common::AudioIoFlags;
+using aidl::android::media::audio::common::AudioOutputFlags;
+using aidl::android::media::audio::common::AudioPort;
+using aidl::android::media::audio::common::AudioPortConfig;
+using aidl::android::media::audio::common::AudioPortDeviceExt;
+using aidl::android::media::audio::common::AudioPortExt;
+using aidl::android::media::audio::common::AudioPortMixExt;
+using aidl::android::media::audio::common::AudioProfile;
+using aidl::android::media::audio::common::Int;
+using aidl::android::media::audio::common::PcmType;
+using android::hardware::audio::common::makeBitPositionFlagMask;
+
+namespace aidl::android::hardware::audio::core::internal {
+
+static void fillProfile(AudioProfile* profile, const std::vector<int32_t>& channelLayouts,
+ const std::vector<int32_t>& sampleRates) {
+ for (auto layout : channelLayouts) {
+ profile->channelMasks.push_back(
+ AudioChannelLayout::make<AudioChannelLayout::layoutMask>(layout));
+ }
+ profile->sampleRates.insert(profile->sampleRates.end(), sampleRates.begin(), sampleRates.end());
+}
+
+static AudioProfile createProfile(PcmType pcmType, const std::vector<int32_t>& channelLayouts,
+ const std::vector<int32_t>& sampleRates) {
+ AudioProfile profile;
+ profile.format.type = AudioFormatType::PCM;
+ profile.format.pcm = pcmType;
+ fillProfile(&profile, channelLayouts, sampleRates);
+ return profile;
+}
+
+static AudioProfile createProfile(const std::string& encodingType,
+ const std::vector<int32_t>& channelLayouts,
+ const std::vector<int32_t>& sampleRates) {
+ AudioProfile profile;
+ profile.format.encoding = encodingType;
+ fillProfile(&profile, channelLayouts, sampleRates);
+ return profile;
+}
+
+static AudioPortExt createDeviceExt(AudioDeviceType devType, int32_t flags,
+ std::string connection = "") {
+ AudioPortDeviceExt deviceExt;
+ deviceExt.device.type.type = devType;
+ deviceExt.device.type.connection = std::move(connection);
+ deviceExt.flags = flags;
+ return AudioPortExt::make<AudioPortExt::Tag::device>(deviceExt);
+}
+
+static AudioPortExt createPortMixExt(int32_t maxOpenStreamCount, int32_t maxActiveStreamCount) {
+ AudioPortMixExt mixExt;
+ mixExt.maxOpenStreamCount = maxOpenStreamCount;
+ mixExt.maxActiveStreamCount = maxActiveStreamCount;
+ return AudioPortExt::make<AudioPortExt::Tag::mix>(mixExt);
+}
+
+static AudioPort createPort(int32_t id, const std::string& name, int32_t flags, bool isInput,
+ const AudioPortExt& ext) {
+ AudioPort port;
+ port.id = id;
+ port.name = name;
+ port.flags = isInput ? AudioIoFlags::make<AudioIoFlags::Tag::input>(flags)
+ : AudioIoFlags::make<AudioIoFlags::Tag::output>(flags);
+ port.ext = ext;
+ 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) {
+ 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);
+ config.ext = ext;
+ return config;
+}
+
+static AudioRoute createRoute(const std::vector<int32_t>& sources, int32_t sink) {
+ AudioRoute route;
+ route.sinkPortId = sink;
+ route.sourcePortIds.insert(route.sourcePortIds.end(), sources.begin(), sources.end());
+ return route;
+}
+
+// Configuration:
+//
+// Device ports:
+// * "Null", OUT_SPEAKER, default
+// - no profiles specified
+// * "Loopback Out", OUT_SUBMIX
+// - profile PCM 24-bit; STEREO; 48000
+// * "USB Out", OUT_DEVICE, CONNECTION_USB
+// - no profiles specified
+// * "Zero", IN_MICROPHONE, default
+// - no profiles specified
+// * "Loopback In", IN_SUBMIX
+// - profile PCM 24-bit; STEREO; 48000
+// * "USB In", IN_DEVICE, CONNECTION_USB
+// - no profiles specified
+//
+// Mix ports:
+// * "primary output", PRIMARY, 1 max open, 1 max active stream
+// - profile PCM 16-bit; MONO, STEREO; 44100, 48000
+// - profile PCM 24-bit; MONO, STEREO; 44100, 48000
+// * "compressed offload", DIRECT|COMPRESS_OFFLOAD|NON_BLOCKING, 1 max open, 1 max active stream
+// - profile MP3; MONO, STEREO; 44100, 48000
+// * "loopback output", stream count unlimited
+// - profile PCM 24-bit; STEREO; 48000
+// * "primary input", 2 max open, 2 max active streams
+// - profile PCM 16-bit; MONO, STEREO, FRONT_BACK;
+// 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+// - profile PCM 24-bit; MONO, STEREO, FRONT_BACK;
+// 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+// * "loopback input", stream count unlimited
+// - profile PCM 24-bit; STEREO; 48000
+//
+// Routes:
+// "primary out", "compressed offload" -> "Null"
+// "primary out", "compressed offload" -> "USB Out"
+// "loopback out" -> "Loopback Out"
+// "Zero", "USB In" -> "primary input"
+// "Loopback In" -> "loopback input"
+//
+// Initial port configs:
+// * "Null" device port: PCM 24-bit; STEREO; 48000
+// * "Zero" device port: PCM 24-bit; MONO; 48000
+//
+// Profiles for device port connected state:
+// * USB Out":
+// - profile PCM 16-bit; MONO, STEREO; 44100, 48000
+// - profile PCM 24-bit; MONO, STEREO; 44100, 48000
+// * USB In":
+// - profile PCM 16-bit; MONO, STEREO; 44100, 48000
+// - profile PCM 24-bit; MONO, STEREO; 44100, 48000
+//
+Configuration& getNullPrimaryConfiguration() {
+ static Configuration configuration = []() {
+ const std::vector<AudioProfile> standardPcmAudioProfiles = {
+ createProfile(PcmType::INT_16_BIT,
+ {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
+ {44100, 48000}),
+ createProfile(PcmType::INT_24_BIT,
+ {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
+ {44100, 48000})};
+ Configuration c;
+
+ AudioPort nullOutDevice =
+ createPort(c.nextPortId++, "Null", 0, false,
+ createDeviceExt(AudioDeviceType::OUT_SPEAKER,
+ 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE));
+ c.ports.push_back(nullOutDevice);
+ c.initialConfigs.push_back(
+ createPortConfig(nullOutDevice.id, nullOutDevice.id, PcmType::INT_24_BIT,
+ AudioChannelLayout::LAYOUT_STEREO, 48000, 0, false,
+ createDeviceExt(AudioDeviceType::OUT_SPEAKER, 0)));
+
+ AudioPort primaryOutMix = createPort(c.nextPortId++, "primary output",
+ makeBitPositionFlagMask(AudioOutputFlags::PRIMARY),
+ false, createPortMixExt(1, 1));
+ primaryOutMix.profiles.insert(primaryOutMix.profiles.begin(),
+ standardPcmAudioProfiles.begin(),
+ standardPcmAudioProfiles.end());
+ c.ports.push_back(primaryOutMix);
+
+ AudioPort compressedOffloadOutMix =
+ createPort(c.nextPortId++, "compressed offload",
+ makeBitPositionFlagMask({AudioOutputFlags::DIRECT,
+ AudioOutputFlags::COMPRESS_OFFLOAD,
+ AudioOutputFlags::NON_BLOCKING}),
+ false, createPortMixExt(1, 1));
+ compressedOffloadOutMix.profiles.push_back(
+ createProfile(::android::MEDIA_MIMETYPE_AUDIO_MPEG,
+ {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
+ {44100, 48000}));
+ c.ports.push_back(compressedOffloadOutMix);
+
+ AudioPort loopOutDevice = createPort(c.nextPortId++, "Loopback Out", 0, false,
+ createDeviceExt(AudioDeviceType::OUT_SUBMIX, 0));
+ loopOutDevice.profiles.push_back(
+ createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000}));
+ c.ports.push_back(loopOutDevice);
+
+ AudioPort loopOutMix =
+ createPort(c.nextPortId++, "loopback output", 0, false, createPortMixExt(0, 0));
+ loopOutMix.profiles.push_back(
+ createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000}));
+ c.ports.push_back(loopOutMix);
+
+ AudioPort usbOutDevice =
+ createPort(c.nextPortId++, "USB Out", 0, false,
+ createDeviceExt(AudioDeviceType::OUT_DEVICE, 0,
+ AudioDeviceDescription::CONNECTION_USB));
+ c.ports.push_back(usbOutDevice);
+ c.connectedProfiles[usbOutDevice.id] = standardPcmAudioProfiles;
+
+ AudioPort zeroInDevice =
+ createPort(c.nextPortId++, "Zero", 0, true,
+ createDeviceExt(AudioDeviceType::IN_MICROPHONE,
+ 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE));
+ c.ports.push_back(zeroInDevice);
+ c.initialConfigs.push_back(
+ createPortConfig(zeroInDevice.id, zeroInDevice.id, PcmType::INT_24_BIT,
+ AudioChannelLayout::LAYOUT_MONO, 48000, 0, true,
+ createDeviceExt(AudioDeviceType::IN_MICROPHONE, 0)));
+
+ AudioPort primaryInMix =
+ createPort(c.nextPortId++, "primary input", 0, true, createPortMixExt(2, 2));
+ primaryInMix.profiles.push_back(
+ createProfile(PcmType::INT_16_BIT,
+ {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO,
+ AudioChannelLayout::LAYOUT_FRONT_BACK},
+ {8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000}));
+ primaryInMix.profiles.push_back(
+ createProfile(PcmType::INT_24_BIT,
+ {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO,
+ AudioChannelLayout::LAYOUT_FRONT_BACK},
+ {8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000}));
+ c.ports.push_back(primaryInMix);
+
+ AudioPort loopInDevice = createPort(c.nextPortId++, "Loopback In", 0, true,
+ createDeviceExt(AudioDeviceType::IN_SUBMIX, 0));
+ loopInDevice.profiles.push_back(
+ createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000}));
+ c.ports.push_back(loopInDevice);
+
+ AudioPort loopInMix =
+ createPort(c.nextPortId++, "loopback input", 0, true, createPortMixExt(0, 0));
+ loopInMix.profiles.push_back(
+ createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000}));
+ c.ports.push_back(loopInMix);
+
+ AudioPort usbInDevice = createPort(c.nextPortId++, "USB In", 0, true,
+ createDeviceExt(AudioDeviceType::IN_DEVICE, 0,
+ AudioDeviceDescription::CONNECTION_USB));
+ c.ports.push_back(usbInDevice);
+ c.connectedProfiles[usbInDevice.id] = standardPcmAudioProfiles;
+
+ c.routes.push_back(
+ createRoute({primaryOutMix.id, compressedOffloadOutMix.id}, nullOutDevice.id));
+ c.routes.push_back(
+ createRoute({primaryOutMix.id, compressedOffloadOutMix.id}, usbOutDevice.id));
+ c.routes.push_back(createRoute({loopOutMix.id}, loopOutDevice.id));
+ c.routes.push_back(createRoute({zeroInDevice.id, usbInDevice.id}, primaryInMix.id));
+ c.routes.push_back(createRoute({loopInDevice.id}, loopInMix.id));
+
+ c.portConfigs.insert(c.portConfigs.end(), c.initialConfigs.begin(), c.initialConfigs.end());
+ return c;
+ }();
+ return configuration;
+}
+
+} // namespace aidl::android::hardware::audio::core::internal
diff --git a/audio/aidl/default/EffectConfig.cpp b/audio/aidl/default/EffectConfig.cpp
new file mode 100644
index 0000000..e1427ec
--- /dev/null
+++ b/audio/aidl/default/EffectConfig.cpp
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AHAL_EffectConfig"
+#include <android-base/logging.h>
+
+#include "effectFactory-impl/EffectConfig.h"
+
+using aidl::android::media::audio::common::AudioUuid;
+
+namespace aidl::android::hardware::audio::effect {
+
+EffectConfig::EffectConfig(const std::string& file) {
+ tinyxml2::XMLDocument doc;
+ doc.LoadFile(file.c_str());
+ LOG(DEBUG) << __func__ << " loading " << file;
+ // parse the xml file into maps
+ if (doc.Error()) {
+ LOG(ERROR) << __func__ << " tinyxml2 failed to load " << file
+ << " error: " << doc.ErrorStr();
+ return;
+ }
+
+ auto registerFailure = [&](bool result) { mSkippedElements += result ? 0 : 1; };
+
+ for (auto& xmlConfig : getChildren(doc, "audio_effects_conf")) {
+ // Parse library
+ for (auto& xmlLibraries : getChildren(xmlConfig, "libraries")) {
+ for (auto& xmlLibrary : getChildren(xmlLibraries, "library")) {
+ registerFailure(parseLibrary(xmlLibrary));
+ }
+ }
+
+ // Parse effects
+ for (auto& xmlEffects : getChildren(xmlConfig, "effects")) {
+ for (auto& xmlEffect : getChildren(xmlEffects)) {
+ registerFailure(parseEffect(xmlEffect));
+ }
+ }
+
+ // Parse pre processing chains
+ for (auto& xmlPreprocess : getChildren(xmlConfig, "preprocess")) {
+ for (auto& xmlStream : getChildren(xmlPreprocess, "stream")) {
+ registerFailure(parseStream(xmlStream));
+ }
+ }
+
+ // Parse post processing chains
+ for (auto& xmlPostprocess : getChildren(xmlConfig, "postprocess")) {
+ for (auto& xmlStream : getChildren(xmlPostprocess, "stream")) {
+ registerFailure(parseStream(xmlStream));
+ }
+ }
+ }
+ LOG(DEBUG) << __func__ << " successfully parsed " << file << ", skipping " << mSkippedElements
+ << " element(s)";
+}
+
+std::vector<std::reference_wrapper<const tinyxml2::XMLElement>> EffectConfig::getChildren(
+ const tinyxml2::XMLNode& node, const char* childTag) {
+ std::vector<std::reference_wrapper<const tinyxml2::XMLElement>> children;
+ for (auto* child = node.FirstChildElement(childTag); child != nullptr;
+ child = child->NextSiblingElement(childTag)) {
+ children.emplace_back(*child);
+ }
+ return children;
+}
+
+bool EffectConfig::parseLibrary(const tinyxml2::XMLElement& xml) {
+ const char* name = xml.Attribute("name");
+ RETURN_VALUE_IF(!name, false, "noNameAttribute");
+ const char* path = xml.Attribute("path");
+ RETURN_VALUE_IF(!path, false, "noPathAttribute");
+
+ mLibraryMap[name] = path;
+ LOG(DEBUG) << __func__ << " " << name << " : " << path;
+ return true;
+}
+
+bool EffectConfig::parseEffect(const tinyxml2::XMLElement& xml) {
+ struct EffectLibraries effectLibraries;
+ std::vector<LibraryUuid> libraryUuids;
+ std::string name = xml.Attribute("name");
+ RETURN_VALUE_IF(name == "", false, "effectsNoName");
+
+ LOG(DEBUG) << __func__ << dump(xml);
+ struct LibraryUuid libraryUuid;
+ if (std::strcmp(xml.Name(), "effectProxy") == 0) {
+ // proxy lib and uuid
+ RETURN_VALUE_IF(!parseLibraryUuid(xml, libraryUuid, true), false, "parseProxyLibFailed");
+ effectLibraries.proxyLibrary = libraryUuid;
+ // proxy effect libs and UUID
+ auto xmlProxyLib = xml.FirstChildElement();
+ RETURN_VALUE_IF(!xmlProxyLib, false, "noLibForProxy");
+ while (xmlProxyLib) {
+ struct LibraryUuid tempLibraryUuid;
+ RETURN_VALUE_IF(!parseLibraryUuid(*xmlProxyLib, tempLibraryUuid), false,
+ "parseEffectLibFailed");
+ libraryUuids.push_back(std::move(tempLibraryUuid));
+ xmlProxyLib = xmlProxyLib->NextSiblingElement();
+ }
+ } else {
+ // expect only one library if not proxy
+ RETURN_VALUE_IF(!parseLibraryUuid(xml, libraryUuid), false, "parseEffectLibFailed");
+ libraryUuids.push_back(std::move(libraryUuid));
+ }
+
+ effectLibraries.libraries = std::move(libraryUuids);
+ mEffectsMap[name] = std::move(effectLibraries);
+ return true;
+}
+
+bool EffectConfig::parseStream(const tinyxml2::XMLElement& xml) {
+ LOG(DEBUG) << __func__ << dump(xml);
+ const char* type = xml.Attribute("type");
+ RETURN_VALUE_IF(!type, false, "noTypeInProcess");
+ RETURN_VALUE_IF(0 != mProcessingMap.count(type), false, "duplicateType");
+
+ for (auto& apply : getChildren(xml, "apply")) {
+ const char* name = apply.get().Attribute("effect");
+ RETURN_VALUE_IF(!name, false, "noEffectAttribute");
+ mProcessingMap[type].push_back(name);
+ LOG(DEBUG) << __func__ << " " << type << " : " << name;
+ }
+ return true;
+}
+
+bool EffectConfig::parseLibraryUuid(const tinyxml2::XMLElement& xml,
+ struct LibraryUuid& libraryUuid, bool isProxy) {
+ // Retrieve library name only if not effectProxy element
+ if (!isProxy) {
+ const char* name = xml.Attribute("library");
+ RETURN_VALUE_IF(!name, false, "noLibraryAttribute");
+ libraryUuid.name = name;
+ }
+
+ const char* uuid = xml.Attribute("uuid");
+ RETURN_VALUE_IF(!uuid, false, "noUuidAttribute");
+ RETURN_VALUE_IF(!stringToUuid(uuid, &libraryUuid.uuid), false, "invalidUuidAttribute");
+
+ LOG(DEBUG) << __func__ << (isProxy ? " proxy " : libraryUuid.name) << " : "
+ << libraryUuid.uuid.toString();
+ return true;
+}
+
+const char* EffectConfig::dump(const tinyxml2::XMLElement& element,
+ tinyxml2::XMLPrinter&& printer) const {
+ element.Accept(&printer);
+ return printer.CStr();
+}
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/EffectFactory.cpp b/audio/aidl/default/EffectFactory.cpp
new file mode 100644
index 0000000..820b447
--- /dev/null
+++ b/audio/aidl/default/EffectFactory.cpp
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AHAL_EffectFactory"
+#include <android-base/logging.h>
+#include <dlfcn.h>
+#include <unordered_set>
+
+#include "effect-impl/EffectTypes.h"
+#include "effect-impl/EffectUUID.h"
+#include "effectFactory-impl/EffectFactory.h"
+
+using aidl::android::media::audio::common::AudioUuid;
+
+namespace aidl::android::hardware::audio::effect {
+
+Factory::Factory(const std::string& file) : mConfig(EffectConfig(file)) {
+ LOG(DEBUG) << __func__ << " with config file: " << file;
+ loadEffectLibs();
+}
+
+Factory::~Factory() {
+ if (auto count = mEffectUuidMap.size()) {
+ LOG(ERROR) << __func__ << " remaining " << count
+ << " effect instances not destroyed indicating resource leak!";
+ for (const auto& it : mEffectUuidMap) {
+ if (auto spEffect = it.first.lock()) {
+ LOG(ERROR) << __func__ << " erase remaining instance UUID " << it.second.toString();
+ destroyEffectImpl(spEffect);
+ }
+ }
+ }
+}
+
+ndk::ScopedAStatus Factory::queryEffects(const std::optional<AudioUuid>& in_type_uuid,
+ const std::optional<AudioUuid>& in_impl_uuid,
+ const std::optional<AudioUuid>& in_proxy_uuid,
+ std::vector<Descriptor::Identity>* _aidl_return) {
+ std::copy_if(
+ mIdentitySet.begin(), mIdentitySet.end(), std::back_inserter(*_aidl_return),
+ [&](auto& desc) {
+ return (!in_type_uuid.has_value() || in_type_uuid.value() == desc.type) &&
+ (!in_impl_uuid.has_value() || in_impl_uuid.value() == desc.uuid) &&
+ (!in_proxy_uuid.has_value() ||
+ (desc.proxy.has_value() && in_proxy_uuid.value() == desc.proxy.value()));
+ });
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Factory::queryProcessing(const std::optional<Processing::Type>& in_type,
+ std::vector<Processing>* _aidl_return) {
+ // TODO: implement this with audio_effect.xml.
+ if (in_type.has_value()) {
+ // return all matching process filter
+ LOG(DEBUG) << __func__ << " process type: " << in_type.value().toString();
+ }
+ LOG(DEBUG) << __func__ << " return " << _aidl_return->size();
+ return ndk::ScopedAStatus::ok();
+}
+
+#define RETURN_IF_BINDER_EXCEPTION(functor) \
+ { \
+ binder_exception_t exception = functor; \
+ if (EX_NONE != exception) { \
+ LOG(ERROR) << #functor << ": failed with error " << exception; \
+ return ndk::ScopedAStatus::fromExceptionCode(exception); \
+ } \
+ }
+
+ndk::ScopedAStatus Factory::createEffect(const AudioUuid& in_impl_uuid,
+ std::shared_ptr<IEffect>* _aidl_return) {
+ LOG(DEBUG) << __func__ << ": UUID " << in_impl_uuid.toString();
+ if (mEffectLibMap.count(in_impl_uuid)) {
+ auto& lib = mEffectLibMap[in_impl_uuid];
+ // didn't do dlsym yet
+ if (nullptr == lib.second) {
+ void* libHandle = lib.first.get();
+ auto dlInterface = std::make_unique<struct effect_dl_interface_s>();
+ dlInterface->createEffectFunc = (EffectCreateFunctor)dlsym(libHandle, "createEffect");
+ dlInterface->destroyEffectFunc =
+ (EffectDestroyFunctor)dlsym(libHandle, "destroyEffect");
+ if (!dlInterface->createEffectFunc || !dlInterface->destroyEffectFunc) {
+ LOG(ERROR) << __func__
+ << ": create or destroy symbol not exist in library: " << libHandle
+ << " with dlerror: " << dlerror();
+ return ndk::ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
+ }
+ lib.second = std::move(dlInterface);
+ }
+
+ auto& libInterface = lib.second;
+ std::shared_ptr<IEffect> effectSp;
+ RETURN_IF_BINDER_EXCEPTION(libInterface->createEffectFunc(&in_impl_uuid, &effectSp));
+ if (!effectSp) {
+ LOG(ERROR) << __func__ << ": library created null instance without return error!";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
+ }
+ *_aidl_return = effectSp;
+ mEffectUuidMap[std::weak_ptr<IEffect>(effectSp)] = in_impl_uuid;
+ LOG(DEBUG) << __func__ << ": instance " << effectSp.get() << " created successfully";
+ return ndk::ScopedAStatus::ok();
+ } else {
+ LOG(ERROR) << __func__ << ": library doesn't exist";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Factory::destroyEffectImpl(const std::shared_ptr<IEffect>& in_handle) {
+ std::weak_ptr<IEffect> wpHandle(in_handle);
+ // find UUID with key (std::weak_ptr<IEffect>)
+ if (auto uuidIt = mEffectUuidMap.find(wpHandle); uuidIt != mEffectUuidMap.end()) {
+ auto& uuid = uuidIt->second;
+ // find implementation library with UUID
+ if (auto libIt = mEffectLibMap.find(uuid); libIt != mEffectLibMap.end()) {
+ if (libIt->second.second->destroyEffectFunc) {
+ RETURN_IF_BINDER_EXCEPTION(libIt->second.second->destroyEffectFunc(in_handle));
+ }
+ } else {
+ LOG(ERROR) << __func__ << ": UUID " << uuid.toString() << " does not exist in libMap!";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ mEffectUuidMap.erase(uuidIt);
+ return ndk::ScopedAStatus::ok();
+ } else {
+ LOG(ERROR) << __func__ << ": instance " << in_handle << " does not exist!";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+}
+
+// go over the map and cleanup all expired weak_ptrs.
+void Factory::cleanupEffectMap() {
+ for (auto it = mEffectUuidMap.begin(); it != mEffectUuidMap.end();) {
+ if (nullptr == it->first.lock()) {
+ it = mEffectUuidMap.erase(it);
+ } else {
+ ++it;
+ }
+ }
+}
+
+ndk::ScopedAStatus Factory::destroyEffect(const std::shared_ptr<IEffect>& in_handle) {
+ LOG(DEBUG) << __func__ << ": instance " << in_handle.get();
+ ndk::ScopedAStatus status = destroyEffectImpl(in_handle);
+ // always do the cleanup
+ cleanupEffectMap();
+ return status;
+}
+
+void Factory::openEffectLibrary(const AudioUuid& impl, const std::string& libName) {
+ std::function<void(void*)> dlClose = [](void* handle) -> void {
+ if (handle && dlclose(handle)) {
+ LOG(ERROR) << "dlclose failed " << dlerror();
+ }
+ };
+
+ auto libHandle =
+ std::unique_ptr<void, decltype(dlClose)>{dlopen(libName.c_str(), RTLD_LAZY), dlClose};
+ if (!libHandle) {
+ LOG(ERROR) << __func__ << ": dlopen failed, err: " << dlerror();
+ return;
+ }
+
+ LOG(DEBUG) << __func__ << " dlopen lib:" << libName << "\nimpl:" << impl.toString()
+ << "\nhandle:" << libHandle;
+ mEffectLibMap.insert({impl, std::make_pair(std::move(libHandle), nullptr)});
+}
+
+void Factory::createIdentityWithConfig(const EffectConfig::LibraryUuid& configLib,
+ const AudioUuid& typeUuid,
+ const std::optional<AudioUuid> proxyUuid) {
+ static const auto& libMap = mConfig.getLibraryMap();
+ const std::string& libName = configLib.name;
+ if (auto path = libMap.find(libName); path != libMap.end()) {
+ Descriptor::Identity id;
+ id.type = typeUuid;
+ id.uuid = configLib.uuid;
+ id.proxy = proxyUuid;
+ LOG(DEBUG) << __func__ << ": typeUuid " << id.type.toString() << "\nimplUuid "
+ << id.uuid.toString() << " proxyUuid "
+ << (proxyUuid.has_value() ? proxyUuid->toString() : "null");
+ openEffectLibrary(id.uuid, path->second);
+ mIdentitySet.insert(std::move(id));
+ } else {
+ LOG(ERROR) << __func__ << ": library " << libName << " not exist!";
+ return;
+ }
+}
+
+void Factory::loadEffectLibs() {
+ const auto& configEffectsMap = mConfig.getEffectsMap();
+ for (const auto& configEffects : configEffectsMap) {
+ if (auto typeUuid = kUuidNameTypeMap.find(configEffects.first /* effect name */);
+ typeUuid != kUuidNameTypeMap.end()) {
+ const auto& configLibs = configEffects.second;
+ std::optional<AudioUuid> proxyUuid;
+ if (configLibs.proxyLibrary.has_value()) {
+ const auto& proxyLib = configLibs.proxyLibrary.value();
+ proxyUuid = proxyLib.uuid;
+ }
+ for (const auto& configLib : configLibs.libraries) {
+ createIdentityWithConfig(configLib, typeUuid->second, proxyUuid);
+ }
+ } else {
+ LOG(ERROR) << __func__ << ": can not find type UUID for effect " << configEffects.first
+ << " skipping!";
+ }
+ }
+}
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/EffectImpl.cpp b/audio/aidl/default/EffectImpl.cpp
new file mode 100644
index 0000000..2754bb6
--- /dev/null
+++ b/audio/aidl/default/EffectImpl.cpp
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AHAL_EffectImpl"
+#include "effect-impl/EffectImpl.h"
+#include "effect-impl/EffectTypes.h"
+#include "include/effect-impl/EffectTypes.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+ndk::ScopedAStatus EffectImpl::open(const Parameter::Common& common,
+ const std::optional<Parameter::Specific>& specific,
+ OpenEffectReturn* ret) {
+ LOG(DEBUG) << __func__;
+ {
+ std::lock_guard lg(mMutex);
+ RETURN_OK_IF(mState != State::INIT);
+ mContext = createContext(common);
+ RETURN_IF(!mContext, EX_ILLEGAL_ARGUMENT, "createContextFailed");
+ setContext(mContext);
+ }
+
+ RETURN_IF_ASTATUS_NOT_OK(setParameterCommon(common), "setCommParamErr");
+ if (specific.has_value()) {
+ RETURN_IF_ASTATUS_NOT_OK(setParameterSpecific(specific.value()), "setSpecParamErr");
+ }
+
+ RETURN_IF(createThread(LOG_TAG) != RetCode::SUCCESS, EX_UNSUPPORTED_OPERATION,
+ "FailedToCreateWorker");
+
+ {
+ std::lock_guard lg(mMutex);
+ mContext->dupeFmq(ret);
+ mState = State::IDLE;
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EffectImpl::close() {
+ std::lock_guard lg(mMutex);
+ RETURN_OK_IF(mState == State::INIT);
+ RETURN_IF(mState == State::PROCESSING, EX_ILLEGAL_STATE, "closeAtProcessing");
+
+ // stop the worker thread, ignore the return code
+ RETURN_IF(destroyThread() != RetCode::SUCCESS, EX_UNSUPPORTED_OPERATION,
+ "FailedToDestroyWorker");
+ RETURN_IF(releaseContext() != RetCode::SUCCESS, EX_UNSUPPORTED_OPERATION,
+ "FailedToCreateWorker");
+ mState = State::INIT;
+ LOG(DEBUG) << __func__;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EffectImpl::setParameter(const Parameter& param) {
+ LOG(DEBUG) << __func__ << " with: " << param.toString();
+
+ auto tag = param.getTag();
+ switch (tag) {
+ case Parameter::common:
+ case Parameter::deviceDescription:
+ case Parameter::mode:
+ case Parameter::source:
+ FALLTHROUGH_INTENDED;
+ case Parameter::volumeStereo:
+ return setParameterCommon(param);
+ case Parameter::specific: {
+ return setParameterSpecific(param.get<Parameter::specific>());
+ }
+ default: {
+ LOG(ERROR) << __func__ << " unsupportedParameterTag " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "ParameterNotSupported");
+ }
+ }
+}
+
+ndk::ScopedAStatus EffectImpl::getParameter(const Parameter::Id& id, Parameter* param) {
+ LOG(DEBUG) << __func__ << id.toString();
+ auto tag = id.getTag();
+ switch (tag) {
+ case Parameter::Id::commonTag: {
+ RETURN_IF_ASTATUS_NOT_OK(getParameterCommon(id.get<Parameter::Id::commonTag>(), param),
+ "CommonParamNotSupported");
+ break;
+ }
+ case Parameter::Id::vendorEffectTag: {
+ LOG(DEBUG) << __func__ << " noop for vendor tag";
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "vendortagNotSupported");
+ }
+ default: {
+ Parameter::Specific specific;
+ RETURN_IF_ASTATUS_NOT_OK(getParameterSpecific(id, &specific), "SpecParamNotSupported");
+ param->set<Parameter::specific>(specific);
+ break;
+ }
+ }
+ LOG(DEBUG) << __func__ << param->toString();
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EffectImpl::setParameterCommon(const Parameter& param) {
+ std::lock_guard lg(mMutex);
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+ auto tag = param.getTag();
+ switch (tag) {
+ case Parameter::common:
+ RETURN_IF(mContext->setCommon(param.get<Parameter::common>()) != RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setCommFailed");
+ break;
+ case Parameter::deviceDescription:
+ RETURN_IF(mContext->setOutputDevice(param.get<Parameter::deviceDescription>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setDeviceFailed");
+ break;
+ case Parameter::mode:
+ RETURN_IF(mContext->setAudioMode(param.get<Parameter::mode>()) != RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setModeFailed");
+ break;
+ case Parameter::source:
+ RETURN_IF(mContext->setAudioSource(param.get<Parameter::source>()) != RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setSourceFailed");
+ break;
+ case Parameter::volumeStereo:
+ RETURN_IF(mContext->setVolumeStereo(param.get<Parameter::volumeStereo>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setVolumeStereoFailed");
+ break;
+ default: {
+ LOG(ERROR) << __func__ << " unsupportedParameterTag " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "commonParamNotSupported");
+ }
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EffectImpl::getParameterCommon(const Parameter::Tag& tag, Parameter* param) {
+ std::lock_guard lg(mMutex);
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+ switch (tag) {
+ case Parameter::common: {
+ param->set<Parameter::common>(mContext->getCommon());
+ break;
+ }
+ case Parameter::deviceDescription: {
+ param->set<Parameter::deviceDescription>(mContext->getOutputDevice());
+ break;
+ }
+ case Parameter::mode: {
+ param->set<Parameter::mode>(mContext->getAudioMode());
+ break;
+ }
+ case Parameter::source: {
+ param->set<Parameter::source>(mContext->getAudioSource());
+ break;
+ }
+ case Parameter::volumeStereo: {
+ param->set<Parameter::volumeStereo>(mContext->getVolumeStereo());
+ break;
+ }
+ default: {
+ LOG(DEBUG) << __func__ << " unsupported tag " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "tagNotSupported");
+ }
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EffectImpl::getState(State* state) {
+ std::lock_guard lg(mMutex);
+ *state = mState;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EffectImpl::command(CommandId command) {
+ std::lock_guard lg(mMutex);
+ LOG(DEBUG) << __func__ << ": receive command: " << toString(command) << " at state "
+ << toString(mState);
+ RETURN_IF(mState == State::INIT, EX_ILLEGAL_STATE, "CommandStateError");
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+ switch (command) {
+ case CommandId::START:
+ RETURN_IF(mState == State::INIT, EX_ILLEGAL_STATE, "instanceNotOpen");
+ RETURN_OK_IF(mState == State::PROCESSING);
+ RETURN_IF_ASTATUS_NOT_OK(commandStart(), "commandStartFailed");
+ mState = State::PROCESSING;
+ startThread();
+ return ndk::ScopedAStatus::ok();
+ case CommandId::STOP:
+ RETURN_OK_IF(mState == State::IDLE);
+ mState = State::IDLE;
+ RETURN_IF_ASTATUS_NOT_OK(commandStop(), "commandStopFailed");
+ stopThread();
+ return ndk::ScopedAStatus::ok();
+ case CommandId::RESET:
+ RETURN_OK_IF(mState == State::IDLE);
+ mState = State::IDLE;
+ RETURN_IF_ASTATUS_NOT_OK(commandStop(), "commandStopFailed");
+ stopThread();
+ mContext->resetBuffer();
+ return ndk::ScopedAStatus::ok();
+ default:
+ LOG(ERROR) << __func__ << " instance still processing";
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "CommandIdNotSupported");
+ }
+ LOG(DEBUG) << __func__ << " transfer to state: " << toString(mState);
+ return ndk::ScopedAStatus::ok();
+}
+
+void EffectImpl::cleanUp() {
+ command(CommandId::STOP);
+ close();
+}
+
+IEffect::Status EffectImpl::status(binder_status_t status, size_t consumed, size_t produced) {
+ IEffect::Status ret;
+ ret.status = status;
+ ret.fmqConsumed = consumed;
+ ret.fmqProduced = produced;
+ return ret;
+}
+
+// A placeholder processing implementation to copy samples from input to output
+IEffect::Status EffectImpl::effectProcessImpl(float* in, float* out, int processSamples) {
+ // lock before access context/parameters
+ std::lock_guard lg(mMutex);
+ IEffect::Status status = {EX_NULL_POINTER, 0, 0};
+ RETURN_VALUE_IF(!mContext, status, "nullContext");
+ auto frameSize = mContext->getInputFrameSize();
+ RETURN_VALUE_IF(0 == frameSize, status, "frameSizeIs0");
+ LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << processSamples
+ << " frames " << processSamples * sizeof(float) / frameSize;
+ for (int i = 0; i < processSamples; i++) {
+ *out++ = *in++;
+ }
+ LOG(DEBUG) << __func__ << " done processing " << processSamples << " samples";
+ return {STATUS_OK, processSamples, processSamples};
+}
+} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/EffectMain.cpp b/audio/aidl/default/EffectMain.cpp
new file mode 100644
index 0000000..ca81204
--- /dev/null
+++ b/audio/aidl/default/EffectMain.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "effectFactory-impl/EffectFactory.h"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <system/audio_config.h>
+
+/** Default name of effect configuration file. */
+static const char* kDefaultConfigName = "audio_effects_config.xml";
+
+int main() {
+ // This is a debug implementation, always enable debug logging.
+ android::base::SetMinimumLogSeverity(::android::base::DEBUG);
+ ABinderProcess_setThreadPoolMaxThreadCount(0);
+
+ auto configFile = android::audio_find_readable_configuration_file(kDefaultConfigName);
+ if (configFile == "") {
+ LOG(ERROR) << __func__ << ": config file " << kDefaultConfigName << " not found!";
+ return EXIT_FAILURE;
+ }
+ LOG(DEBUG) << __func__ << ": start factory with configFile:" << configFile;
+ auto effectFactory =
+ ndk::SharedRefBase::make<aidl::android::hardware::audio::effect::Factory>(configFile);
+
+ std::string serviceName = std::string() + effectFactory->descriptor + "/default";
+ binder_status_t status =
+ AServiceManager_addService(effectFactory->asBinder().get(), serviceName.c_str());
+ CHECK_EQ(STATUS_OK, status);
+
+ LOG(DEBUG) << __func__ << ": effectFactory: " << serviceName << " start";
+ ABinderProcess_joinThreadPool();
+ return EXIT_FAILURE; // should not reach
+}
diff --git a/audio/aidl/default/EffectThread.cpp b/audio/aidl/default/EffectThread.cpp
new file mode 100644
index 0000000..80f120b
--- /dev/null
+++ b/audio/aidl/default/EffectThread.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AHAL_EffectThread"
+#include <android-base/logging.h>
+#include <pthread.h>
+#include <sys/resource.h>
+
+#include "effect-impl/EffectThread.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+EffectThread::EffectThread() {
+ LOG(DEBUG) << __func__;
+}
+
+EffectThread::~EffectThread() {
+ destroyThread();
+ LOG(DEBUG) << __func__ << " done";
+};
+
+RetCode EffectThread::createThread(const std::string& name, const int priority) {
+ if (mThread.joinable()) {
+ LOG(WARNING) << __func__ << " thread already created, no-op";
+ return RetCode::SUCCESS;
+ }
+ mName = name;
+ mPriority = priority;
+ mThread = std::thread(&EffectThread::threadLoop, this);
+ LOG(DEBUG) << __func__ << " " << name << " priority " << mPriority << " done";
+ return RetCode::SUCCESS;
+}
+
+RetCode EffectThread::destroyThread() {
+ {
+ std::lock_guard lg(mMutex);
+ mStop = mExit = true;
+ }
+ mCv.notify_one();
+
+ if (mThread.joinable()) {
+ mThread.join();
+ }
+ LOG(DEBUG) << __func__ << " done";
+ return RetCode::SUCCESS;
+}
+
+RetCode EffectThread::startThread() {
+ if (!mThread.joinable()) {
+ LOG(ERROR) << __func__ << " thread already destroyed";
+ return RetCode::ERROR_THREAD;
+ }
+
+ {
+ std::lock_guard lg(mMutex);
+ if (!mStop) {
+ LOG(WARNING) << __func__ << " already start";
+ return RetCode::SUCCESS;
+ }
+ mStop = false;
+ }
+
+ mCv.notify_one();
+ LOG(DEBUG) << __func__ << " done";
+ return RetCode::SUCCESS;
+}
+
+RetCode EffectThread::stopThread() {
+ if (!mThread.joinable()) {
+ LOG(ERROR) << __func__ << " thread already destroyed";
+ return RetCode::ERROR_THREAD;
+ }
+
+ {
+ std::lock_guard lg(mMutex);
+ if (mStop) {
+ LOG(WARNING) << __func__ << " already stop";
+ return RetCode::SUCCESS;
+ }
+ mStop = true;
+ }
+ LOG(DEBUG) << __func__ << " done";
+ return RetCode::SUCCESS;
+}
+
+void EffectThread::threadLoop() {
+ pthread_setname_np(pthread_self(), mName.substr(0, MAX_TASK_COMM_LEN - 1).c_str());
+ setpriority(PRIO_PROCESS, 0, mPriority);
+ while (true) {
+ bool needExit = false;
+ {
+ std::unique_lock l(mMutex);
+ mCv.wait(l, [&]() REQUIRES(mMutex) {
+ needExit = mExit;
+ return mExit || !mStop;
+ });
+ }
+ if (needExit) {
+ LOG(WARNING) << __func__ << " EXIT!";
+ return;
+ }
+ // process without lock
+ process();
+ }
+}
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp
new file mode 100644
index 0000000..9dbd61c
--- /dev/null
+++ b/audio/aidl/default/Module.cpp
@@ -0,0 +1,863 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <algorithm>
+#include <set>
+
+#define LOG_TAG "AHAL_Module"
+#include <android-base/logging.h>
+
+#include <Utils.h>
+#include <aidl/android/media/audio/common/AudioInputFlags.h>
+#include <aidl/android/media/audio/common/AudioOutputFlags.h>
+
+#include "core-impl/Module.h"
+#include "core-impl/Telephony.h"
+#include "core-impl/utils.h"
+
+using aidl::android::hardware::audio::common::SinkMetadata;
+using aidl::android::hardware::audio::common::SourceMetadata;
+using aidl::android::media::audio::common::AudioChannelLayout;
+using aidl::android::media::audio::common::AudioFormatDescription;
+using aidl::android::media::audio::common::AudioFormatType;
+using aidl::android::media::audio::common::AudioInputFlags;
+using aidl::android::media::audio::common::AudioIoFlags;
+using aidl::android::media::audio::common::AudioOffloadInfo;
+using aidl::android::media::audio::common::AudioOutputFlags;
+using aidl::android::media::audio::common::AudioPort;
+using aidl::android::media::audio::common::AudioPortConfig;
+using aidl::android::media::audio::common::AudioPortExt;
+using aidl::android::media::audio::common::AudioProfile;
+using aidl::android::media::audio::common::Int;
+using aidl::android::media::audio::common::PcmType;
+using android::hardware::audio::common::getFrameSizeInBytes;
+using android::hardware::audio::common::isBitPositionFlagSet;
+
+namespace aidl::android::hardware::audio::core {
+
+namespace {
+
+bool generateDefaultPortConfig(const AudioPort& port, AudioPortConfig* config) {
+ *config = {};
+ config->portId = port.id;
+ if (port.profiles.empty()) {
+ LOG(ERROR) << __func__ << ": port " << port.id << " has no profiles";
+ return false;
+ }
+ const auto& profile = port.profiles.begin();
+ config->format = profile->format;
+ if (profile->channelMasks.empty()) {
+ LOG(ERROR) << __func__ << ": the first profile in port " << port.id
+ << " has no channel masks";
+ return false;
+ }
+ config->channelMask = *profile->channelMasks.begin();
+ if (profile->sampleRates.empty()) {
+ LOG(ERROR) << __func__ << ": the first profile in port " << port.id
+ << " has no sample rates";
+ return false;
+ }
+ Int sampleRate;
+ sampleRate.value = *profile->sampleRates.begin();
+ config->sampleRate = sampleRate;
+ config->flags = port.flags;
+ config->ext = port.ext;
+ return true;
+}
+
+bool findAudioProfile(const AudioPort& port, const AudioFormatDescription& format,
+ AudioProfile* profile) {
+ if (auto profilesIt =
+ find_if(port.profiles.begin(), port.profiles.end(),
+ [&format](const auto& profile) { return profile.format == format; });
+ profilesIt != port.profiles.end()) {
+ *profile = *profilesIt;
+ return true;
+ }
+ return false;
+}
+
+} // namespace
+
+void Module::cleanUpPatch(int32_t patchId) {
+ erase_all_values(mPatches, std::set<int32_t>{patchId});
+}
+
+ndk::ScopedAStatus Module::createStreamContext(int32_t in_portConfigId, int64_t in_bufferSizeFrames,
+ std::shared_ptr<IStreamCallback> asyncCallback,
+ StreamContext* out_context) {
+ if (in_bufferSizeFrames <= 0) {
+ LOG(ERROR) << __func__ << ": non-positive buffer size " << in_bufferSizeFrames;
+ 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 size_t frameSize =
+ getFrameSizeInBytes(portConfigIt->format.value(), portConfigIt->channelMask.value());
+ if (frameSize == 0) {
+ LOG(ERROR) << __func__ << ": could not calculate frame size for port config "
+ << portConfigIt->toString();
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ LOG(DEBUG) << __func__ << ": frame size " << frameSize << " bytes";
+ if (frameSize > kMaximumStreamBufferSizeBytes / in_bufferSizeFrames) {
+ LOG(ERROR) << __func__ << ": buffer size " << in_bufferSizeFrames
+ << " frames is too large, maximum size is "
+ << kMaximumStreamBufferSizeBytes / frameSize;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ const auto& flags = portConfigIt->flags.value();
+ if ((flags.getTag() == AudioIoFlags::Tag::input &&
+ !isBitPositionFlagSet(flags.get<AudioIoFlags::Tag::input>(),
+ AudioInputFlags::MMAP_NOIRQ)) ||
+ (flags.getTag() == AudioIoFlags::Tag::output &&
+ !isBitPositionFlagSet(flags.get<AudioIoFlags::Tag::output>(),
+ AudioOutputFlags::MMAP_NOIRQ))) {
+ StreamContext temp(
+ std::make_unique<StreamContext::CommandMQ>(1, true /*configureEventFlagWord*/),
+ std::make_unique<StreamContext::ReplyMQ>(1, true /*configureEventFlagWord*/),
+ frameSize, std::make_unique<StreamContext::DataMQ>(frameSize * in_bufferSizeFrames),
+ asyncCallback, mDebug.streamTransientStateDelayMs);
+ if (temp.isValid()) {
+ *out_context = std::move(temp);
+ } else {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
+ } else {
+ // TODO: Implement simulation of MMAP buffer allocation
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::findPortIdForNewStream(int32_t in_portConfigId, AudioPort** port) {
+ auto& configs = getConfig().portConfigs;
+ auto portConfigIt = findById<AudioPortConfig>(configs, in_portConfigId);
+ if (portConfigIt == configs.end()) {
+ LOG(ERROR) << __func__ << ": existing port config id " << in_portConfigId << " not found";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ const int32_t portId = portConfigIt->portId;
+ // In our implementation, configs of mix ports always have unique IDs.
+ CHECK(portId != in_portConfigId);
+ auto& ports = getConfig().ports;
+ auto portIt = findById<AudioPort>(ports, portId);
+ if (portIt == ports.end()) {
+ LOG(ERROR) << __func__ << ": port id " << portId << " used by port config id "
+ << in_portConfigId << " not found";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ if (mStreams.count(in_portConfigId) != 0) {
+ LOG(ERROR) << __func__ << ": port config id " << in_portConfigId
+ << " already has a stream opened on it";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
+ if (portIt->ext.getTag() != AudioPortExt::Tag::mix) {
+ LOG(ERROR) << __func__ << ": port config id " << in_portConfigId
+ << " does not correspond to a mix port";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ const int32_t maxOpenStreamCount = portIt->ext.get<AudioPortExt::Tag::mix>().maxOpenStreamCount;
+ if (maxOpenStreamCount != 0 && mStreams.count(portId) >= maxOpenStreamCount) {
+ LOG(ERROR) << __func__ << ": port id " << portId
+ << " has already reached maximum allowed opened stream count: "
+ << maxOpenStreamCount;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
+ *port = &(*portIt);
+ return ndk::ScopedAStatus::ok();
+}
+
+internal::Configuration& Module::getConfig() {
+ if (!mConfig) {
+ mConfig.reset(new internal::Configuration(internal::getNullPrimaryConfiguration()));
+ }
+ return *mConfig;
+}
+
+void Module::registerPatch(const AudioPatch& patch) {
+ auto& configs = getConfig().portConfigs;
+ auto do_insert = [&](const std::vector<int32_t>& portConfigIds) {
+ for (auto portConfigId : portConfigIds) {
+ auto configIt = findById<AudioPortConfig>(configs, portConfigId);
+ if (configIt != configs.end()) {
+ mPatches.insert(std::pair{portConfigId, patch.id});
+ if (configIt->portId != portConfigId) {
+ mPatches.insert(std::pair{configIt->portId, patch.id});
+ }
+ }
+ };
+ };
+ do_insert(patch.sourcePortConfigIds);
+ do_insert(patch.sinkPortConfigIds);
+}
+
+void 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.
+ std::set<int32_t> idsToDisconnect, idsToConnect;
+ 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.setStreamIsConnected(portConfigId, false);
+ }
+ });
+ std::for_each(idsToConnect.begin(), idsToConnect.end(), [&](const auto& portConfigId) {
+ if (idsToDisconnect.count(portConfigId) == 0) {
+ mStreams.setStreamIsConnected(portConfigId, true);
+ }
+ });
+}
+
+ndk::ScopedAStatus Module::setModuleDebug(
+ const ::aidl::android::hardware::audio::core::ModuleDebug& in_debug) {
+ LOG(DEBUG) << __func__ << ": old flags:" << mDebug.toString()
+ << ", new flags: " << in_debug.toString();
+ if (mDebug.simulateDeviceConnections != in_debug.simulateDeviceConnections &&
+ !mConnectedDevicePorts.empty()) {
+ LOG(ERROR) << __func__ << ": attempting to change device connections simulation "
+ << "while having external devices connected";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
+ if (in_debug.streamTransientStateDelayMs < 0) {
+ LOG(ERROR) << __func__ << ": streamTransientStateDelayMs is negative: "
+ << in_debug.streamTransientStateDelayMs;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ mDebug = in_debug;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::getTelephony(std::shared_ptr<ITelephony>* _aidl_return) {
+ if (mTelephony == nullptr) {
+ mTelephony = ndk::SharedRefBase::make<Telephony>();
+ }
+ *_aidl_return = mTelephony;
+ LOG(DEBUG) << __func__ << ": returning instance of ITelephony: " << _aidl_return->get();
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::connectExternalDevice(const AudioPort& in_templateIdAndAdditionalData,
+ AudioPort* _aidl_return) {
+ const int32_t templateId = in_templateIdAndAdditionalData.id;
+ auto& ports = getConfig().ports;
+ AudioPort connectedPort;
+ { // Scope the template port so that we don't accidentally modify it.
+ auto templateIt = findById<AudioPort>(ports, templateId);
+ if (templateIt == ports.end()) {
+ LOG(ERROR) << __func__ << ": port id " << templateId << " not found";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ if (templateIt->ext.getTag() != AudioPortExt::Tag::device) {
+ LOG(ERROR) << __func__ << ": port id " << templateId << " is not a device port";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ if (!templateIt->profiles.empty()) {
+ LOG(ERROR) << __func__ << ": port id " << templateId
+ << " does not have dynamic profiles";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ auto& templateDevicePort = templateIt->ext.get<AudioPortExt::Tag::device>();
+ if (templateDevicePort.device.type.connection.empty()) {
+ LOG(ERROR) << __func__ << ": port id " << templateId << " is permanently attached";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ // Postpone id allocation until we ensure that there are no client errors.
+ connectedPort = *templateIt;
+ connectedPort.extraAudioDescriptors = in_templateIdAndAdditionalData.extraAudioDescriptors;
+ const auto& inputDevicePort =
+ in_templateIdAndAdditionalData.ext.get<AudioPortExt::Tag::device>();
+ auto& connectedDevicePort = connectedPort.ext.get<AudioPortExt::Tag::device>();
+ connectedDevicePort.device.address = inputDevicePort.device.address;
+ LOG(DEBUG) << __func__ << ": device port " << connectedPort.id << " device set to "
+ << connectedDevicePort.device.toString();
+ // Check if there is already a connected port with for the same external device.
+ for (auto connectedPortId : mConnectedDevicePorts) {
+ auto connectedPortIt = findById<AudioPort>(ports, connectedPortId);
+ if (connectedPortIt->ext.get<AudioPortExt::Tag::device>().device ==
+ connectedDevicePort.device) {
+ LOG(ERROR) << __func__ << ": device " << connectedDevicePort.device.toString()
+ << " is already connected at the device port id " << connectedPortId;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
+ }
+ }
+
+ if (!mDebug.simulateDeviceConnections) {
+ // In a real HAL here we would attempt querying the profiles from the device.
+ LOG(ERROR) << __func__ << ": failed to query supported device profiles";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
+
+ connectedPort.id = ++getConfig().nextPortId;
+ mConnectedDevicePorts.insert(connectedPort.id);
+ LOG(DEBUG) << __func__ << ": template port " << templateId << " external device connected, "
+ << "connected port ID " << connectedPort.id;
+ auto& connectedProfiles = getConfig().connectedProfiles;
+ if (auto connectedProfilesIt = connectedProfiles.find(templateId);
+ connectedProfilesIt != connectedProfiles.end()) {
+ connectedPort.profiles = connectedProfilesIt->second;
+ }
+ ports.push_back(connectedPort);
+ *_aidl_return = std::move(connectedPort);
+
+ 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));
+ } else {
+ auto& srcs = r.sourcePortIds;
+ if (std::find(srcs.begin(), srcs.end(), templateId) != srcs.end()) {
+ srcs.push_back(connectedPort.id);
+ }
+ }
+ }
+ routes.insert(routes.end(), newRoutes.begin(), newRoutes.end());
+
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::disconnectExternalDevice(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);
+ }
+ if (mConnectedDevicePorts.count(in_portId) == 0) {
+ LOG(ERROR) << __func__ << ": port id " << in_portId << " is not a connected device port";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ auto& configs = getConfig().portConfigs;
+ auto& initials = getConfig().initialConfigs;
+ auto configIt = std::find_if(configs.begin(), configs.end(), [&](const auto& config) {
+ if (config.portId == in_portId) {
+ // Check if the configuration was provided by the client.
+ const auto& initialIt = findById<AudioPortConfig>(initials, config.id);
+ return initialIt == initials.end() || config != *initialIt;
+ }
+ return false;
+ });
+ if (configIt != configs.end()) {
+ LOG(ERROR) << __func__ << ": port id " << in_portId << " has a non-default config with id "
+ << configIt->id;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
+ ports.erase(portIt);
+ mConnectedDevicePorts.erase(in_portId);
+ LOG(DEBUG) << __func__ << ": connected device port " << in_portId << " released";
+
+ auto& routes = getConfig().routes;
+ for (auto routesIt = routes.begin(); routesIt != routes.end();) {
+ if (routesIt->sinkPortId == in_portId) {
+ routesIt = routes.erase(routesIt);
+ } else {
+ // Note: the list of sourcePortIds can't become empty because there must
+ // be the id of the template port in the route.
+ erase_if(routesIt->sourcePortIds, [in_portId](auto src) { return src == in_portId; });
+ ++routesIt;
+ }
+ }
+
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::getAudioPatches(std::vector<AudioPatch>* _aidl_return) {
+ *_aidl_return = getConfig().patches;
+ LOG(DEBUG) << __func__ << ": returning " << _aidl_return->size() << " patches";
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::getAudioPort(int32_t in_portId, AudioPort* _aidl_return) {
+ auto& ports = getConfig().ports;
+ auto portIt = findById<AudioPort>(ports, in_portId);
+ if (portIt != ports.end()) {
+ *_aidl_return = *portIt;
+ LOG(DEBUG) << __func__ << ": returning port by id " << in_portId;
+ return ndk::ScopedAStatus::ok();
+ }
+ LOG(ERROR) << __func__ << ": port id " << in_portId << " not found";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+}
+
+ndk::ScopedAStatus Module::getAudioPortConfigs(std::vector<AudioPortConfig>* _aidl_return) {
+ *_aidl_return = getConfig().portConfigs;
+ LOG(DEBUG) << __func__ << ": returning " << _aidl_return->size() << " port configs";
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::getAudioPorts(std::vector<AudioPort>* _aidl_return) {
+ *_aidl_return = getConfig().ports;
+ LOG(DEBUG) << __func__ << ": returning " << _aidl_return->size() << " ports";
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::getAudioRoutes(std::vector<AudioRoute>* _aidl_return) {
+ *_aidl_return = getConfig().routes;
+ LOG(DEBUG) << __func__ << ": returning " << _aidl_return->size() << " routes";
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::getAudioRoutesForAudioPort(int32_t in_portId,
+ std::vector<AudioRoute>* _aidl_return) {
+ auto& ports = getConfig().ports;
+ if (auto portIt = findById<AudioPort>(ports, in_portId); portIt == ports.end()) {
+ 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();
+ });
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::openInputStream(const OpenInputStreamArguments& in_args,
+ OpenInputStreamReturn* _aidl_return) {
+ LOG(DEBUG) << __func__ << ": port config id " << in_args.portConfigId << ", buffer size "
+ << in_args.bufferSizeFrames << " frames";
+ AudioPort* port = nullptr;
+ if (auto status = findPortIdForNewStream(in_args.portConfigId, &port); !status.isOk()) {
+ return status;
+ }
+ if (port->flags.getTag() != AudioIoFlags::Tag::input) {
+ LOG(ERROR) << __func__ << ": port config id " << in_args.portConfigId
+ << " does not correspond to an input mix port";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ StreamContext context;
+ if (auto status = createStreamContext(in_args.portConfigId, in_args.bufferSizeFrames, nullptr,
+ &context);
+ !status.isOk()) {
+ return status;
+ }
+ context.fillDescriptor(&_aidl_return->desc);
+ auto stream = ndk::SharedRefBase::make<StreamIn>(in_args.sinkMetadata, std::move(context));
+ if (auto status = stream->init(); !status.isOk()) {
+ return status;
+ }
+ StreamWrapper streamWrapper(stream);
+ auto patchIt = mPatches.find(in_args.portConfigId);
+ if (patchIt != mPatches.end()) {
+ streamWrapper.setStreamIsConnected(true);
+ }
+ mStreams.insert(port->id, in_args.portConfigId, std::move(streamWrapper));
+ _aidl_return->stream = std::move(stream);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::openOutputStream(const OpenOutputStreamArguments& in_args,
+ OpenOutputStreamReturn* _aidl_return) {
+ LOG(DEBUG) << __func__ << ": port config id " << in_args.portConfigId << ", has offload info? "
+ << (in_args.offloadInfo.has_value()) << ", buffer size " << in_args.bufferSizeFrames
+ << " frames";
+ AudioPort* port = nullptr;
+ if (auto status = findPortIdForNewStream(in_args.portConfigId, &port); !status.isOk()) {
+ return status;
+ }
+ if (port->flags.getTag() != AudioIoFlags::Tag::output) {
+ LOG(ERROR) << __func__ << ": port config id " << in_args.portConfigId
+ << " does not correspond to an output mix port";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ const bool isOffload = isBitPositionFlagSet(port->flags.get<AudioIoFlags::Tag::output>(),
+ AudioOutputFlags::COMPRESS_OFFLOAD);
+ if (isOffload && !in_args.offloadInfo.has_value()) {
+ LOG(ERROR) << __func__ << ": port id " << port->id
+ << " has COMPRESS_OFFLOAD flag set, requires offload info";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ const bool isNonBlocking = isBitPositionFlagSet(port->flags.get<AudioIoFlags::Tag::output>(),
+ AudioOutputFlags::NON_BLOCKING);
+ if (isNonBlocking && in_args.callback == nullptr) {
+ LOG(ERROR) << __func__ << ": port id " << port->id
+ << " has NON_BLOCKING flag set, requires async callback";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ StreamContext context;
+ if (auto status = createStreamContext(in_args.portConfigId, in_args.bufferSizeFrames,
+ isNonBlocking ? in_args.callback : nullptr, &context);
+ !status.isOk()) {
+ return status;
+ }
+ context.fillDescriptor(&_aidl_return->desc);
+ auto stream = ndk::SharedRefBase::make<StreamOut>(in_args.sourceMetadata, std::move(context),
+ in_args.offloadInfo);
+ if (auto status = stream->init(); !status.isOk()) {
+ return status;
+ }
+ StreamWrapper streamWrapper(stream);
+ auto patchIt = mPatches.find(in_args.portConfigId);
+ if (patchIt != mPatches.end()) {
+ streamWrapper.setStreamIsConnected(true);
+ }
+ mStreams.insert(port->id, in_args.portConfigId, std::move(streamWrapper));
+ _aidl_return->stream = std::move(stream);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::setAudioPatch(const AudioPatch& in_requested, AudioPatch* _aidl_return) {
+ LOG(DEBUG) << __func__ << ": requested patch " << in_requested.toString();
+ if (in_requested.sourcePortConfigIds.empty()) {
+ LOG(ERROR) << __func__ << ": requested patch has empty sources list";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ if (!all_unique<int32_t>(in_requested.sourcePortConfigIds)) {
+ LOG(ERROR) << __func__ << ": requested patch has duplicate ids in the sources list";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ if (in_requested.sinkPortConfigIds.empty()) {
+ LOG(ERROR) << __func__ << ": requested patch has empty sinks list";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ if (!all_unique<int32_t>(in_requested.sinkPortConfigIds)) {
+ LOG(ERROR) << __func__ << ": requested patch has duplicate ids in the sinks list";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+
+ auto& configs = getConfig().portConfigs;
+ std::vector<int32_t> missingIds;
+ auto sources =
+ selectByIds<AudioPortConfig>(configs, in_requested.sourcePortConfigIds, &missingIds);
+ if (!missingIds.empty()) {
+ LOG(ERROR) << __func__ << ": following source port config ids not found: "
+ << ::android::internal::ToString(missingIds);
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ auto sinks = selectByIds<AudioPortConfig>(configs, in_requested.sinkPortConfigIds, &missingIds);
+ if (!missingIds.empty()) {
+ LOG(ERROR) << __func__ << ": following sink port config ids not found: "
+ << ::android::internal::ToString(missingIds);
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ // bool indicates whether a non-exclusive route is available.
+ // If only an exclusive route is available, that means the patch can not be
+ // established if there is any other patch which currently uses the sink port.
+ std::map<int32_t, bool> allowedSinkPorts;
+ auto& routes = getConfig().routes;
+ for (auto src : sources) {
+ for (const auto& r : routes) {
+ const auto& srcs = r.sourcePortIds;
+ if (std::find(srcs.begin(), srcs.end(), src->portId) != srcs.end()) {
+ if (!allowedSinkPorts[r.sinkPortId]) { // prefer non-exclusive
+ allowedSinkPorts[r.sinkPortId] = !r.isExclusive;
+ }
+ }
+ }
+ }
+ for (auto sink : sinks) {
+ if (allowedSinkPorts.count(sink->portId) == 0) {
+ LOG(ERROR) << __func__ << ": there is no route to the sink port id " << sink->portId;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ }
+
+ auto& patches = getConfig().patches;
+ auto existing = patches.end();
+ std::optional<decltype(mPatches)> patchesBackup;
+ if (in_requested.id != 0) {
+ existing = findById<AudioPatch>(patches, in_requested.id);
+ if (existing != patches.end()) {
+ patchesBackup = mPatches;
+ cleanUpPatch(existing->id);
+ } else {
+ LOG(ERROR) << __func__ << ": not found existing patch id " << in_requested.id;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ }
+ // Validate the requested patch.
+ for (const auto& [sinkPortId, nonExclusive] : allowedSinkPorts) {
+ if (!nonExclusive && mPatches.count(sinkPortId) != 0) {
+ LOG(ERROR) << __func__ << ": sink port id " << sinkPortId
+ << "is exclusive and is already used by some other patch";
+ if (patchesBackup.has_value()) {
+ mPatches = std::move(*patchesBackup);
+ }
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
+ }
+ *_aidl_return = in_requested;
+ _aidl_return->minimumStreamBufferSizeFrames = kMinimumStreamBufferSizeFrames;
+ _aidl_return->latenciesMs.clear();
+ _aidl_return->latenciesMs.insert(_aidl_return->latenciesMs.end(),
+ _aidl_return->sinkPortConfigIds.size(), kLatencyMs);
+ AudioPatch oldPatch{};
+ if (existing == patches.end()) {
+ _aidl_return->id = getConfig().nextPatchId++;
+ patches.push_back(*_aidl_return);
+ existing = patches.begin() + (patches.size() - 1);
+ } else {
+ oldPatch = *existing;
+ *existing = *_aidl_return;
+ }
+ registerPatch(*existing);
+ updateStreamsConnectedState(oldPatch, *_aidl_return);
+
+ LOG(DEBUG) << __func__ << ": " << (oldPatch.id == 0 ? "created" : "updated") << " patch "
+ << _aidl_return->toString();
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::setAudioPortConfig(const AudioPortConfig& in_requested,
+ AudioPortConfig* out_suggested, bool* _aidl_return) {
+ LOG(DEBUG) << __func__ << ": requested " << in_requested.toString();
+ auto& configs = getConfig().portConfigs;
+ auto existing = configs.end();
+ if (in_requested.id != 0) {
+ if (existing = findById<AudioPortConfig>(configs, in_requested.id);
+ existing == configs.end()) {
+ LOG(ERROR) << __func__ << ": existing port config id " << in_requested.id
+ << " not found";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ }
+
+ const int portId = existing != configs.end() ? existing->portId : in_requested.portId;
+ if (portId == 0) {
+ LOG(ERROR) << __func__ << ": input 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;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ if (existing != configs.end()) {
+ *out_suggested = *existing;
+ } else {
+ AudioPortConfig newConfig;
+ if (generateDefaultPortConfig(*portIt, &newConfig)) {
+ *out_suggested = newConfig;
+ } else {
+ LOG(ERROR) << __func__ << ": unable generate a default config for port " << portId;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ }
+ // From this moment, 'out_suggested' is either an existing port config,
+ // or a new generated config. Now attempt to update it according to the specified
+ // fields of 'in_requested'.
+
+ bool requestedIsValid = true, requestedIsFullySpecified = true;
+
+ AudioIoFlags portFlags = portIt->flags;
+ if (in_requested.flags.has_value()) {
+ if (in_requested.flags.value() != portFlags) {
+ LOG(WARNING) << __func__ << ": requested flags "
+ << in_requested.flags.value().toString() << " do not match port's "
+ << portId << " flags " << portFlags.toString();
+ requestedIsValid = false;
+ }
+ } else {
+ requestedIsFullySpecified = false;
+ }
+
+ AudioProfile portProfile;
+ if (in_requested.format.has_value()) {
+ const auto& format = in_requested.format.value();
+ if (findAudioProfile(*portIt, format, &portProfile)) {
+ out_suggested->format = format;
+ } else {
+ LOG(WARNING) << __func__ << ": requested format " << format.toString()
+ << " is not found in port's " << portId << " profiles";
+ requestedIsValid = false;
+ }
+ } else {
+ requestedIsFullySpecified = false;
+ }
+ if (!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);
+ }
+
+ 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()) {
+ out_suggested->channelMask = channelMask;
+ } else {
+ LOG(WARNING) << __func__ << ": requested channel mask " << channelMask.toString()
+ << " is not supported for the format " << portProfile.format.toString()
+ << " by the port " << portId;
+ requestedIsValid = false;
+ }
+ } else {
+ requestedIsFullySpecified = false;
+ }
+
+ if (in_requested.sampleRate.has_value()) {
+ const auto& sampleRate = in_requested.sampleRate.value();
+ if (find(portProfile.sampleRates.begin(), portProfile.sampleRates.end(),
+ sampleRate.value) != portProfile.sampleRates.end()) {
+ out_suggested->sampleRate = sampleRate;
+ } else {
+ LOG(WARNING) << __func__ << ": requested sample rate " << sampleRate.value
+ << " is not supported for the format " << portProfile.format.toString()
+ << " by the port " << portId;
+ requestedIsValid = false;
+ }
+ } else {
+ requestedIsFullySpecified = false;
+ }
+
+ if (in_requested.gain.has_value()) {
+ // Let's pretend that gain can always be applied.
+ out_suggested->gain = in_requested.gain.value();
+ }
+
+ if (existing == configs.end() && requestedIsValid && requestedIsFullySpecified) {
+ out_suggested->id = getConfig().nextPortId++;
+ configs.push_back(*out_suggested);
+ *_aidl_return = true;
+ LOG(DEBUG) << __func__ << ": created new port config " << out_suggested->toString();
+ } else if (existing != configs.end() && requestedIsValid) {
+ *existing = *out_suggested;
+ *_aidl_return = true;
+ LOG(DEBUG) << __func__ << ": updated port config " << out_suggested->toString();
+ } else {
+ LOG(DEBUG) << __func__ << ": not applied; existing config ? " << (existing != configs.end())
+ << "; requested is valid? " << requestedIsValid << ", fully specified? "
+ << requestedIsFullySpecified;
+ *_aidl_return = false;
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::resetAudioPatch(int32_t in_patchId) {
+ auto& patches = getConfig().patches;
+ auto patchIt = findById<AudioPatch>(patches, in_patchId);
+ if (patchIt != patches.end()) {
+ cleanUpPatch(patchIt->id);
+ updateStreamsConnectedState(*patchIt, AudioPatch{});
+ patches.erase(patchIt);
+ LOG(DEBUG) << __func__ << ": erased patch " << in_patchId;
+ return ndk::ScopedAStatus::ok();
+ }
+ LOG(ERROR) << __func__ << ": patch id " << in_patchId << " not found";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+}
+
+ndk::ScopedAStatus Module::resetAudioPortConfig(int32_t in_portConfigId) {
+ auto& configs = getConfig().portConfigs;
+ auto configIt = findById<AudioPortConfig>(configs, in_portConfigId);
+ if (configIt != configs.end()) {
+ if (mStreams.count(in_portConfigId) != 0) {
+ LOG(ERROR) << __func__ << ": port config id " << in_portConfigId
+ << " has a stream opened on it";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
+ auto patchIt = mPatches.find(in_portConfigId);
+ if (patchIt != mPatches.end()) {
+ LOG(ERROR) << __func__ << ": port config id " << in_portConfigId
+ << " is used by the patch with id " << patchIt->second;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
+ auto& initials = getConfig().initialConfigs;
+ auto initialIt = findById<AudioPortConfig>(initials, in_portConfigId);
+ if (initialIt == initials.end()) {
+ configs.erase(configIt);
+ LOG(DEBUG) << __func__ << ": erased port config " << in_portConfigId;
+ } else if (*configIt != *initialIt) {
+ *configIt = *initialIt;
+ LOG(DEBUG) << __func__ << ": reset port config " << in_portConfigId;
+ }
+ return ndk::ScopedAStatus::ok();
+ }
+ LOG(ERROR) << __func__ << ": port config id " << in_portConfigId << " not found";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+}
+
+ndk::ScopedAStatus Module::getMasterMute(bool* _aidl_return) {
+ *_aidl_return = mMasterMute;
+ LOG(DEBUG) << __func__ << ": returning " << *_aidl_return;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::setMasterMute(bool in_mute) {
+ LOG(DEBUG) << __func__ << ": " << in_mute;
+ mMasterMute = in_mute;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::getMasterVolume(float* _aidl_return) {
+ *_aidl_return = mMasterVolume;
+ LOG(DEBUG) << __func__ << ": returning " << *_aidl_return;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::setMasterVolume(float in_volume) {
+ LOG(DEBUG) << __func__ << ": " << in_volume;
+ if (in_volume >= 0.0f && in_volume <= 1.0f) {
+ mMasterVolume = in_volume;
+ return ndk::ScopedAStatus::ok();
+ }
+ LOG(ERROR) << __func__ << ": invalid master volume value: " << in_volume;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+}
+
+ndk::ScopedAStatus Module::getMicMute(bool* _aidl_return) {
+ *_aidl_return = mMicMute;
+ LOG(DEBUG) << __func__ << ": returning " << *_aidl_return;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::setMicMute(bool in_mute) {
+ LOG(DEBUG) << __func__ << ": " << in_mute;
+ mMicMute = in_mute;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::updateAudioMode(AudioMode in_mode) {
+ // No checks for supported audio modes here, it's an informative notification.
+ LOG(DEBUG) << __func__ << ": " << toString(in_mode);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::updateScreenRotation(ScreenRotation in_rotation) {
+ LOG(DEBUG) << __func__ << ": " << toString(in_rotation);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::updateScreenState(bool in_isTurnedOn) {
+ LOG(DEBUG) << __func__ << ": " << in_isTurnedOn;
+ return ndk::ScopedAStatus::ok();
+}
+
+} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp
new file mode 100644
index 0000000..d7c352f
--- /dev/null
+++ b/audio/aidl/default/Stream.cpp
@@ -0,0 +1,545 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AHAL_Stream"
+#include <android-base/logging.h>
+#include <utils/SystemClock.h>
+
+#include "core-impl/Module.h"
+#include "core-impl/Stream.h"
+
+using aidl::android::hardware::audio::common::SinkMetadata;
+using aidl::android::hardware::audio::common::SourceMetadata;
+using aidl::android::media::audio::common::AudioOffloadInfo;
+
+namespace aidl::android::hardware::audio::core {
+
+void StreamContext::fillDescriptor(StreamDescriptor* desc) {
+ if (mCommandMQ) {
+ desc->command = mCommandMQ->dupeDesc();
+ }
+ if (mReplyMQ) {
+ desc->reply = mReplyMQ->dupeDesc();
+ }
+ if (mDataMQ) {
+ desc->frameSizeBytes = mFrameSize;
+ desc->bufferSizeFrames =
+ mDataMQ->getQuantumCount() * mDataMQ->getQuantumSize() / mFrameSize;
+ desc->audio.set<StreamDescriptor::AudioBuffer::Tag::fmq>(mDataMQ->dupeDesc());
+ }
+}
+
+bool StreamContext::isValid() const {
+ if (mCommandMQ && !mCommandMQ->isValid()) {
+ LOG(ERROR) << "command FMQ is invalid";
+ return false;
+ }
+ if (mReplyMQ && !mReplyMQ->isValid()) {
+ LOG(ERROR) << "reply FMQ is invalid";
+ return false;
+ }
+ if (mFrameSize == 0) {
+ LOG(ERROR) << "frame size is not set";
+ return false;
+ }
+ if (mDataMQ && !mDataMQ->isValid()) {
+ LOG(ERROR) << "data FMQ is invalid";
+ return false;
+ }
+ return true;
+}
+
+void StreamContext::reset() {
+ mCommandMQ.reset();
+ mReplyMQ.reset();
+ mDataMQ.reset();
+}
+
+std::string StreamWorkerCommonLogic::init() {
+ if (mCommandMQ == nullptr) return "Command MQ is null";
+ if (mReplyMQ == nullptr) return "Reply MQ is null";
+ if (mDataMQ == nullptr) return "Data MQ is null";
+ if (sizeof(decltype(mDataBuffer)::element_type) != mDataMQ->getQuantumSize()) {
+ return "Unexpected Data MQ quantum size: " + std::to_string(mDataMQ->getQuantumSize());
+ }
+ mDataBufferSize = mDataMQ->getQuantumCount() * mDataMQ->getQuantumSize();
+ mDataBuffer.reset(new (std::nothrow) int8_t[mDataBufferSize]);
+ if (mDataBuffer == nullptr) {
+ return "Failed to allocate data buffer for element count " +
+ std::to_string(mDataMQ->getQuantumCount()) +
+ ", size in bytes: " + std::to_string(mDataBufferSize);
+ }
+ return "";
+}
+
+void StreamWorkerCommonLogic::populateReply(StreamDescriptor::Reply* reply,
+ bool isConnected) const {
+ reply->status = STATUS_OK;
+ if (isConnected) {
+ reply->observable.frames = mFrameCount;
+ reply->observable.timeNs = ::android::elapsedRealtimeNano();
+ } else {
+ reply->observable.frames = StreamDescriptor::Position::UNKNOWN;
+ reply->observable.timeNs = StreamDescriptor::Position::UNKNOWN;
+ }
+}
+
+void StreamWorkerCommonLogic::populateReplyWrongState(
+ StreamDescriptor::Reply* reply, const StreamDescriptor::Command& command) const {
+ LOG(WARNING) << "command '" << toString(command.getTag())
+ << "' can not be handled in the state " << toString(mState);
+ reply->status = STATUS_INVALID_OPERATION;
+}
+
+const std::string StreamInWorkerLogic::kThreadName = "reader";
+
+StreamInWorkerLogic::Status StreamInWorkerLogic::cycle() {
+ // Note: for input streams, draining is driven by the client, thus
+ // "empty buffer" condition can only happen while handling the 'burst'
+ // command. Thus, unlike for output streams, it does not make sense to
+ // delay the 'DRAINING' state here by 'mTransientStateDelayMs'.
+ // TODO: Add a delay for transitions of async operations when/if they added.
+
+ StreamDescriptor::Command command{};
+ if (!mCommandMQ->readBlocking(&command, 1)) {
+ LOG(ERROR) << __func__ << ": reading of command from MQ failed";
+ mState = StreamDescriptor::State::ERROR;
+ return Status::ABORT;
+ }
+ LOG(DEBUG) << __func__ << ": received command " << command.toString() << " in " << kThreadName;
+ StreamDescriptor::Reply reply{};
+ reply.status = STATUS_BAD_VALUE;
+ using Tag = StreamDescriptor::Command::Tag;
+ switch (command.getTag()) {
+ case Tag::halReservedExit:
+ if (const int32_t cookie = command.get<Tag::halReservedExit>();
+ cookie == mInternalCommandCookie) {
+ setClosed();
+ // This is an internal command, no need to reply.
+ return Status::EXIT;
+ } else {
+ LOG(WARNING) << __func__ << ": EXIT command has a bad cookie: " << cookie;
+ }
+ break;
+ case Tag::getStatus:
+ populateReply(&reply, mIsConnected);
+ break;
+ case Tag::start:
+ if (mState == StreamDescriptor::State::STANDBY ||
+ mState == StreamDescriptor::State::DRAINING) {
+ populateReply(&reply, mIsConnected);
+ mState = mState == StreamDescriptor::State::STANDBY
+ ? StreamDescriptor::State::IDLE
+ : StreamDescriptor::State::ACTIVE;
+ } else {
+ populateReplyWrongState(&reply, command);
+ }
+ break;
+ case Tag::burst:
+ if (const int32_t fmqByteCount = command.get<Tag::burst>(); fmqByteCount >= 0) {
+ LOG(DEBUG) << __func__ << ": '" << toString(command.getTag()) << "' command for "
+ << fmqByteCount << " bytes";
+ if (mState == StreamDescriptor::State::IDLE ||
+ mState == StreamDescriptor::State::ACTIVE ||
+ mState == StreamDescriptor::State::PAUSED ||
+ mState == StreamDescriptor::State::DRAINING) {
+ if (!read(fmqByteCount, &reply)) {
+ mState = StreamDescriptor::State::ERROR;
+ }
+ if (mState == StreamDescriptor::State::IDLE ||
+ mState == StreamDescriptor::State::PAUSED) {
+ mState = StreamDescriptor::State::ACTIVE;
+ } else if (mState == StreamDescriptor::State::DRAINING) {
+ // To simplify the reference code, we assume that the read operation
+ // has consumed all the data remaining in the hardware buffer.
+ // In a real implementation, here we would either remain in
+ // the 'DRAINING' state, or transfer to 'STANDBY' depending on the
+ // buffer state.
+ mState = StreamDescriptor::State::STANDBY;
+ }
+ } else {
+ populateReplyWrongState(&reply, command);
+ }
+ } else {
+ LOG(WARNING) << __func__ << ": invalid burst byte count: " << fmqByteCount;
+ }
+ break;
+ case Tag::drain:
+ if (command.get<Tag::drain>() == StreamDescriptor::DrainMode::DRAIN_UNSPECIFIED) {
+ if (mState == StreamDescriptor::State::ACTIVE) {
+ usleep(1000); // Simulate a blocking call into the driver.
+ populateReply(&reply, mIsConnected);
+ // Can switch the state to ERROR if a driver error occurs.
+ mState = StreamDescriptor::State::DRAINING;
+ } else {
+ populateReplyWrongState(&reply, command);
+ }
+ } else {
+ LOG(WARNING) << __func__
+ << ": invalid drain mode: " << toString(command.get<Tag::drain>());
+ }
+ break;
+ case Tag::standby:
+ if (mState == StreamDescriptor::State::IDLE) {
+ usleep(1000); // Simulate a blocking call into the driver.
+ populateReply(&reply, mIsConnected);
+ // Can switch the state to ERROR if a driver error occurs.
+ mState = StreamDescriptor::State::STANDBY;
+ } else {
+ populateReplyWrongState(&reply, command);
+ }
+ break;
+ case Tag::pause:
+ if (mState == StreamDescriptor::State::ACTIVE) {
+ usleep(1000); // Simulate a blocking call into the driver.
+ populateReply(&reply, mIsConnected);
+ // Can switch the state to ERROR if a driver error occurs.
+ mState = StreamDescriptor::State::PAUSED;
+ } else {
+ populateReplyWrongState(&reply, command);
+ }
+ break;
+ case Tag::flush:
+ if (mState == StreamDescriptor::State::PAUSED) {
+ usleep(1000); // Simulate a blocking call into the driver.
+ populateReply(&reply, mIsConnected);
+ // Can switch the state to ERROR if a driver error occurs.
+ mState = StreamDescriptor::State::STANDBY;
+ } else {
+ populateReplyWrongState(&reply, command);
+ }
+ break;
+ }
+ reply.state = mState;
+ LOG(DEBUG) << __func__ << ": writing reply " << reply.toString();
+ if (!mReplyMQ->writeBlocking(&reply, 1)) {
+ LOG(ERROR) << __func__ << ": writing of reply " << reply.toString() << " to MQ failed";
+ mState = StreamDescriptor::State::ERROR;
+ return Status::ABORT;
+ }
+ return Status::CONTINUE;
+}
+
+bool StreamInWorkerLogic::read(size_t clientSize, StreamDescriptor::Reply* reply) {
+ // Can switch the state to ERROR if a driver error occurs.
+ const size_t byteCount = std::min({clientSize, mDataMQ->availableToWrite(), mDataBufferSize});
+ const bool isConnected = mIsConnected;
+ bool fatal = false;
+ // Simulate reading of data, or provide zeroes if the stream is not connected.
+ for (size_t i = 0; i < byteCount; ++i) {
+ using buffer_type = decltype(mDataBuffer)::element_type;
+ constexpr int kBufferValueRange = std::numeric_limits<buffer_type>::max() -
+ std::numeric_limits<buffer_type>::min() + 1;
+ mDataBuffer[i] = isConnected ? (std::rand() % kBufferValueRange) +
+ std::numeric_limits<buffer_type>::min()
+ : 0;
+ }
+ usleep(3000); // Simulate a blocking call into the driver.
+ // Set 'fatal = true' if a driver error occurs.
+ if (bool success = byteCount > 0 ? mDataMQ->write(&mDataBuffer[0], byteCount) : true; success) {
+ LOG(DEBUG) << __func__ << ": writing of " << byteCount << " bytes into data MQ"
+ << " succeeded; connected? " << isConnected;
+ // Frames are provided and counted regardless of connection status.
+ reply->fmqByteCount += byteCount;
+ mFrameCount += byteCount / mFrameSize;
+ populateReply(reply, isConnected);
+ } else {
+ LOG(WARNING) << __func__ << ": writing of " << byteCount << " bytes of data to MQ failed";
+ reply->status = STATUS_NOT_ENOUGH_DATA;
+ }
+ reply->latencyMs = Module::kLatencyMs;
+ return !fatal;
+}
+
+const std::string StreamOutWorkerLogic::kThreadName = "writer";
+
+StreamOutWorkerLogic::Status StreamOutWorkerLogic::cycle() {
+ if (mState == StreamDescriptor::State::DRAINING ||
+ mState == StreamDescriptor::State::TRANSFERRING) {
+ if (auto stateDurationMs = std::chrono::duration_cast<std::chrono::milliseconds>(
+ std::chrono::steady_clock::now() - mTransientStateStart);
+ stateDurationMs >= mTransientStateDelayMs) {
+ if (mAsyncCallback == nullptr) {
+ // In blocking mode, mState can only be DRAINING.
+ mState = StreamDescriptor::State::IDLE;
+ } else {
+ // In a real implementation, the driver should notify the HAL about
+ // drain or transfer completion. In the stub, we switch unconditionally.
+ if (mState == StreamDescriptor::State::DRAINING) {
+ mState = StreamDescriptor::State::IDLE;
+ ndk::ScopedAStatus status = mAsyncCallback->onDrainReady();
+ if (!status.isOk()) {
+ LOG(ERROR) << __func__ << ": error from onDrainReady: " << status;
+ }
+ } else {
+ mState = StreamDescriptor::State::ACTIVE;
+ ndk::ScopedAStatus status = mAsyncCallback->onTransferReady();
+ if (!status.isOk()) {
+ LOG(ERROR) << __func__ << ": error from onTransferReady: " << status;
+ }
+ }
+ }
+ if (mTransientStateDelayMs.count() != 0) {
+ LOG(DEBUG) << __func__ << ": switched to state " << toString(mState)
+ << " after a timeout";
+ }
+ }
+ }
+
+ StreamDescriptor::Command command{};
+ if (!mCommandMQ->readBlocking(&command, 1)) {
+ LOG(ERROR) << __func__ << ": reading of command from MQ failed";
+ mState = StreamDescriptor::State::ERROR;
+ return Status::ABORT;
+ }
+ LOG(DEBUG) << __func__ << ": received command " << command.toString() << " in " << kThreadName;
+ StreamDescriptor::Reply reply{};
+ reply.status = STATUS_BAD_VALUE;
+ using Tag = StreamDescriptor::Command::Tag;
+ switch (command.getTag()) {
+ case Tag::halReservedExit:
+ if (const int32_t cookie = command.get<Tag::halReservedExit>();
+ cookie == mInternalCommandCookie) {
+ setClosed();
+ // This is an internal command, no need to reply.
+ return Status::EXIT;
+ } else {
+ LOG(WARNING) << __func__ << ": EXIT command has a bad cookie: " << cookie;
+ }
+ break;
+ case Tag::getStatus:
+ populateReply(&reply, mIsConnected);
+ break;
+ case Tag::start: {
+ bool commandAccepted = true;
+ switch (mState) {
+ case StreamDescriptor::State::STANDBY:
+ mState = StreamDescriptor::State::IDLE;
+ break;
+ case StreamDescriptor::State::PAUSED:
+ mState = StreamDescriptor::State::ACTIVE;
+ break;
+ case StreamDescriptor::State::DRAIN_PAUSED:
+ switchToTransientState(StreamDescriptor::State::DRAINING);
+ break;
+ case StreamDescriptor::State::TRANSFER_PAUSED:
+ switchToTransientState(StreamDescriptor::State::TRANSFERRING);
+ break;
+ default:
+ populateReplyWrongState(&reply, command);
+ commandAccepted = false;
+ }
+ if (commandAccepted) {
+ populateReply(&reply, mIsConnected);
+ }
+ } break;
+ case Tag::burst:
+ if (const int32_t fmqByteCount = command.get<Tag::burst>(); fmqByteCount >= 0) {
+ LOG(DEBUG) << __func__ << ": '" << toString(command.getTag()) << "' command for "
+ << fmqByteCount << " bytes";
+ if (mState != StreamDescriptor::State::ERROR &&
+ mState != StreamDescriptor::State::TRANSFERRING &&
+ mState != StreamDescriptor::State::TRANSFER_PAUSED) {
+ if (!write(fmqByteCount, &reply)) {
+ mState = StreamDescriptor::State::ERROR;
+ }
+ if (mState == StreamDescriptor::State::STANDBY ||
+ mState == StreamDescriptor::State::DRAIN_PAUSED ||
+ mState == StreamDescriptor::State::PAUSED) {
+ if (mAsyncCallback == nullptr ||
+ mState != StreamDescriptor::State::DRAIN_PAUSED) {
+ mState = StreamDescriptor::State::PAUSED;
+ } else {
+ mState = StreamDescriptor::State::TRANSFER_PAUSED;
+ }
+ } else if (mState == StreamDescriptor::State::IDLE ||
+ mState == StreamDescriptor::State::DRAINING ||
+ mState == StreamDescriptor::State::ACTIVE) {
+ if (mAsyncCallback == nullptr || reply.fmqByteCount == fmqByteCount) {
+ mState = StreamDescriptor::State::ACTIVE;
+ } else {
+ switchToTransientState(StreamDescriptor::State::TRANSFERRING);
+ }
+ }
+ } else {
+ populateReplyWrongState(&reply, command);
+ }
+ } else {
+ LOG(WARNING) << __func__ << ": invalid burst byte count: " << fmqByteCount;
+ }
+ break;
+ case Tag::drain:
+ if (command.get<Tag::drain>() == StreamDescriptor::DrainMode::DRAIN_ALL ||
+ command.get<Tag::drain>() == StreamDescriptor::DrainMode::DRAIN_EARLY_NOTIFY) {
+ if (mState == StreamDescriptor::State::ACTIVE ||
+ mState == StreamDescriptor::State::TRANSFERRING) {
+ usleep(1000); // Simulate a blocking call into the driver.
+ populateReply(&reply, mIsConnected);
+ // Can switch the state to ERROR if a driver error occurs.
+ switchToTransientState(StreamDescriptor::State::DRAINING);
+ } else if (mState == StreamDescriptor::State::TRANSFER_PAUSED) {
+ mState = StreamDescriptor::State::DRAIN_PAUSED;
+ populateReply(&reply, mIsConnected);
+ } else {
+ populateReplyWrongState(&reply, command);
+ }
+ } else {
+ LOG(WARNING) << __func__
+ << ": invalid drain mode: " << toString(command.get<Tag::drain>());
+ }
+ break;
+ case Tag::standby:
+ if (mState == StreamDescriptor::State::IDLE) {
+ usleep(1000); // Simulate a blocking call into the driver.
+ populateReply(&reply, mIsConnected);
+ // Can switch the state to ERROR if a driver error occurs.
+ mState = StreamDescriptor::State::STANDBY;
+ } else {
+ populateReplyWrongState(&reply, command);
+ }
+ break;
+ case Tag::pause: {
+ bool commandAccepted = true;
+ switch (mState) {
+ case StreamDescriptor::State::ACTIVE:
+ mState = StreamDescriptor::State::PAUSED;
+ break;
+ case StreamDescriptor::State::DRAINING:
+ mState = StreamDescriptor::State::DRAIN_PAUSED;
+ break;
+ case StreamDescriptor::State::TRANSFERRING:
+ mState = StreamDescriptor::State::TRANSFER_PAUSED;
+ break;
+ default:
+ populateReplyWrongState(&reply, command);
+ commandAccepted = false;
+ }
+ if (commandAccepted) {
+ populateReply(&reply, mIsConnected);
+ }
+ } break;
+ case Tag::flush:
+ if (mState == StreamDescriptor::State::PAUSED ||
+ mState == StreamDescriptor::State::DRAIN_PAUSED ||
+ mState == StreamDescriptor::State::TRANSFER_PAUSED) {
+ populateReply(&reply, mIsConnected);
+ mState = StreamDescriptor::State::IDLE;
+ } else {
+ populateReplyWrongState(&reply, command);
+ }
+ break;
+ }
+ reply.state = mState;
+ LOG(DEBUG) << __func__ << ": writing reply " << reply.toString();
+ if (!mReplyMQ->writeBlocking(&reply, 1)) {
+ LOG(ERROR) << __func__ << ": writing of reply " << reply.toString() << " to MQ failed";
+ mState = StreamDescriptor::State::ERROR;
+ return Status::ABORT;
+ }
+ return Status::CONTINUE;
+}
+
+bool StreamOutWorkerLogic::write(size_t clientSize, StreamDescriptor::Reply* reply) {
+ const size_t readByteCount = mDataMQ->availableToRead();
+ // Amount of data that the HAL module is going to actually use.
+ const size_t byteCount = std::min({clientSize, readByteCount, mDataBufferSize});
+ bool fatal = false;
+ if (bool success = readByteCount > 0 ? mDataMQ->read(&mDataBuffer[0], readByteCount) : true) {
+ const bool isConnected = mIsConnected;
+ LOG(DEBUG) << __func__ << ": reading of " << readByteCount << " bytes from data MQ"
+ << " succeeded; connected? " << isConnected;
+ // Frames are consumed and counted regardless of connection status.
+ reply->fmqByteCount += byteCount;
+ mFrameCount += byteCount / mFrameSize;
+ populateReply(reply, isConnected);
+ usleep(3000); // Simulate a blocking call into the driver.
+ // Set 'fatal = true' if a driver error occurs.
+ } else {
+ LOG(WARNING) << __func__ << ": reading of " << readByteCount
+ << " bytes of data from MQ failed";
+ reply->status = STATUS_NOT_ENOUGH_DATA;
+ }
+ reply->latencyMs = Module::kLatencyMs;
+ return !fatal;
+}
+
+template <class Metadata, class StreamWorker>
+StreamCommon<Metadata, StreamWorker>::~StreamCommon() {
+ if (!isClosed()) {
+ LOG(ERROR) << __func__ << ": stream was not closed prior to destruction, resource leak";
+ stopWorker();
+ // The worker and the context should clean up by themselves via destructors.
+ }
+}
+
+template <class Metadata, class StreamWorker>
+ndk::ScopedAStatus StreamCommon<Metadata, StreamWorker>::close() {
+ LOG(DEBUG) << __func__;
+ if (!isClosed()) {
+ stopWorker();
+ LOG(DEBUG) << __func__ << ": joining the worker thread...";
+ mWorker.stop();
+ LOG(DEBUG) << __func__ << ": worker thread joined";
+ mContext.reset();
+ mWorker.setClosed();
+ return ndk::ScopedAStatus::ok();
+ } else {
+ LOG(ERROR) << __func__ << ": stream was already closed";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
+}
+
+template <class Metadata, class StreamWorker>
+void StreamCommon<Metadata, StreamWorker>::stopWorker() {
+ if (auto commandMQ = mContext.getCommandMQ(); commandMQ != nullptr) {
+ LOG(DEBUG) << __func__ << ": asking the worker to exit...";
+ auto cmd = StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::halReservedExit>(
+ mContext.getInternalCommandCookie());
+ // Note: never call 'pause' and 'resume' methods of StreamWorker
+ // in the HAL implementation. These methods are to be used by
+ // the client side only. Preventing the worker loop from running
+ // on the HAL side can cause a deadlock.
+ if (!commandMQ->writeBlocking(&cmd, 1)) {
+ LOG(ERROR) << __func__ << ": failed to write exit command to the MQ";
+ }
+ LOG(DEBUG) << __func__ << ": done";
+ }
+}
+
+template <class Metadata, class StreamWorker>
+ndk::ScopedAStatus StreamCommon<Metadata, StreamWorker>::updateMetadata(const Metadata& metadata) {
+ LOG(DEBUG) << __func__;
+ if (!isClosed()) {
+ mMetadata = metadata;
+ return ndk::ScopedAStatus::ok();
+ }
+ LOG(ERROR) << __func__ << ": stream was closed";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+}
+
+StreamIn::StreamIn(const SinkMetadata& sinkMetadata, StreamContext context)
+ : StreamCommon<SinkMetadata, StreamInWorker>(sinkMetadata, std::move(context)) {
+ LOG(DEBUG) << __func__;
+}
+
+StreamOut::StreamOut(const SourceMetadata& sourceMetadata, StreamContext context,
+ const std::optional<AudioOffloadInfo>& offloadInfo)
+ : StreamCommon<SourceMetadata, StreamOutWorker>(sourceMetadata, std::move(context)),
+ mOffloadInfo(offloadInfo) {
+ LOG(DEBUG) << __func__;
+}
+
+} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/Telephony.cpp b/audio/aidl/default/Telephony.cpp
new file mode 100644
index 0000000..1854b35
--- /dev/null
+++ b/audio/aidl/default/Telephony.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/binder_to_string.h>
+#define LOG_TAG "AHAL_Telephony"
+#include <android-base/logging.h>
+
+#include "core-impl/Telephony.h"
+
+namespace aidl::android::hardware::audio::core {
+
+ndk::ScopedAStatus Telephony::getSupportedAudioModes(std::vector<AudioMode>* _aidl_return) {
+ *_aidl_return = mSupportedAudioModes;
+ LOG(DEBUG) << __func__ << ": returning " << ::android::internal::ToString(*_aidl_return);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Telephony::switchAudioMode(AudioMode in_mode) {
+ if (std::find(mSupportedAudioModes.begin(), mSupportedAudioModes.end(), in_mode) !=
+ mSupportedAudioModes.end()) {
+ LOG(DEBUG) << __func__ << ": " << toString(in_mode);
+ return ndk::ScopedAStatus::ok();
+ }
+ LOG(ERROR) << __func__ << ": unsupported mode " << toString(in_mode);
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/android.hardware.audio.effect.service-aidl.example.rc b/audio/aidl/default/android.hardware.audio.effect.service-aidl.example.rc
new file mode 100644
index 0000000..68bbf5b
--- /dev/null
+++ b/audio/aidl/default/android.hardware.audio.effect.service-aidl.example.rc
@@ -0,0 +1,9 @@
+service vendor.audio-effect-hal-aidl /vendor/bin/hw/android.hardware.audio.effect.service-aidl.example
+ class hal
+ user audioserver
+ # media gid needed for /dev/fm (radio) and for /data/misc/media (tee)
+ group audio media
+ capabilities BLOCK_SUSPEND
+ ioprio rt 4
+ task_profiles ProcessCapacityHigh HighPerformance
+ onrestart restart audioserver
diff --git a/audio/aidl/default/android.hardware.audio.effect.service-aidl.xml b/audio/aidl/default/android.hardware.audio.effect.service-aidl.xml
new file mode 100644
index 0000000..fdc53a3
--- /dev/null
+++ b/audio/aidl/default/android.hardware.audio.effect.service-aidl.xml
@@ -0,0 +1,7 @@
+<manifest version="1.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.audio.effect</name>
+ <version>1</version>
+ <fqname>IFactory/default</fqname>
+ </hal>
+</manifest>
diff --git a/audio/aidl/default/android.hardware.audio.service-aidl.example.rc b/audio/aidl/default/android.hardware.audio.service-aidl.example.rc
new file mode 100644
index 0000000..02a9c37
--- /dev/null
+++ b/audio/aidl/default/android.hardware.audio.service-aidl.example.rc
@@ -0,0 +1,9 @@
+service vendor.audio-hal-aidl /vendor/bin/hw/android.hardware.audio.service-aidl.example
+ class hal
+ user audioserver
+ # media gid needed for /dev/fm (radio) and for /data/misc/media (tee)
+ group audio camera drmrpc inet media mediadrm net_bt net_bt_admin net_bw_acct wakelock context_hub
+ capabilities BLOCK_SUSPEND
+ ioprio rt 4
+ task_profiles ProcessCapacityHigh HighPerformance
+ onrestart restart audioserver
diff --git a/audio/aidl/default/android.hardware.audio.service-aidl.xml b/audio/aidl/default/android.hardware.audio.service-aidl.xml
new file mode 100644
index 0000000..bb4b01a
--- /dev/null
+++ b/audio/aidl/default/android.hardware.audio.service-aidl.xml
@@ -0,0 +1,12 @@
+<manifest version="1.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.audio.core</name>
+ <version>1</version>
+ <fqname>IModule/default</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
new file mode 100644
index 0000000..f4ac8fe
--- /dev/null
+++ b/audio/aidl/default/audio_effects_config.xml
@@ -0,0 +1,122 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<audio_effects_conf version="2.0" xmlns="http://schemas.android.com/audio/audio_effects_conf/v2_0">
+ <!-- Overview.
+ This example config file was copy from existing one: frameworks/av/media/libeffects/data/
+ audio_effects.xml, with effect library names updated to AIDL libraries we currently have.
+
+ All "library" attributes in "effect" element must must match a "library" element with the
+ same value of the "name" attribute.
+ All "effect" attributes in "preprocess" and "postprocess" element must match an "effect"
+ element with the same value of the "name" attribute.
+
+ AIDL EffectFactory are relying on the "name" attribute in "effect" element to identify the
+ effect type, so it's necessary to have the mapping from name to effect type UUID. Make
+ sure to either use existing effect name as key of
+ ::android::hardware::audio::effect::kUuidNameTypeMap, or add a new {name, typeUUID} map
+ item to the kUuidNameTypeMap.
+
+ Existing audio_effects.xml should working without any change as long as:
+ 1. "path" attribute of "library" element matches with the actual effect library name.
+ 2. "name" attribute of "effect" and "effectProxy" element correctly added as key of
+ kUuidNameTypeMap, with value matches Identity.type in Descriptor.aidl.
+ 3. "uuid" attribute of "effect" element matches Identity.uuid in Descriptor.aidl.
+ 4. "uuid" attribute of "effectProxy" element matches Identity.proxy in Descriptor.aidl.
+ -->
+
+ <!-- List of effect libraries to load.
+ Each library element must contain a "name" attribute and a "path" attribute giving the
+ name of a library .so file on the target device.
+ -->
+ <libraries>
+ <library name="bassboostsw" path="libbassboostsw.so"/>
+ <library name="bundle" path="libbundleaidl.so"/>
+ <library name="dynamics_processingsw" path="libdynamicsprocessingsw.so"/>
+ <library name="equalizersw" path="libequalizersw.so"/>
+ <library name="haptic_generatorsw" path="libhapticgeneratorsw.so"/>
+ <library name="loudness_enhancersw" path="libloudnessenhancersw.so"/>
+ <library name="env_reverbsw" path="libenvreverbsw.so"/>
+ <library name="preset_reverbsw" path="libpresetreverbsw.so"/>
+ <library name="virtualizersw" path="libvirtualizersw.so"/>
+ <library name="visualizersw" path="libvisualizersw.so"/>
+ <library name="volumesw" path="libvolumesw.so"/>
+ </libraries>
+
+ <!-- list of effects to load.
+ Each "effect" element must contain a "name", "library" and a "uuid" attribute.
+ The value of the "library" attribute must correspond to the name of one library element in
+ the "libraries" element.
+ The "name" attribute used to specific effect type, and should be mapping to a key of
+ aidl::android::hardware::audio::effect::kUuidNameTypeMap.
+ The "uuid" attribute is the implementation specific UUID as specified by the effect vendor.
+
+ Effect proxy can be supported with "effectProxy" element, each sub-element should contain
+ "library" and "uuid" attribute, all other attributes were ignored. Framework side use
+ result of IFactory.queryEffects() to decide which effect implementation should be part of
+ proxy and which not.
+
+ Only "name", "library", and "uuid" attributes in "effects" element are meaningful and
+ parsed out by EffectConfig class, all other attributes are ignored.
+ Only "name" and "uuid" attributes in "effectProxy" element are meaningful and parsed out
+ by EffectConfig class, all other attributes are ignored.
+ -->
+
+ <effects>
+ <effect name="bassboost" library="bassboostsw" uuid="fa8181f2-588b-11ed-9b6a-0242ac120002"/>
+ <effect name="dynamics_processing" library="dynamics_processingsw" uuid="fa818d78-588b-11ed-9b6a-0242ac120002"/>
+ <effect name="haptic_generator" library="haptic_generatorsw" uuid="fa819110-588b-11ed-9b6a-0242ac120002"/>
+ <effect name="loudness_enhancer" library="loudness_enhancersw" uuid="fa819610-588b-11ed-9b6a-0242ac120002"/>
+ <effect name="env_reverb" library="env_reverbsw" uuid="fa819886-588b-11ed-9b6a-0242ac120002"/>
+ <effect name="preset_reverb" library="preset_reverbsw" uuid="fa8199c6-588b-11ed-9b6a-0242ac120002"/>
+ <effect name="virtualizer" library="virtualizersw" uuid="fa819d86-588b-11ed-9b6a-0242ac120002"/>
+ <effect name="visualizer" library="visualizersw" uuid="fa81a0f6-588b-11ed-9b6a-0242ac120002"/>
+ <effect name="volume" library="volumesw" uuid="fa81a718-588b-11ed-9b6a-0242ac120002"/>
+ <effectProxy name="equalizer" uuid="c8e70ecd-48ca-456e-8a4f-0002a5d5c51b">
+ <libsw library="equalizersw" uuid="0bed4300-847d-11df-bb17-0002a5d5c51b"/>
+ <libsw library="bundle" uuid="ce772f20-847d-11df-bb17-0002a5d5c51b"/>
+ </effectProxy>
+ </effects>
+
+ <!-- Audio pre processor configurations.
+ The pre processor configuration is described in a "preprocess" element and consists in a
+ list of elements each describing pre processor settings for a given use case or "stream".
+ Each stream element has a "type" attribute corresponding to the input source used.
+ Valid types are these defined in system/hardware/interfaces/media/aidl/android/media/audio/
+ common/AudioSource.aidl.
+ Each "stream" element contains a list of "apply" elements indicating one effect to apply.
+ The effect to apply is designated by its name in the "effects" elements.
+ If there are more than one effect apply to one stream, the audio framework will apply them
+ in the same equence as they listed in "stream" element.
+
+ <preprocess>
+ <stream type="voice_communication">
+ <apply effect="aec"/>
+ <apply effect="ns"/>
+ </stream>
+ </preprocess>
+ -->
+
+ <!-- Audio post processor configurations.
+ The post processor configuration is described in a "postprocess" element and consists in a
+ list of elements each describing post processor settings for a given use case or "stream".
+ Each stream element has a "type" attribute corresponding to the stream type used.
+ Valid types are these defined in system/hardware/interfaces/media/aidl/android/media/audio/
+ common/AudioStreamType.aidl.
+ Each "stream" element contains a list of "apply" elements indicating one effect to apply.
+ The effect to apply is designated by its name in the "effects" elements.
+ If there are more than one effect apply to one stream, the audio framework will apply them
+ in the same equence as they listed in "stream" element.
+
+ <postprocess>
+ <stream type="music">
+ <apply effect="music_post_proc"/>
+ </stream>
+ <stream type="voice_call">
+ <apply effect="voice_post_proc"/>
+ </stream>
+ <stream type="notification">
+ <apply effect="notification_post_proc"/>
+ </stream>
+ </postprocess>
+ -->
+
+</audio_effects_conf>
diff --git a/audio/aidl/default/bassboost/Android.bp b/audio/aidl/default/bassboost/Android.bp
new file mode 100644
index 0000000..f22eb95
--- /dev/null
+++ b/audio/aidl/default/bassboost/Android.bp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_shared {
+ name: "libbassboostsw",
+ defaults: [
+ "aidlaudioeffectservice_defaults",
+ "latest_android_media_audio_common_types_ndk_shared",
+ "latest_android_hardware_audio_effect_ndk_shared",
+ ],
+ srcs: [
+ "BassBoostSw.cpp",
+ ":effectCommonFile",
+ ],
+ visibility: [
+ "//hardware/interfaces/audio/aidl/default",
+ ],
+}
diff --git a/audio/aidl/default/bassboost/BassBoostSw.cpp b/audio/aidl/default/bassboost/BassBoostSw.cpp
new file mode 100644
index 0000000..c52d16f
--- /dev/null
+++ b/audio/aidl/default/bassboost/BassBoostSw.cpp
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cstddef>
+#define LOG_TAG "AHAL_BassBoostSw"
+#include <Utils.h>
+#include <algorithm>
+#include <unordered_set>
+
+#include <android-base/logging.h>
+#include <fmq/AidlMessageQueue.h>
+
+#include "BassBoostSw.h"
+
+using aidl::android::hardware::audio::effect::BassBoostSw;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kBassBoostSwImplUUID;
+using aidl::android::hardware::audio::effect::State;
+using aidl::android::media::audio::common::AudioUuid;
+
+extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
+ std::shared_ptr<IEffect>* instanceSpp) {
+ if (!in_impl_uuid || *in_impl_uuid != kBassBoostSwImplUUID) {
+ LOG(ERROR) << __func__ << "uuid not supported";
+ return EX_ILLEGAL_ARGUMENT;
+ }
+ if (instanceSpp) {
+ *instanceSpp = ndk::SharedRefBase::make<BassBoostSw>();
+ LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
+ return EX_NONE;
+ } else {
+ LOG(ERROR) << __func__ << " invalid input parameter!";
+ return EX_ILLEGAL_ARGUMENT;
+ }
+}
+
+extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
+ if (!instanceSp) {
+ return EX_NONE;
+ }
+ State state;
+ ndk::ScopedAStatus status = instanceSp->getState(&state);
+ if (!status.isOk() || State::INIT != state) {
+ LOG(ERROR) << __func__ << " instance " << instanceSp.get()
+ << " in state: " << toString(state) << ", status: " << status.getDescription();
+ return EX_ILLEGAL_STATE;
+ }
+ LOG(DEBUG) << __func__ << " instance " << instanceSp.get() << " destroyed";
+ return EX_NONE;
+}
+
+namespace aidl::android::hardware::audio::effect {
+
+ndk::ScopedAStatus BassBoostSw::getDescriptor(Descriptor* _aidl_return) {
+ LOG(DEBUG) << __func__ << kDescriptor.toString();
+ *_aidl_return = kDescriptor;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus BassBoostSw::setParameterSpecific(const Parameter::Specific& specific) {
+ RETURN_IF(Parameter::Specific::bassBoost != specific.getTag(), EX_ILLEGAL_ARGUMENT,
+ "EffectNotSupported");
+ std::lock_guard lg(mMutex);
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+ mSpecificParam = specific.get<Parameter::Specific::bassBoost>();
+ LOG(DEBUG) << __func__ << " success with: " << specific.toString();
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus BassBoostSw::getParameterSpecific(const Parameter::Id& id,
+ Parameter::Specific* specific) {
+ auto tag = id.getTag();
+ RETURN_IF(Parameter::Id::bassBoostTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
+ specific->set<Parameter::Specific::bassBoost>(mSpecificParam);
+ return ndk::ScopedAStatus::ok();
+}
+
+std::shared_ptr<EffectContext> BassBoostSw::createContext(const Parameter::Common& common) {
+ if (mContext) {
+ LOG(DEBUG) << __func__ << " context already exist";
+ return mContext;
+ }
+ mContext = std::make_shared<BassBoostSwContext>(1 /* statusFmqDepth */, common);
+ return mContext;
+}
+
+RetCode BassBoostSw::releaseContext() {
+ if (mContext) {
+ mContext.reset();
+ }
+ return RetCode::SUCCESS;
+}
+
+// Processing method running in EffectWorker thread.
+IEffect::Status BassBoostSw::effectProcessImpl(float* in, float* out, int process) {
+ // TODO: get data buffer and process.
+ LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
+ for (int i = 0; i < process; i++) {
+ *out++ = *in++;
+ }
+ return {STATUS_OK, process, process};
+}
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/bassboost/BassBoostSw.h b/audio/aidl/default/bassboost/BassBoostSw.h
new file mode 100644
index 0000000..90a8887
--- /dev/null
+++ b/audio/aidl/default/bassboost/BassBoostSw.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/audio/effect/BnEffect.h>
+#include <fmq/AidlMessageQueue.h>
+#include <cstdlib>
+#include <memory>
+
+#include "effect-impl/EffectImpl.h"
+#include "effect-impl/EffectUUID.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+class BassBoostSwContext final : public EffectContext {
+ public:
+ BassBoostSwContext(int statusDepth, const Parameter::Common& common)
+ : EffectContext(statusDepth, common) {
+ LOG(DEBUG) << __func__;
+ }
+ // TODO: add specific context here
+};
+
+class BassBoostSw final : public EffectImpl {
+ public:
+ BassBoostSw() { LOG(DEBUG) << __func__; }
+ ~BassBoostSw() {
+ cleanUp();
+ LOG(DEBUG) << __func__;
+ }
+
+ ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
+ ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
+ ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
+ Parameter::Specific* specific) override;
+ IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+ std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+ RetCode releaseContext() override;
+
+ private:
+ std::shared_ptr<BassBoostSwContext> mContext;
+ /* capabilities */
+ const BassBoost::Capability kCapability;
+ /* Effect descriptor */
+ const Descriptor kDescriptor = {
+ .common = {.id = {.type = kBassBoostTypeUUID,
+ .uuid = kBassBoostSwImplUUID,
+ .proxy = std::nullopt},
+ .flags = {.type = Flags::Type::INSERT,
+ .insert = Flags::Insert::FIRST,
+ .volume = Flags::Volume::CTRL},
+ .name = "BassBoostSw",
+ .implementor = "The Android Open Source Project"},
+ .capability = Capability::make<Capability::bassBoost>(kCapability)};
+
+ /* parameters */
+ BassBoost mSpecificParam;
+};
+} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/config/audio_policy_configuration.xsd b/audio/aidl/default/config/audio_policy_configuration.xsd
new file mode 100644
index 0000000..2c18a1e
--- /dev/null
+++ b/audio/aidl/default/config/audio_policy_configuration.xsd
@@ -0,0 +1,829 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<xs:schema version="2.0"
+ elementFormDefault="qualified"
+ attributeFormDefault="unqualified"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <!-- List the config versions supported by audio policy. -->
+ <xs:simpleType name="version">
+ <xs:restriction base="xs:decimal">
+ <xs:enumeration value="7.0"/>
+ <xs:enumeration value="7.1"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="halVersion">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ Version of the interface the hal implements. Note that this
+ relates to legacy HAL API versions since HIDL APIs are versioned
+ using other mechanisms.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:restriction base="xs:decimal">
+ <!-- List of HAL versions supported by the framework. -->
+ <xs:enumeration value="2.0"/>
+ <xs:enumeration value="3.0"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:element name="audioPolicyConfiguration">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="globalConfiguration" type="globalConfiguration"/>
+ <xs:element name="modules" type="modules" maxOccurs="unbounded"/>
+ <xs:element name="volumes" type="volumes" maxOccurs="unbounded"/>
+ <xs:element name="surroundSound" type="surroundSound" minOccurs="0" />
+ </xs:sequence>
+ <xs:attribute name="version" type="version"/>
+ </xs:complexType>
+ <xs:key name="moduleNameKey">
+ <xs:selector xpath="modules/module"/>
+ <xs:field xpath="@name"/>
+ </xs:key>
+ <xs:unique name="volumeTargetUniqueness">
+ <xs:selector xpath="volumes/volume"/>
+ <xs:field xpath="@stream"/>
+ <xs:field xpath="@deviceCategory"/>
+ </xs:unique>
+ <xs:key name="volumeCurveNameKey">
+ <xs:selector xpath="volumes/reference"/>
+ <xs:field xpath="@name"/>
+ </xs:key>
+ <xs:keyref name="volumeCurveRef" refer="volumeCurveNameKey">
+ <xs:selector xpath="volumes/volume"/>
+ <xs:field xpath="@ref"/>
+ </xs:keyref>
+ </xs:element>
+ <xs:complexType name="globalConfiguration">
+ <xs:attribute name="speaker_drc_enabled" type="xs:boolean" use="required"/>
+ <xs:attribute name="call_screen_mode_supported" type="xs:boolean" use="optional"/>
+ <xs:attribute name="engine_library" type="engineSuffix" use="optional"/>
+ </xs:complexType>
+ <xs:complexType name="modules">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ There should be one section per audio HW module present on the platform.
+ Each <module/> contains two mandatory tags: “halVersion” and “name”.
+ The module "name" is the same as in previous .conf file.
+ Each module must contain the following sections:
+ - <devicePorts/>: a list of device descriptors for all
+ input and output devices accessible via this module.
+ This contains both permanently attached devices and removable devices.
+ - <mixPorts/>: listing all output and input streams exposed by the audio HAL
+ - <routes/>: list of possible connections between input
+ and output devices or between stream and devices.
+ A <route/> is defined by a set of 3 attributes:
+ -"type": mux|mix means all sources are mutual exclusive (mux) or can be mixed (mix)
+ -"sink": the sink involved in this route
+ -"sources": all the sources than can be connected to the sink via this route
+ - <attachedDevices/>: permanently attached devices.
+ The attachedDevices section is a list of devices names.
+ Their names correspond to device names defined in "devicePorts" section.
+ - <defaultOutputDevice/> is the device to be used when no policy rule applies
+ </xs:documentation>
+ </xs:annotation>
+ <xs:sequence>
+ <xs:element name="module" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="attachedDevices" type="attachedDevices" minOccurs="0">
+ <xs:unique name="attachedDevicesUniqueness">
+ <xs:selector xpath="item"/>
+ <xs:field xpath="."/>
+ </xs:unique>
+ </xs:element>
+ <xs:element name="defaultOutputDevice" type="xs:token" minOccurs="0"/>
+ <xs:element name="mixPorts" type="mixPorts" minOccurs="0"/>
+ <xs:element name="devicePorts" type="devicePorts" minOccurs="0"/>
+ <xs:element name="routes" type="routes" minOccurs="0"/>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:string" use="required"/>
+ <xs:attribute name="halVersion" type="halVersion" use="required"/>
+ </xs:complexType>
+ <xs:unique name="mixPortNameUniqueness">
+ <xs:selector xpath="mixPorts/mixPort"/>
+ <xs:field xpath="@name"/>
+ </xs:unique>
+ <xs:key name="devicePortNameKey">
+ <xs:selector xpath="devicePorts/devicePort"/>
+ <xs:field xpath="@tagName"/>
+ </xs:key>
+ <xs:unique name="devicePortUniqueness">
+ <xs:selector xpath="devicePorts/devicePort"/>
+ <xs:field xpath="@type"/>
+ <xs:field xpath="@address"/>
+ </xs:unique>
+ <xs:keyref name="defaultOutputDeviceRef" refer="devicePortNameKey">
+ <xs:selector xpath="defaultOutputDevice"/>
+ <xs:field xpath="."/>
+ </xs:keyref>
+ <xs:keyref name="attachedDeviceRef" refer="devicePortNameKey">
+ <xs:selector xpath="attachedDevices/item"/>
+ <xs:field xpath="."/>
+ </xs:keyref>
+ <!-- The following 3 constraints try to make sure each sink port
+ is reference in one an only one route. -->
+ <xs:key name="routeSinkKey">
+ <!-- predicate [@type='sink'] does not work in xsd 1.0 -->
+ <xs:selector xpath="devicePorts/devicePort|mixPorts/mixPort"/>
+ <xs:field xpath="@tagName|@name"/>
+ </xs:key>
+ <xs:keyref name="routeSinkRef" refer="routeSinkKey">
+ <xs:selector xpath="routes/route"/>
+ <xs:field xpath="@sink"/>
+ </xs:keyref>
+ <xs:unique name="routeUniqueness">
+ <xs:selector xpath="routes/route"/>
+ <xs:field xpath="@sink"/>
+ </xs:unique>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="attachedDevices">
+ <xs:sequence>
+ <xs:element name="item" type="xs:token" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:simpleType name="audioInOutFlag">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ The flags indicate suggested stream attributes supported by the profile.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_DIRECT" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_PRIMARY" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_FAST" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_DEEP_BUFFER" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_NON_BLOCKING" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_HW_AV_SYNC" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_TTS" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_RAW" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_SYNC" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_DIRECT_PCM" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_MMAP_NOIRQ" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_VOIP_RX" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_INCALL_MUSIC" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_GAPLESS_OFFLOAD" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_SPATIALIZER" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_ULTRASOUND" />
+ <xs:enumeration value="AUDIO_INPUT_FLAG_FAST" />
+ <xs:enumeration value="AUDIO_INPUT_FLAG_HW_HOTWORD" />
+ <xs:enumeration value="AUDIO_INPUT_FLAG_RAW" />
+ <xs:enumeration value="AUDIO_INPUT_FLAG_SYNC" />
+ <xs:enumeration value="AUDIO_INPUT_FLAG_MMAP_NOIRQ" />
+ <xs:enumeration value="AUDIO_INPUT_FLAG_VOIP_TX" />
+ <xs:enumeration value="AUDIO_INPUT_FLAG_HW_AV_SYNC" />
+ <xs:enumeration value="AUDIO_INPUT_FLAG_DIRECT" />
+ <xs:enumeration value="AUDIO_INPUT_FLAG_ULTRASOUND" />
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="audioInOutFlags">
+ <xs:list itemType="audioInOutFlag" />
+ </xs:simpleType>
+ <xs:simpleType name="role">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="sink"/>
+ <xs:enumeration value="source"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="mixPorts">
+ <xs:sequence>
+ <xs:element name="mixPort" minOccurs="0" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="profile" type="profile" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="gains" type="gains" minOccurs="0"/>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:token" use="required"/>
+ <xs:attribute name="role" type="role" use="required"/>
+ <xs:attribute name="flags" type="audioInOutFlags"/>
+ <xs:attribute name="maxOpenCount" type="xs:unsignedInt"/>
+ <xs:attribute name="maxActiveCount" type="xs:unsignedInt"/>
+ <xs:attribute name="preferredUsage" type="audioUsageList">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ When choosing the mixPort of an audio track, the audioPolicy
+ first considers the mixPorts with a preferredUsage including
+ the track AudioUsage preferred .
+ If non support the track format, the other mixPorts are considered.
+ Eg: a <mixPort preferredUsage="AUDIO_USAGE_MEDIA" /> will receive
+ the audio of all apps playing with a MEDIA usage.
+ It may receive audio from ALARM if there are no audio compatible
+ <mixPort preferredUsage="AUDIO_USAGE_ALARM" />.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="recommendedMuteDurationMs" type="xs:unsignedInt"/>
+ </xs:complexType>
+ <xs:unique name="mixPortProfileUniqueness">
+ <xs:selector xpath="profile"/>
+ <xs:field xpath="format"/>
+ <xs:field xpath="samplingRate"/>
+ <xs:field xpath="channelMasks"/>
+ </xs:unique>
+ <xs:unique name="mixPortGainUniqueness">
+ <xs:selector xpath="gains/gain"/>
+ <xs:field xpath="@name"/>
+ </xs:unique>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:simpleType name="audioDevice">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="AUDIO_DEVICE_NONE"/>
+
+ <xs:enumeration value="AUDIO_DEVICE_OUT_EARPIECE"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_SPEAKER"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_WIRED_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_WIRED_HEADPHONE"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_SCO"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_HDMI"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_HDMI_EARC"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_AUX_DIGITAL"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_USB_ACCESSORY"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_USB_DEVICE"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_REMOTE_SUBMIX"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_TELEPHONY_TX"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_LINE"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_HDMI_ARC"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_SPDIF"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_FM"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_AUX_LINE"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_SPEAKER_SAFE"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_IP"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_BUS"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_PROXY"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_USB_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_HEARING_AID"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_ECHO_CANCELLER"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_BLE_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_BLE_SPEAKER"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_BLE_BROADCAST"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_DEFAULT"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_STUB"/>
+
+ <xs:enumeration value="AUDIO_DEVICE_IN_COMMUNICATION"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_AMBIENT"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_BUILTIN_MIC"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_WIRED_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_HDMI"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_AUX_DIGITAL"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_VOICE_CALL"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_TELEPHONY_RX"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_BACK_MIC"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_REMOTE_SUBMIX"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_USB_ACCESSORY"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_USB_DEVICE"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_FM_TUNER"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_TV_TUNER"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_LINE"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_SPDIF"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_BLUETOOTH_A2DP"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_LOOPBACK"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_IP"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_BUS"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_PROXY"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_USB_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_BLUETOOTH_BLE"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_HDMI_ARC"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_HDMI_EARC"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_ECHO_REFERENCE"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_BLE_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_DEFAULT"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_STUB"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="vendorExtension">
+ <!-- Vendor extension names must be prefixed by "VX_" to distinguish them from
+ AOSP values. Vendors must namespace their names to avoid conflicts. The
+ namespace part must only use capital latin characters and decimal digits and
+ consist of at least 3 characters. The part of the extension name after the
+ namespace may in addition include underscores. Example for a hypothetical
+ Google virtual reality device:
+
+ <devicePort tagName="VR" type="VX_GOOGLE_VR" role="sink" />
+ -->
+ <xs:restriction base="xs:string">
+ <xs:pattern value="VX_[A-Z0-9]{3,}_[_A-Z0-9]+"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="extendableAudioDevice">
+ <xs:union memberTypes="audioDevice vendorExtension"/>
+ </xs:simpleType>
+ <xs:simpleType name="audioFormat">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="AUDIO_FORMAT_DEFAULT" />
+ <xs:enumeration value="AUDIO_FORMAT_PCM_16_BIT" />
+ <xs:enumeration value="AUDIO_FORMAT_PCM_8_BIT"/>
+ <xs:enumeration value="AUDIO_FORMAT_PCM_32_BIT"/>
+ <xs:enumeration value="AUDIO_FORMAT_PCM_8_24_BIT"/>
+ <xs:enumeration value="AUDIO_FORMAT_PCM_FLOAT"/>
+ <xs:enumeration value="AUDIO_FORMAT_PCM_24_BIT_PACKED"/>
+ <xs:enumeration value="AUDIO_FORMAT_MP3"/>
+ <xs:enumeration value="AUDIO_FORMAT_AMR_NB"/>
+ <xs:enumeration value="AUDIO_FORMAT_AMR_WB"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_MAIN"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_LC"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_SSR"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_LTP"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_HE_V1"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_SCALABLE"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ERLC"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_LD"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_HE_V2"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ELD"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_XHE"/>
+ <xs:enumeration value="AUDIO_FORMAT_HE_AAC_V1"/>
+ <xs:enumeration value="AUDIO_FORMAT_HE_AAC_V2"/>
+ <xs:enumeration value="AUDIO_FORMAT_VORBIS"/>
+ <xs:enumeration value="AUDIO_FORMAT_OPUS"/>
+ <xs:enumeration value="AUDIO_FORMAT_AC3"/>
+ <xs:enumeration value="AUDIO_FORMAT_E_AC3"/>
+ <xs:enumeration value="AUDIO_FORMAT_E_AC3_JOC"/>
+ <xs:enumeration value="AUDIO_FORMAT_DTS"/>
+ <xs:enumeration value="AUDIO_FORMAT_DTS_HD"/>
+ <xs:enumeration value="AUDIO_FORMAT_IEC61937"/>
+ <xs:enumeration value="AUDIO_FORMAT_DOLBY_TRUEHD"/>
+ <xs:enumeration value="AUDIO_FORMAT_EVRC"/>
+ <xs:enumeration value="AUDIO_FORMAT_EVRCB"/>
+ <xs:enumeration value="AUDIO_FORMAT_EVRCWB"/>
+ <xs:enumeration value="AUDIO_FORMAT_EVRCNW"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADIF"/>
+ <xs:enumeration value="AUDIO_FORMAT_WMA"/>
+ <xs:enumeration value="AUDIO_FORMAT_WMA_PRO"/>
+ <xs:enumeration value="AUDIO_FORMAT_AMR_WB_PLUS"/>
+ <xs:enumeration value="AUDIO_FORMAT_MP2"/>
+ <xs:enumeration value="AUDIO_FORMAT_QCELP"/>
+ <xs:enumeration value="AUDIO_FORMAT_DSD"/>
+ <xs:enumeration value="AUDIO_FORMAT_FLAC"/>
+ <xs:enumeration value="AUDIO_FORMAT_ALAC"/>
+ <xs:enumeration value="AUDIO_FORMAT_APE"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_MAIN"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_LC"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_SSR"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_LTP"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_HE_V1"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_SCALABLE"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_ERLC"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_LD"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_HE_V2"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_ELD"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_XHE"/>
+ <xs:enumeration value="AUDIO_FORMAT_SBC"/>
+ <xs:enumeration value="AUDIO_FORMAT_APTX"/>
+ <xs:enumeration value="AUDIO_FORMAT_APTX_HD"/>
+ <xs:enumeration value="AUDIO_FORMAT_AC4"/>
+ <xs:enumeration value="AUDIO_FORMAT_LDAC"/>
+ <xs:enumeration value="AUDIO_FORMAT_MAT"/>
+ <xs:enumeration value="AUDIO_FORMAT_MAT_1_0"/>
+ <xs:enumeration value="AUDIO_FORMAT_MAT_2_0"/>
+ <xs:enumeration value="AUDIO_FORMAT_MAT_2_1"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_LATM"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_LATM_LC"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_LATM_HE_V1"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_LATM_HE_V2"/>
+ <xs:enumeration value="AUDIO_FORMAT_CELT"/>
+ <xs:enumeration value="AUDIO_FORMAT_APTX_ADAPTIVE"/>
+ <xs:enumeration value="AUDIO_FORMAT_LHDC"/>
+ <xs:enumeration value="AUDIO_FORMAT_LHDC_LL"/>
+ <xs:enumeration value="AUDIO_FORMAT_APTX_TWSP"/>
+ <xs:enumeration value="AUDIO_FORMAT_LC3"/>
+ <xs:enumeration value="AUDIO_FORMAT_MPEGH_BL_L3"/>
+ <xs:enumeration value="AUDIO_FORMAT_MPEGH_BL_L4"/>
+ <xs:enumeration value="AUDIO_FORMAT_MPEGH_LC_L3"/>
+ <xs:enumeration value="AUDIO_FORMAT_MPEGH_LC_L4"/>
+ <xs:enumeration value="AUDIO_FORMAT_IEC60958"/>
+ <xs:enumeration value="AUDIO_FORMAT_DTS_UHD"/>
+ <xs:enumeration value="AUDIO_FORMAT_DRA"/>
+ <xs:enumeration value="AUDIO_FORMAT_APTX_ADAPTIVE_QLEA"/>
+ <xs:enumeration value="AUDIO_FORMAT_APTX_ADAPTIVE_R4"/>
+ <xs:enumeration value="AUDIO_FORMAT_DTS_HD_MA"/>
+ <xs:enumeration value="AUDIO_FORMAT_DTS_UHD_P2"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="extendableAudioFormat">
+ <xs:union memberTypes="audioFormat vendorExtension"/>
+ </xs:simpleType>
+ <xs:simpleType name="audioUsage">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ Audio usage specifies the intended use case for the sound being played.
+ Please consult frameworks/base/media/java/android/media/AudioAttributes.java
+ for the description of each value.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="AUDIO_USAGE_UNKNOWN" />
+ <xs:enumeration value="AUDIO_USAGE_MEDIA" />
+ <xs:enumeration value="AUDIO_USAGE_VOICE_COMMUNICATION" />
+ <xs:enumeration value="AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING" />
+ <xs:enumeration value="AUDIO_USAGE_ALARM" />
+ <xs:enumeration value="AUDIO_USAGE_NOTIFICATION" />
+ <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE" />
+ <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_EVENT" />
+ <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY" />
+ <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE" />
+ <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_SONIFICATION" />
+ <xs:enumeration value="AUDIO_USAGE_GAME" />
+ <xs:enumeration value="AUDIO_USAGE_VIRTUAL_SOURCE" />
+ <xs:enumeration value="AUDIO_USAGE_ASSISTANT" />
+ <xs:enumeration value="AUDIO_USAGE_CALL_ASSISTANT" />
+ <xs:enumeration value="AUDIO_USAGE_EMERGENCY" />
+ <xs:enumeration value="AUDIO_USAGE_SAFETY" />
+ <xs:enumeration value="AUDIO_USAGE_VEHICLE_STATUS" />
+ <xs:enumeration value="AUDIO_USAGE_ANNOUNCEMENT" />
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="audioUsageList">
+ <xs:list itemType="audioUsage"/>
+ </xs:simpleType>
+ <xs:simpleType name="audioContentType">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ Audio content type expresses the general category of the content.
+ Please consult frameworks/base/media/java/android/media/AudioAttributes.java
+ for the description of each value.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="AUDIO_CONTENT_TYPE_UNKNOWN"/>
+ <xs:enumeration value="AUDIO_CONTENT_TYPE_SPEECH"/>
+ <xs:enumeration value="AUDIO_CONTENT_TYPE_MUSIC"/>
+ <xs:enumeration value="AUDIO_CONTENT_TYPE_MOVIE"/>
+ <xs:enumeration value="AUDIO_CONTENT_TYPE_SONIFICATION"/>
+ <xs:enumeration value="AUDIO_CONTENT_TYPE_ULTRASOUND"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="samplingRates">
+ <xs:list itemType="xs:nonNegativeInteger" />
+ </xs:simpleType>
+ <xs:simpleType name="audioChannelMask">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ Audio channel mask specifies presence of particular channels.
+ There are two representations:
+ - representation position (traditional discrete channel specification,
+ e.g. "left", "right");
+ - indexed (this is similar to "tracks" in audio mixing, channels
+ are represented using numbers).
+ </xs:documentation>
+ </xs:annotation>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="AUDIO_CHANNEL_NONE"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_MONO"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_STEREO"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_2POINT1"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_TRI"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_TRI_BACK"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_3POINT1"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_2POINT0POINT2"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_2POINT1POINT2"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_3POINT0POINT2"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_3POINT1POINT2"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_QUAD"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_QUAD_BACK"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_QUAD_SIDE"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_SURROUND"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_PENTA"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_5POINT1"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_5POINT1_BACK"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_5POINT1_SIDE"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_5POINT1POINT2"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_5POINT1POINT4"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_6POINT1"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_7POINT1"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_7POINT1POINT2"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_7POINT1POINT4"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_9POINT1POINT4"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_9POINT1POINT6"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_13POINT_360RA"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_22POINT2"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_MONO_HAPTIC_A"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_STEREO_HAPTIC_A"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_HAPTIC_AB"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_MONO_HAPTIC_AB"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_STEREO_HAPTIC_AB"/>
+ <xs:enumeration value="AUDIO_CHANNEL_IN_MONO"/>
+ <xs:enumeration value="AUDIO_CHANNEL_IN_STEREO"/>
+ <xs:enumeration value="AUDIO_CHANNEL_IN_FRONT_BACK"/>
+ <xs:enumeration value="AUDIO_CHANNEL_IN_6"/>
+ <xs:enumeration value="AUDIO_CHANNEL_IN_2POINT0POINT2"/>
+ <xs:enumeration value="AUDIO_CHANNEL_IN_2POINT1POINT2"/>
+ <xs:enumeration value="AUDIO_CHANNEL_IN_3POINT0POINT2"/>
+ <xs:enumeration value="AUDIO_CHANNEL_IN_3POINT1POINT2"/>
+ <xs:enumeration value="AUDIO_CHANNEL_IN_5POINT1"/>
+ <xs:enumeration value="AUDIO_CHANNEL_IN_VOICE_UPLINK_MONO"/>
+ <xs:enumeration value="AUDIO_CHANNEL_IN_VOICE_DNLINK_MONO"/>
+ <xs:enumeration value="AUDIO_CHANNEL_IN_VOICE_CALL_MONO"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_1"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_2"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_3"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_4"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_5"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_6"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_7"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_8"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_9"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_10"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_11"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_12"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_13"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_14"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_15"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_16"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_17"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_18"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_19"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_20"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_21"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_22"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_23"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_24"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="channelMasks">
+ <xs:list itemType="audioChannelMask" />
+ </xs:simpleType>
+ <xs:simpleType name="audioEncapsulationType">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="AUDIO_ENCAPSULATION_TYPE_NONE"/>
+ <xs:enumeration value="AUDIO_ENCAPSULATION_TYPE_IEC61937"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="profile">
+ <xs:attribute name="name" type="xs:token" use="optional"/>
+ <xs:attribute name="format" type="extendableAudioFormat" use="optional"/>
+ <xs:attribute name="samplingRates" type="samplingRates" use="optional"/>
+ <xs:attribute name="channelMasks" type="channelMasks" use="optional"/>
+ <xs:attribute name="encapsulationType" type="audioEncapsulationType" use="optional"/>
+ </xs:complexType>
+ <xs:simpleType name="audioGainMode">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="AUDIO_GAIN_MODE_JOINT"/>
+ <xs:enumeration value="AUDIO_GAIN_MODE_CHANNELS"/>
+ <xs:enumeration value="AUDIO_GAIN_MODE_RAMP"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="audioGainModeMaskUnrestricted">
+ <xs:list itemType="audioGainMode" />
+ </xs:simpleType>
+ <xs:simpleType name='audioGainModeMask'>
+ <xs:restriction base='audioGainModeMaskUnrestricted'>
+ <xs:minLength value='1' />
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="gains">
+ <xs:sequence>
+ <xs:element name="gain" minOccurs="0" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:attribute name="name" type="xs:token" use="required"/>
+ <xs:attribute name="mode" type="audioGainModeMask" use="required"/>
+ <xs:attribute name="channel_mask" type="audioChannelMask" use="optional"/>
+ <xs:attribute name="minValueMB" type="xs:int" use="optional"/>
+ <xs:attribute name="maxValueMB" type="xs:int" use="optional"/>
+ <xs:attribute name="defaultValueMB" type="xs:int" use="optional"/>
+ <xs:attribute name="stepValueMB" type="xs:int" use="optional"/>
+ <xs:attribute name="minRampMs" type="xs:int" use="optional"/>
+ <xs:attribute name="maxRampMs" type="xs:int" use="optional"/>
+ <xs:attribute name="useForVolume" type="xs:boolean" use="optional"/>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="devicePorts">
+ <xs:sequence>
+ <xs:element name="devicePort" minOccurs="0" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="profile" type="profile" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="gains" type="gains" minOccurs="0"/>
+ </xs:sequence>
+ <xs:attribute name="tagName" type="xs:token" use="required"/>
+ <xs:attribute name="type" type="extendableAudioDevice" use="required"/>
+ <xs:attribute name="role" type="role" use="required"/>
+ <xs:attribute name="address" type="xs:string" use="optional" default=""/>
+ <!-- Note that XSD 1.0 can not check that a type only has one default. -->
+ <xs:attribute name="default" type="xs:boolean" use="optional">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ The default device will be used if multiple have the same type
+ and no explicit route request exists for a specific device of
+ that type.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="encodedFormats" type="audioFormatsList" use="optional"
+ default="" />
+ </xs:complexType>
+ <xs:unique name="devicePortProfileUniqueness">
+ <xs:selector xpath="profile"/>
+ <xs:field xpath="format"/>
+ <xs:field xpath="samplingRate"/>
+ <xs:field xpath="channelMasks"/>
+ </xs:unique>
+ <xs:unique name="devicePortGainUniqueness">
+ <xs:selector xpath="gains/gain"/>
+ <xs:field xpath="@name"/>
+ </xs:unique>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:simpleType name="mixType">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="mix"/>
+ <xs:enumeration value="mux"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="routes">
+ <xs:sequence>
+ <xs:element name="route" minOccurs="0" maxOccurs="unbounded">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ List all available sources for a given sink.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:attribute name="type" type="mixType" use="required"/>
+ <xs:attribute name="sink" type="xs:string" use="required"/>
+ <xs:attribute name="sources" type="xs:string" use="required"/>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="volumes">
+ <xs:sequence>
+ <xs:element name="volume" type="volume" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="reference" type="reference" minOccurs="0" maxOccurs="unbounded">
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ <!-- TODO: Always require a ref for better xsd validations.
+ Currently a volume could have no points nor ref
+ as it can not be forbidden by xsd 1.0.-->
+ <xs:simpleType name="volumePoint">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ Comma separated pair of number.
+ The fist one is the framework level (between 0 and 100).
+ The second one is the volume to send to the HAL.
+ The framework will interpolate volumes not specified.
+ Their MUST be at least 2 points specified.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:restriction base="xs:string">
+ <xs:pattern value="([0-9]{1,2}|100),-?[0-9]+"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="audioStreamType">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ Audio stream type describing the intended use case of a stream.
+ Please consult frameworks/base/media/java/android/media/AudioSystem.java
+ for the description of each value.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="AUDIO_STREAM_VOICE_CALL"/>
+ <xs:enumeration value="AUDIO_STREAM_SYSTEM"/>
+ <xs:enumeration value="AUDIO_STREAM_RING"/>
+ <xs:enumeration value="AUDIO_STREAM_MUSIC"/>
+ <xs:enumeration value="AUDIO_STREAM_ALARM"/>
+ <xs:enumeration value="AUDIO_STREAM_NOTIFICATION"/>
+ <xs:enumeration value="AUDIO_STREAM_BLUETOOTH_SCO"/>
+ <xs:enumeration value="AUDIO_STREAM_ENFORCED_AUDIBLE"/>
+ <xs:enumeration value="AUDIO_STREAM_DTMF"/>
+ <xs:enumeration value="AUDIO_STREAM_TTS"/>
+ <xs:enumeration value="AUDIO_STREAM_ACCESSIBILITY"/>
+ <xs:enumeration value="AUDIO_STREAM_ASSISTANT"/>
+ <xs:enumeration value="AUDIO_STREAM_REROUTING"/>
+ <xs:enumeration value="AUDIO_STREAM_PATCH"/>
+ <xs:enumeration value="AUDIO_STREAM_CALL_ASSISTANT"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="audioSource">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ An audio source defines the intended use case for the sound being recorded.
+ Please consult frameworks/base/media/java/android/media/MediaRecorder.java
+ for the description of each value.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="AUDIO_SOURCE_DEFAULT"/>
+ <xs:enumeration value="AUDIO_SOURCE_MIC"/>
+ <xs:enumeration value="AUDIO_SOURCE_VOICE_UPLINK"/>
+ <xs:enumeration value="AUDIO_SOURCE_VOICE_DOWNLINK"/>
+ <xs:enumeration value="AUDIO_SOURCE_VOICE_CALL"/>
+ <xs:enumeration value="AUDIO_SOURCE_CAMCORDER"/>
+ <xs:enumeration value="AUDIO_SOURCE_VOICE_RECOGNITION"/>
+ <xs:enumeration value="AUDIO_SOURCE_VOICE_COMMUNICATION"/>
+ <xs:enumeration value="AUDIO_SOURCE_REMOTE_SUBMIX"/>
+ <xs:enumeration value="AUDIO_SOURCE_UNPROCESSED"/>
+ <xs:enumeration value="AUDIO_SOURCE_VOICE_PERFORMANCE"/>
+ <xs:enumeration value="AUDIO_SOURCE_ECHO_REFERENCE"/>
+ <xs:enumeration value="AUDIO_SOURCE_FM_TUNER"/>
+ <xs:enumeration value="AUDIO_SOURCE_HOTWORD"/>
+ <xs:enumeration value="AUDIO_SOURCE_ULTRASOUND"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <!-- Enum values of device_category from Volume.h. -->
+ <xs:simpleType name="deviceCategory">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="DEVICE_CATEGORY_HEADSET"/>
+ <xs:enumeration value="DEVICE_CATEGORY_SPEAKER"/>
+ <xs:enumeration value="DEVICE_CATEGORY_EARPIECE"/>
+ <xs:enumeration value="DEVICE_CATEGORY_EXT_MEDIA"/>
+ <xs:enumeration value="DEVICE_CATEGORY_HEARING_AID"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="volume">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ Volume section defines a volume curve for a given use case and device category.
+ It contains a list of points of this curve expressing the attenuation in Millibels
+ for a given volume index from 0 to 100.
+ <volume stream="AUDIO_STREAM_MUSIC" deviceCategory="DEVICE_CATEGORY_SPEAKER">
+ <point>0,-9600</point>
+ <point>100,0</point>
+ </volume>
+
+ It may also reference a reference/@name to avoid duplicating curves.
+ <volume stream="AUDIO_STREAM_MUSIC" deviceCategory="DEVICE_CATEGORY_SPEAKER"
+ ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+ <reference name="DEFAULT_MEDIA_VOLUME_CURVE">
+ <point>0,-9600</point>
+ <point>100,0</point>
+ </reference>
+ </xs:documentation>
+ </xs:annotation>
+ <xs:sequence>
+ <xs:element name="point" type="volumePoint" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="stream" type="audioStreamType"/>
+ <xs:attribute name="deviceCategory" type="deviceCategory"/>
+ <xs:attribute name="ref" type="xs:token" use="optional"/>
+ </xs:complexType>
+ <xs:complexType name="reference">
+ <xs:sequence>
+ <xs:element name="point" type="volumePoint" minOccurs="2" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:token" use="required"/>
+ </xs:complexType>
+ <xs:complexType name="surroundSound">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ Surround Sound section provides configuration related to handling of
+ multi-channel formats.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:sequence>
+ <xs:element name="formats" type="surroundFormats"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:simpleType name="audioFormatsList">
+ <xs:list itemType="extendableAudioFormat" />
+ </xs:simpleType>
+ <xs:complexType name="surroundFormats">
+ <xs:sequence>
+ <xs:element name="format" minOccurs="0" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:attribute name="name" type="extendableAudioFormat" use="required"/>
+ <xs:attribute name="subformats" type="audioFormatsList" />
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:simpleType name="engineSuffix">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="default"/>
+ <xs:enumeration value="configurable"/>
+ </xs:restriction>
+ </xs:simpleType>
+</xs:schema>
diff --git a/audio/aidl/default/dynamicProcessing/Android.bp b/audio/aidl/default/dynamicProcessing/Android.bp
new file mode 100644
index 0000000..3697ba3
--- /dev/null
+++ b/audio/aidl/default/dynamicProcessing/Android.bp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_shared {
+ name: "libdynamicsprocessingsw",
+ defaults: [
+ "aidlaudioeffectservice_defaults",
+ "latest_android_media_audio_common_types_ndk_shared",
+ "latest_android_hardware_audio_effect_ndk_shared",
+ ],
+ srcs: [
+ "DynamicsProcessingSw.cpp",
+ ":effectCommonFile",
+ ],
+ visibility: [
+ "//hardware/interfaces/audio/aidl/default",
+ ],
+}
diff --git a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp
new file mode 100644
index 0000000..3920a58
--- /dev/null
+++ b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cstddef>
+#define LOG_TAG "AHAL_DynamicsProcessingSw"
+#include <Utils.h>
+#include <algorithm>
+#include <unordered_set>
+
+#include <android-base/logging.h>
+#include <fmq/AidlMessageQueue.h>
+
+#include "DynamicsProcessingSw.h"
+
+using aidl::android::hardware::audio::effect::DynamicsProcessingSw;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kDynamicsProcessingSwImplUUID;
+using aidl::android::hardware::audio::effect::State;
+using aidl::android::media::audio::common::AudioUuid;
+
+extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
+ std::shared_ptr<IEffect>* instanceSpp) {
+ if (!in_impl_uuid || *in_impl_uuid != kDynamicsProcessingSwImplUUID) {
+ LOG(ERROR) << __func__ << "uuid not supported";
+ return EX_ILLEGAL_ARGUMENT;
+ }
+ if (instanceSpp) {
+ *instanceSpp = ndk::SharedRefBase::make<DynamicsProcessingSw>();
+ LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
+ return EX_NONE;
+ } else {
+ LOG(ERROR) << __func__ << " invalid input parameter!";
+ return EX_ILLEGAL_ARGUMENT;
+ }
+}
+
+extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
+ if (!instanceSp) {
+ return EX_NONE;
+ }
+ State state;
+ ndk::ScopedAStatus status = instanceSp->getState(&state);
+ if (!status.isOk() || State::INIT != state) {
+ LOG(ERROR) << __func__ << " instance " << instanceSp.get()
+ << " in state: " << toString(state) << ", status: " << status.getDescription();
+ return EX_ILLEGAL_STATE;
+ }
+ LOG(DEBUG) << __func__ << " instance " << instanceSp.get() << " destroyed";
+ return EX_NONE;
+}
+
+namespace aidl::android::hardware::audio::effect {
+
+ndk::ScopedAStatus DynamicsProcessingSw::getDescriptor(Descriptor* _aidl_return) {
+ LOG(DEBUG) << __func__ << kDescriptor.toString();
+ *_aidl_return = kDescriptor;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus DynamicsProcessingSw::setParameterSpecific(const Parameter::Specific& specific) {
+ RETURN_IF(Parameter::Specific::dynamicsProcessing != specific.getTag(), EX_ILLEGAL_ARGUMENT,
+ "EffectNotSupported");
+ std::lock_guard lg(mMutex);
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+ mSpecificParam = specific.get<Parameter::Specific::dynamicsProcessing>();
+ LOG(DEBUG) << __func__ << " success with: " << specific.toString();
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus DynamicsProcessingSw::getParameterSpecific(const Parameter::Id& id,
+ Parameter::Specific* specific) {
+ auto tag = id.getTag();
+ RETURN_IF(Parameter::Id::dynamicsProcessingTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
+ specific->set<Parameter::Specific::dynamicsProcessing>(mSpecificParam);
+ return ndk::ScopedAStatus::ok();
+}
+
+std::shared_ptr<EffectContext> DynamicsProcessingSw::createContext(
+ const Parameter::Common& common) {
+ if (mContext) {
+ LOG(DEBUG) << __func__ << " context already exist";
+ return mContext;
+ }
+ mContext = std::make_shared<DynamicsProcessingSwContext>(1 /* statusFmqDepth */, common);
+ return mContext;
+}
+
+RetCode DynamicsProcessingSw::releaseContext() {
+ if (mContext) {
+ mContext.reset();
+ }
+ return RetCode::SUCCESS;
+}
+
+// Processing method running in EffectWorker thread.
+IEffect::Status DynamicsProcessingSw::effectProcessImpl(float* in, float* out, int process) {
+ // TODO: get data buffer and process.
+ LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
+ for (int i = 0; i < process; i++) {
+ *out++ = *in++;
+ }
+ return {STATUS_OK, process, process};
+}
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h
new file mode 100644
index 0000000..2bc2762
--- /dev/null
+++ b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/audio/effect/BnEffect.h>
+#include <fmq/AidlMessageQueue.h>
+#include <cstdlib>
+#include <memory>
+
+#include "effect-impl/EffectImpl.h"
+#include "effect-impl/EffectUUID.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+class DynamicsProcessingSwContext final : public EffectContext {
+ public:
+ DynamicsProcessingSwContext(int statusDepth, const Parameter::Common& common)
+ : EffectContext(statusDepth, common) {
+ LOG(DEBUG) << __func__;
+ }
+ // TODO: add specific context here
+};
+
+class DynamicsProcessingSw final : public EffectImpl {
+ public:
+ DynamicsProcessingSw() { LOG(DEBUG) << __func__; }
+ ~DynamicsProcessingSw() {
+ cleanUp();
+ LOG(DEBUG) << __func__;
+ }
+
+ ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
+ ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
+ ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
+ Parameter::Specific* specific) override;
+ IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+ std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+ RetCode releaseContext() override;
+
+ private:
+ std::shared_ptr<DynamicsProcessingSwContext> mContext;
+ /* capabilities */
+ const DynamicsProcessing::Capability kCapability;
+ /* Effect descriptor */
+ const Descriptor kDescriptor = {
+ .common = {.id = {.type = kDynamicsProcessingTypeUUID,
+ .uuid = kDynamicsProcessingSwImplUUID,
+ .proxy = std::nullopt},
+ .flags = {.type = Flags::Type::INSERT,
+ .insert = Flags::Insert::FIRST,
+ .volume = Flags::Volume::CTRL},
+ .name = "DynamicsProcessingSw",
+ .implementor = "The Android Open Source Project"},
+ .capability = Capability::make<Capability::dynamicsProcessing>(kCapability)};
+
+ /* parameters */
+ DynamicsProcessing mSpecificParam;
+};
+} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/envReverb/Android.bp b/audio/aidl/default/envReverb/Android.bp
new file mode 100644
index 0000000..c239ee5
--- /dev/null
+++ b/audio/aidl/default/envReverb/Android.bp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_shared {
+ name: "libenvreverbsw",
+ defaults: [
+ "aidlaudioeffectservice_defaults",
+ "latest_android_media_audio_common_types_ndk_shared",
+ "latest_android_hardware_audio_effect_ndk_shared",
+ ],
+ srcs: [
+ "EnvReverbSw.cpp",
+ ":effectCommonFile",
+ ],
+ visibility: [
+ "//hardware/interfaces/audio/aidl/default",
+ ],
+}
diff --git a/audio/aidl/default/envReverb/EnvReverbSw.cpp b/audio/aidl/default/envReverb/EnvReverbSw.cpp
new file mode 100644
index 0000000..ad447ab
--- /dev/null
+++ b/audio/aidl/default/envReverb/EnvReverbSw.cpp
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cstddef>
+#define LOG_TAG "AHAL_EnvReverbSw"
+#include <Utils.h>
+#include <algorithm>
+#include <unordered_set>
+
+#include <android-base/logging.h>
+#include <fmq/AidlMessageQueue.h>
+
+#include "EnvReverbSw.h"
+
+using aidl::android::hardware::audio::effect::EnvReverbSw;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kEnvReverbSwImplUUID;
+using aidl::android::hardware::audio::effect::State;
+using aidl::android::media::audio::common::AudioUuid;
+
+extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
+ std::shared_ptr<IEffect>* instanceSpp) {
+ if (!in_impl_uuid || *in_impl_uuid != kEnvReverbSwImplUUID) {
+ LOG(ERROR) << __func__ << "uuid not supported";
+ return EX_ILLEGAL_ARGUMENT;
+ }
+ if (instanceSpp) {
+ *instanceSpp = ndk::SharedRefBase::make<EnvReverbSw>();
+ LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
+ return EX_NONE;
+ } else {
+ LOG(ERROR) << __func__ << " invalid input parameter!";
+ return EX_ILLEGAL_ARGUMENT;
+ }
+}
+
+extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
+ if (!instanceSp) {
+ return EX_NONE;
+ }
+ State state;
+ ndk::ScopedAStatus status = instanceSp->getState(&state);
+ if (!status.isOk() || State::INIT != state) {
+ LOG(ERROR) << __func__ << " instance " << instanceSp.get()
+ << " in state: " << toString(state) << ", status: " << status.getDescription();
+ return EX_ILLEGAL_STATE;
+ }
+ LOG(DEBUG) << __func__ << " instance " << instanceSp.get() << " destroyed";
+ return EX_NONE;
+}
+
+namespace aidl::android::hardware::audio::effect {
+
+ndk::ScopedAStatus EnvReverbSw::getDescriptor(Descriptor* _aidl_return) {
+ LOG(DEBUG) << __func__ << kDescriptor.toString();
+ *_aidl_return = kDescriptor;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EnvReverbSw::setParameterSpecific(const Parameter::Specific& specific) {
+ RETURN_IF(Parameter::Specific::reverb != specific.getTag(), EX_ILLEGAL_ARGUMENT,
+ "EffectNotSupported");
+ std::lock_guard lg(mMutex);
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+ mSpecificParam = specific.get<Parameter::Specific::reverb>();
+ LOG(DEBUG) << __func__ << " success with: " << specific.toString();
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EnvReverbSw::getParameterSpecific(const Parameter::Id& id,
+ Parameter::Specific* specific) {
+ auto tag = id.getTag();
+ RETURN_IF(Parameter::Id::reverbTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
+ specific->set<Parameter::Specific::reverb>(mSpecificParam);
+ return ndk::ScopedAStatus::ok();
+}
+
+std::shared_ptr<EffectContext> EnvReverbSw::createContext(const Parameter::Common& common) {
+ if (mContext) {
+ LOG(DEBUG) << __func__ << " context already exist";
+ return mContext;
+ }
+ mContext = std::make_shared<EnvReverbSwContext>(1 /* statusFmqDepth */, common);
+ return mContext;
+}
+
+RetCode EnvReverbSw::releaseContext() {
+ if (mContext) {
+ mContext.reset();
+ }
+ return RetCode::SUCCESS;
+}
+
+// Processing method running in EffectWorker thread.
+IEffect::Status EnvReverbSw::effectProcessImpl(float* in, float* out, int process) {
+ // TODO: get data buffer and process.
+ LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
+ for (int i = 0; i < process; i++) {
+ *out++ = *in++;
+ }
+ return {STATUS_OK, process, process};
+}
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/envReverb/EnvReverbSw.h b/audio/aidl/default/envReverb/EnvReverbSw.h
new file mode 100644
index 0000000..5a9ab27
--- /dev/null
+++ b/audio/aidl/default/envReverb/EnvReverbSw.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/audio/effect/BnEffect.h>
+#include <fmq/AidlMessageQueue.h>
+#include <cstdlib>
+#include <memory>
+
+#include "effect-impl/EffectImpl.h"
+#include "effect-impl/EffectUUID.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+class EnvReverbSwContext final : public EffectContext {
+ public:
+ EnvReverbSwContext(int statusDepth, const Parameter::Common& common)
+ : EffectContext(statusDepth, common) {
+ LOG(DEBUG) << __func__;
+ }
+ // TODO: add specific context here
+};
+
+class EnvReverbSw final : public EffectImpl {
+ public:
+ EnvReverbSw() { LOG(DEBUG) << __func__; }
+ ~EnvReverbSw() {
+ cleanUp();
+ LOG(DEBUG) << __func__;
+ }
+
+ ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
+ ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
+ ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
+ Parameter::Specific* specific) override;
+ IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+ std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+ RetCode releaseContext() override;
+
+ private:
+ std::shared_ptr<EnvReverbSwContext> mContext;
+ /* capabilities */
+ const Reverb::Capability kCapability;
+ /* Effect descriptor */
+ const Descriptor kDescriptor = {
+ .common = {.id = {.type = kEnvReverbTypeUUID,
+ .uuid = kEnvReverbSwImplUUID,
+ .proxy = std::nullopt},
+ .flags = {.type = Flags::Type::INSERT,
+ .insert = Flags::Insert::FIRST,
+ .volume = Flags::Volume::CTRL},
+ .name = "EnvReverbSw",
+ .implementor = "The Android Open Source Project"},
+ .capability = Capability::make<Capability::reverb>(kCapability)};
+
+ /* parameters */
+ Reverb mSpecificParam;
+};
+} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/equalizer/Android.bp b/audio/aidl/default/equalizer/Android.bp
new file mode 100644
index 0000000..8de6b1a
--- /dev/null
+++ b/audio/aidl/default/equalizer/Android.bp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_shared {
+ name: "libequalizersw",
+ defaults: [
+ "aidlaudioeffectservice_defaults",
+ "latest_android_media_audio_common_types_ndk_shared",
+ "latest_android_hardware_audio_effect_ndk_shared",
+ ],
+ srcs: [
+ "EqualizerSw.cpp",
+ ":effectCommonFile",
+ ],
+ visibility: [
+ "//hardware/interfaces/audio/aidl/default",
+ ],
+}
diff --git a/audio/aidl/default/equalizer/EqualizerSw.cpp b/audio/aidl/default/equalizer/EqualizerSw.cpp
new file mode 100644
index 0000000..d61ef97
--- /dev/null
+++ b/audio/aidl/default/equalizer/EqualizerSw.cpp
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cstddef>
+#define LOG_TAG "AHAL_EqualizerSw"
+#include <Utils.h>
+#include <algorithm>
+#include <unordered_set>
+
+#include <android-base/logging.h>
+#include <fmq/AidlMessageQueue.h>
+
+#include "EqualizerSw.h"
+
+using aidl::android::hardware::audio::effect::EqualizerSw;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kEqualizerSwImplUUID;
+using aidl::android::hardware::audio::effect::State;
+using aidl::android::media::audio::common::AudioUuid;
+
+extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
+ std::shared_ptr<IEffect>* instanceSpp) {
+ if (!in_impl_uuid || *in_impl_uuid != kEqualizerSwImplUUID) {
+ LOG(ERROR) << __func__ << "uuid not supported";
+ return EX_ILLEGAL_ARGUMENT;
+ }
+ if (instanceSpp) {
+ *instanceSpp = ndk::SharedRefBase::make<EqualizerSw>();
+ LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
+ return EX_NONE;
+ } else {
+ LOG(ERROR) << __func__ << " invalid input parameter!";
+ return EX_ILLEGAL_ARGUMENT;
+ }
+}
+
+extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
+ State state;
+ ndk::ScopedAStatus status = instanceSp->getState(&state);
+ if (!status.isOk() || State::INIT != state) {
+ LOG(ERROR) << __func__ << " instance " << instanceSp.get()
+ << " in state: " << toString(state) << ", status: " << status.getDescription();
+ return EX_ILLEGAL_STATE;
+ }
+ LOG(DEBUG) << __func__ << " instance " << instanceSp.get() << " destroyed";
+ return EX_NONE;
+}
+
+namespace aidl::android::hardware::audio::effect {
+
+ndk::ScopedAStatus EqualizerSw::getDescriptor(Descriptor* _aidl_return) {
+ LOG(DEBUG) << __func__ << kDesc.toString();
+ *_aidl_return = kDesc;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EqualizerSw::setParameterSpecific(const Parameter::Specific& specific) {
+ RETURN_IF(Parameter::Specific::equalizer != specific.getTag(), EX_ILLEGAL_ARGUMENT,
+ "EffectNotSupported");
+ std::lock_guard lg(mMutex);
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+ auto& eqParam = specific.get<Parameter::Specific::equalizer>();
+ auto tag = eqParam.getTag();
+ switch (tag) {
+ case Equalizer::preset: {
+ RETURN_IF(mContext->setEqPreset(eqParam.get<Equalizer::preset>()) != RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setBandLevelsFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case Equalizer::bandLevels: {
+ RETURN_IF(mContext->setEqBandLevels(eqParam.get<Equalizer::bandLevels>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setBandLevelsFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ default: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "EqTagNotSupported");
+ }
+ }
+
+ LOG(ERROR) << __func__ << " unsupported eq param tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "ParamNotSupported");
+}
+
+ndk::ScopedAStatus EqualizerSw::getParameterSpecific(const Parameter::Id& id,
+ Parameter::Specific* specific) {
+ auto tag = id.getTag();
+ RETURN_IF(Parameter::Id::equalizerTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
+ auto eqId = id.get<Parameter::Id::equalizerTag>();
+ auto eqIdTag = eqId.getTag();
+ switch (eqIdTag) {
+ case Equalizer::Id::commonTag:
+ return getParameterEqualizer(eqId.get<Equalizer::Id::commonTag>(), specific);
+ default:
+ LOG(ERROR) << __func__ << " tag " << toString(eqIdTag) << " not supported";
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "EqualizerTagNotSupported");
+ }
+}
+
+ndk::ScopedAStatus EqualizerSw::getParameterEqualizer(const Equalizer::Tag& tag,
+ Parameter::Specific* specific) {
+ std::lock_guard lg(mMutex);
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+ Equalizer eqParam;
+ switch (tag) {
+ case Equalizer::bandLevels: {
+ eqParam.set<Equalizer::bandLevels>(mContext->getEqBandLevels());
+ break;
+ }
+ case Equalizer::preset: {
+ eqParam.set<Equalizer::preset>(mContext->getEqPreset());
+ break;
+ }
+ default: {
+ LOG(ERROR) << __func__ << " not handled tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "unsupportedTag");
+ }
+ }
+
+ specific->set<Parameter::Specific::equalizer>(eqParam);
+ return ndk::ScopedAStatus::ok();
+}
+
+std::shared_ptr<EffectContext> EqualizerSw::createContext(const Parameter::Common& common) {
+ if (mContext) {
+ LOG(DEBUG) << __func__ << " context already exist";
+ return mContext;
+ }
+ mContext = std::make_shared<EqualizerSwContext>(1 /* statusFmqDepth */, common);
+ return mContext;
+}
+
+RetCode EqualizerSw::releaseContext() {
+ if (mContext) {
+ mContext.reset();
+ }
+ return RetCode::SUCCESS;
+}
+
+// Processing method running in EffectWorker thread.
+IEffect::Status EqualizerSw::effectProcessImpl(float* in, float* out, int process) {
+ // TODO: get data buffer and process.
+ LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
+ for (int i = 0; i < process; i++) {
+ *out++ = *in++;
+ }
+ return {STATUS_OK, process, process};
+}
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/equalizer/EqualizerSw.h b/audio/aidl/default/equalizer/EqualizerSw.h
new file mode 100644
index 0000000..aa4587a
--- /dev/null
+++ b/audio/aidl/default/equalizer/EqualizerSw.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/audio/effect/BnEffect.h>
+#include <fmq/AidlMessageQueue.h>
+#include <cstdlib>
+#include <memory>
+
+#include "effect-impl/EffectImpl.h"
+#include "effect-impl/EffectUUID.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+class EqualizerSwContext final : public EffectContext {
+ public:
+ EqualizerSwContext(int statusDepth, const Parameter::Common& common)
+ : EffectContext(statusDepth, common) {
+ LOG(DEBUG) << __func__;
+ }
+
+ RetCode setEqPreset(const int& presetIdx) {
+ if (presetIdx < 0 || presetIdx >= NUM_OF_PRESETS) {
+ return RetCode::ERROR_ILLEGAL_PARAMETER;
+ }
+ mPreset = presetIdx;
+ return RetCode::SUCCESS;
+ }
+ int getEqPreset() { return mPreset; }
+
+ RetCode setEqBandLevels(const std::vector<Equalizer::BandLevel>& bandLevels) {
+ if (bandLevels.size() > NUM_OF_BANDS) {
+ LOG(ERROR) << __func__ << " return because size exceed " << NUM_OF_BANDS;
+ return RetCode::ERROR_ILLEGAL_PARAMETER;
+ }
+ RetCode ret = RetCode::SUCCESS;
+ for (auto& it : bandLevels) {
+ if (it.index >= NUM_OF_BANDS || it.index < 0) {
+ LOG(ERROR) << __func__ << " index illegal, skip: " << it.index << " - "
+ << it.levelMb;
+ ret = RetCode::ERROR_ILLEGAL_PARAMETER;
+ }
+ mBandLevels[it.index] = it.levelMb;
+ }
+ return ret;
+ }
+
+ std::vector<Equalizer::BandLevel> getEqBandLevels() {
+ std::vector<Equalizer::BandLevel> bandLevels;
+ for (int i = 0; i < NUM_OF_BANDS; i++) {
+ bandLevels.push_back({i, mBandLevels[i]});
+ }
+ return bandLevels;
+ }
+
+ private:
+ static const int NUM_OF_BANDS = 5;
+ static const int NUM_OF_PRESETS = 10;
+ static const int PRESET_CUSTOM = -1;
+ // preset band level
+ int mPreset = PRESET_CUSTOM;
+ int32_t mBandLevels[NUM_OF_BANDS] = {3, 0, 0, 0, 3};
+
+ // Add equalizer specific context for processing here
+};
+
+class EqualizerSw final : public EffectImpl {
+ public:
+ EqualizerSw() { LOG(DEBUG) << __func__; }
+ ~EqualizerSw() {
+ cleanUp();
+ LOG(DEBUG) << __func__;
+ }
+
+ ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
+ ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
+ ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
+ Parameter::Specific* specific) override;
+ IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+ std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+ RetCode releaseContext() override;
+
+ private:
+ std::shared_ptr<EqualizerSwContext> mContext;
+ /* capabilities */
+ const std::vector<Equalizer::BandFrequency> mBandFrequency = {{0, 30000, 120000},
+ {1, 120001, 460000},
+ {2, 460001, 1800000},
+ {3, 1800001, 7000000},
+ {4, 7000001, 20000000}};
+ // presets supported by the device
+ const std::vector<Equalizer::Preset> mPresets = {
+ {0, "Normal"}, {1, "Classical"}, {2, "Dance"}, {3, "Flat"}, {4, "Folk"},
+ {5, "Heavy Metal"}, {6, "Hip Hop"}, {7, "Jazz"}, {8, "Pop"}, {9, "Rock"}};
+
+ const Equalizer::Capability kEqCap = {.bandFrequencies = mBandFrequency, .presets = mPresets};
+ // Effect descriptor.
+ const Descriptor kDesc = {.common = {.id = {.type = kEqualizerTypeUUID,
+ .uuid = kEqualizerSwImplUUID,
+ .proxy = kEqualizerProxyUUID},
+ .flags = {.type = Flags::Type::INSERT,
+ .insert = Flags::Insert::FIRST,
+ .volume = Flags::Volume::CTRL},
+ .name = "EqualizerSw",
+ .implementor = "The Android Open Source Project"},
+ .capability = Capability::make<Capability::equalizer>(kEqCap)};
+
+ ndk::ScopedAStatus getParameterEqualizer(const Equalizer::Tag& tag,
+ Parameter::Specific* specific);
+};
+} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/hapticGenerator/Android.bp b/audio/aidl/default/hapticGenerator/Android.bp
new file mode 100644
index 0000000..a632130
--- /dev/null
+++ b/audio/aidl/default/hapticGenerator/Android.bp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_shared {
+ name: "libhapticgeneratorsw",
+ defaults: [
+ "aidlaudioeffectservice_defaults",
+ "latest_android_media_audio_common_types_ndk_shared",
+ "latest_android_hardware_audio_effect_ndk_shared",
+ ],
+ srcs: [
+ "HapticGeneratorSw.cpp",
+ ":effectCommonFile",
+ ],
+ visibility: [
+ "//hardware/interfaces/audio/aidl/default",
+ ],
+}
diff --git a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp
new file mode 100644
index 0000000..fd5ea34
--- /dev/null
+++ b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cstddef>
+#define LOG_TAG "AHAL_HapticGeneratorSw"
+#include <Utils.h>
+#include <algorithm>
+#include <unordered_set>
+
+#include <android-base/logging.h>
+#include <fmq/AidlMessageQueue.h>
+
+#include "HapticGeneratorSw.h"
+
+using aidl::android::hardware::audio::effect::HapticGeneratorSw;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kHapticGeneratorSwImplUUID;
+using aidl::android::hardware::audio::effect::State;
+using aidl::android::media::audio::common::AudioUuid;
+
+extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
+ std::shared_ptr<IEffect>* instanceSpp) {
+ if (!in_impl_uuid || *in_impl_uuid != kHapticGeneratorSwImplUUID) {
+ LOG(ERROR) << __func__ << "uuid not supported";
+ return EX_ILLEGAL_ARGUMENT;
+ }
+ if (instanceSpp) {
+ *instanceSpp = ndk::SharedRefBase::make<HapticGeneratorSw>();
+ LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
+ return EX_NONE;
+ } else {
+ LOG(ERROR) << __func__ << " invalid input parameter!";
+ return EX_ILLEGAL_ARGUMENT;
+ }
+}
+
+extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
+ if (!instanceSp) {
+ return EX_NONE;
+ }
+ State state;
+ ndk::ScopedAStatus status = instanceSp->getState(&state);
+ if (!status.isOk() || State::INIT != state) {
+ LOG(ERROR) << __func__ << " instance " << instanceSp.get()
+ << " in state: " << toString(state) << ", status: " << status.getDescription();
+ return EX_ILLEGAL_STATE;
+ }
+ LOG(DEBUG) << __func__ << " instance " << instanceSp.get() << " destroyed";
+ return EX_NONE;
+}
+
+namespace aidl::android::hardware::audio::effect {
+
+ndk::ScopedAStatus HapticGeneratorSw::getDescriptor(Descriptor* _aidl_return) {
+ LOG(DEBUG) << __func__ << kDescriptor.toString();
+ *_aidl_return = kDescriptor;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus HapticGeneratorSw::setParameterSpecific(const Parameter::Specific& specific) {
+ RETURN_IF(Parameter::Specific::hapticGenerator != specific.getTag(), EX_ILLEGAL_ARGUMENT,
+ "EffectNotSupported");
+ std::lock_guard lg(mMutex);
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+ mSpecificParam = specific.get<Parameter::Specific::hapticGenerator>();
+ LOG(DEBUG) << __func__ << " success with: " << specific.toString();
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus HapticGeneratorSw::getParameterSpecific(const Parameter::Id& id,
+ Parameter::Specific* specific) {
+ auto tag = id.getTag();
+ RETURN_IF(Parameter::Id::hapticGeneratorTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
+ specific->set<Parameter::Specific::hapticGenerator>(mSpecificParam);
+ return ndk::ScopedAStatus::ok();
+}
+
+std::shared_ptr<EffectContext> HapticGeneratorSw::createContext(const Parameter::Common& common) {
+ if (mContext) {
+ LOG(DEBUG) << __func__ << " context already exist";
+ return mContext;
+ }
+ mContext = std::make_shared<HapticGeneratorSwContext>(1 /* statusFmqDepth */, common);
+ return mContext;
+}
+
+RetCode HapticGeneratorSw::releaseContext() {
+ if (mContext) {
+ mContext.reset();
+ }
+ return RetCode::SUCCESS;
+}
+
+// Processing method running in EffectWorker thread.
+IEffect::Status HapticGeneratorSw::effectProcessImpl(float* in, float* out, int process) {
+ // TODO: get data buffer and process.
+ LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
+ for (int i = 0; i < process; i++) {
+ *out++ = *in++;
+ }
+ return {STATUS_OK, process, process};
+}
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h
new file mode 100644
index 0000000..518aa87
--- /dev/null
+++ b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/audio/effect/BnEffect.h>
+#include <fmq/AidlMessageQueue.h>
+#include <cstdlib>
+#include <memory>
+
+#include "effect-impl/EffectImpl.h"
+#include "effect-impl/EffectUUID.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+class HapticGeneratorSwContext final : public EffectContext {
+ public:
+ HapticGeneratorSwContext(int statusDepth, const Parameter::Common& common)
+ : EffectContext(statusDepth, common) {
+ LOG(DEBUG) << __func__;
+ }
+ // TODO: add specific context here
+};
+
+class HapticGeneratorSw final : public EffectImpl {
+ public:
+ HapticGeneratorSw() { LOG(DEBUG) << __func__; }
+ ~HapticGeneratorSw() {
+ cleanUp();
+ LOG(DEBUG) << __func__;
+ }
+
+ ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
+ ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
+ ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
+ Parameter::Specific* specific) override;
+ IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+ std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+ RetCode releaseContext() override;
+
+ private:
+ std::shared_ptr<HapticGeneratorSwContext> mContext;
+ /* capabilities */
+ const HapticGenerator::Capability kCapability;
+ /* Effect descriptor */
+ const Descriptor kDescriptor = {
+ .common = {.id = {.type = kHapticGeneratorTypeUUID,
+ .uuid = kHapticGeneratorSwImplUUID,
+ .proxy = std::nullopt},
+ .flags = {.type = Flags::Type::INSERT,
+ .insert = Flags::Insert::FIRST,
+ .volume = Flags::Volume::CTRL},
+ .name = "HapticGeneratorSw",
+ .implementor = "The Android Open Source Project"},
+ .capability = Capability::make<Capability::hapticGenerator>(kCapability)};
+
+ /* parameters */
+ HapticGenerator mSpecificParam;
+};
+} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/core-impl/Config.h b/audio/aidl/default/include/core-impl/Config.h
new file mode 100644
index 0000000..4555efd
--- /dev/null
+++ b/audio/aidl/default/include/core-impl/Config.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/audio/core/BnConfig.h>
+
+namespace aidl::android::hardware::audio::core {
+
+class Config : public BnConfig {
+ ndk::ScopedAStatus getSurroundSoundConfig(SurroundSoundConfig* _aidl_return) override;
+};
+
+} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/Configuration.h b/audio/aidl/default/include/core-impl/Configuration.h
new file mode 100644
index 0000000..d5cd30b
--- /dev/null
+++ b/audio/aidl/default/include/core-impl/Configuration.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <map>
+#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>
+
+namespace aidl::android::hardware::audio::core::internal {
+
+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'.
+ 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;
+};
+
+Configuration& getNullPrimaryConfiguration();
+
+} // namespace aidl::android::hardware::audio::core::internal
diff --git a/audio/aidl/default/include/core-impl/Module.h b/audio/aidl/default/include/core-impl/Module.h
new file mode 100644
index 0000000..f7b85ed
--- /dev/null
+++ b/audio/aidl/default/include/core-impl/Module.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <map>
+#include <memory>
+#include <set>
+
+#include <aidl/android/hardware/audio/core/BnModule.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;
+
+ private:
+ ndk::ScopedAStatus setModuleDebug(
+ const ::aidl::android::hardware::audio::core::ModuleDebug& in_debug) override;
+ ndk::ScopedAStatus getTelephony(std::shared_ptr<ITelephony>* _aidl_return) override;
+ ndk::ScopedAStatus connectExternalDevice(
+ const ::aidl::android::media::audio::common::AudioPort& in_templateIdAndAdditionalData,
+ ::aidl::android::media::audio::common::AudioPort* _aidl_return) override;
+ ndk::ScopedAStatus disconnectExternalDevice(int32_t in_portId) override;
+ ndk::ScopedAStatus getAudioPatches(std::vector<AudioPatch>* _aidl_return) override;
+ ndk::ScopedAStatus getAudioPort(
+ int32_t in_portId,
+ ::aidl::android::media::audio::common::AudioPort* _aidl_return) override;
+ ndk::ScopedAStatus getAudioPortConfigs(
+ std::vector<::aidl::android::media::audio::common::AudioPortConfig>* _aidl_return)
+ override;
+ ndk::ScopedAStatus getAudioPorts(
+ std::vector<::aidl::android::media::audio::common::AudioPort>* _aidl_return) override;
+ ndk::ScopedAStatus getAudioRoutes(std::vector<AudioRoute>* _aidl_return) override;
+ ndk::ScopedAStatus getAudioRoutesForAudioPort(
+ int32_t in_portId,
+ std::vector<::aidl::android::hardware::audio::core::AudioRoute>* _aidl_return) override;
+ ndk::ScopedAStatus openInputStream(
+ const ::aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments&
+ in_args,
+ ::aidl::android::hardware::audio::core::IModule::OpenInputStreamReturn* _aidl_return)
+ override;
+ ndk::ScopedAStatus openOutputStream(
+ const ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments&
+ in_args,
+ ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn* _aidl_return)
+ override;
+ ndk::ScopedAStatus setAudioPatch(const AudioPatch& in_requested,
+ AudioPatch* _aidl_return) override;
+ ndk::ScopedAStatus setAudioPortConfig(
+ const ::aidl::android::media::audio::common::AudioPortConfig& in_requested,
+ ::aidl::android::media::audio::common::AudioPortConfig* out_suggested,
+ bool* _aidl_return) override;
+ ndk::ScopedAStatus resetAudioPatch(int32_t in_patchId) override;
+ ndk::ScopedAStatus resetAudioPortConfig(int32_t in_portConfigId) override;
+ ndk::ScopedAStatus getMasterMute(bool* _aidl_return) override;
+ ndk::ScopedAStatus setMasterMute(bool in_mute) override;
+ ndk::ScopedAStatus getMasterVolume(float* _aidl_return) override;
+ ndk::ScopedAStatus setMasterVolume(float in_volume) override;
+ ndk::ScopedAStatus getMicMute(bool* _aidl_return) override;
+ ndk::ScopedAStatus setMicMute(bool in_mute) override;
+ ndk::ScopedAStatus updateAudioMode(
+ ::aidl::android::hardware::audio::core::AudioMode in_mode) override;
+ ndk::ScopedAStatus updateScreenRotation(
+ ::aidl::android::hardware::audio::core::IModule::ScreenRotation in_rotation) override;
+ ndk::ScopedAStatus updateScreenState(bool in_isTurnedOn) override;
+
+ void cleanUpPatch(int32_t patchId);
+ ndk::ScopedAStatus createStreamContext(
+ int32_t in_portConfigId, int64_t in_bufferSizeFrames,
+ std::shared_ptr<IStreamCallback> asyncCallback,
+ ::aidl::android::hardware::audio::core::StreamContext* out_context);
+ ndk::ScopedAStatus findPortIdForNewStream(
+ int32_t in_portConfigId, ::aidl::android::media::audio::common::AudioPort** port);
+ internal::Configuration& getConfig();
+ void registerPatch(const AudioPatch& patch);
+ void updateStreamsConnectedState(const AudioPatch& oldPatch, const AudioPatch& newPatch);
+
+ // This value is used for all AudioPatches.
+ static constexpr int32_t kMinimumStreamBufferSizeFrames = 16;
+ // The maximum stream buffer size is 1 GiB = 2 ** 30 bytes;
+ static constexpr int32_t kMaximumStreamBufferSizeBytes = 1 << 30;
+
+ std::unique_ptr<internal::Configuration> mConfig;
+ ModuleDebug mDebug;
+ // Since it is required to return the same instance of the ITelephony, even
+ // if the client has released it on its side, we need to hold it via a strong pointer.
+ std::shared_ptr<ITelephony> mTelephony;
+ // ids of ports created at runtime via 'connectExternalDevice'.
+ std::set<int32_t> mConnectedDevicePorts;
+ Streams mStreams;
+ // Maps port ids and port config ids to patch ids.
+ // Multimap because both ports and configs can be used by multiple patches.
+ std::multimap<int32_t, int32_t> mPatches;
+ bool mMasterMute = false;
+ float mMasterVolume = 1.0f;
+ bool mMicMute = false;
+};
+
+} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h
new file mode 100644
index 0000000..3c96973
--- /dev/null
+++ b/audio/aidl/default/include/core-impl/Stream.h
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <atomic>
+#include <chrono>
+#include <cstdlib>
+#include <map>
+#include <memory>
+#include <optional>
+#include <variant>
+
+#include <StreamWorker.h>
+#include <aidl/android/hardware/audio/common/SinkMetadata.h>
+#include <aidl/android/hardware/audio/common/SourceMetadata.h>
+#include <aidl/android/hardware/audio/core/BnStreamIn.h>
+#include <aidl/android/hardware/audio/core/BnStreamOut.h>
+#include <aidl/android/hardware/audio/core/IStreamCallback.h>
+#include <aidl/android/hardware/audio/core/StreamDescriptor.h>
+#include <aidl/android/media/audio/common/AudioOffloadInfo.h>
+#include <fmq/AidlMessageQueue.h>
+#include <system/thread_defs.h>
+
+#include "core-impl/utils.h"
+
+namespace aidl::android::hardware::audio::core {
+
+// This class is similar to StreamDescriptor, but unlike
+// the descriptor, it actually owns the objects implementing
+// data exchange: FMQs etc, whereas StreamDescriptor only
+// contains their descriptors.
+class StreamContext {
+ public:
+ typedef ::android::AidlMessageQueue<
+ StreamDescriptor::Command,
+ ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
+ CommandMQ;
+ typedef ::android::AidlMessageQueue<
+ StreamDescriptor::Reply, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
+ ReplyMQ;
+ typedef ::android::AidlMessageQueue<
+ int8_t, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
+ DataMQ;
+
+ // Ensure that this value is not used by any of StreamDescriptor.State enums
+ static constexpr int32_t STATE_CLOSED = -1;
+
+ StreamContext() = default;
+ StreamContext(std::unique_ptr<CommandMQ> commandMQ, std::unique_ptr<ReplyMQ> replyMQ,
+ size_t frameSize, std::unique_ptr<DataMQ> dataMQ,
+ std::shared_ptr<IStreamCallback> asyncCallback, int transientStateDelayMs)
+ : mCommandMQ(std::move(commandMQ)),
+ mInternalCommandCookie(std::rand()),
+ mReplyMQ(std::move(replyMQ)),
+ mFrameSize(frameSize),
+ mDataMQ(std::move(dataMQ)),
+ mAsyncCallback(asyncCallback),
+ mTransientStateDelayMs(transientStateDelayMs) {}
+ StreamContext(StreamContext&& other)
+ : mCommandMQ(std::move(other.mCommandMQ)),
+ mInternalCommandCookie(other.mInternalCommandCookie),
+ mReplyMQ(std::move(other.mReplyMQ)),
+ mFrameSize(other.mFrameSize),
+ mDataMQ(std::move(other.mDataMQ)),
+ mAsyncCallback(other.mAsyncCallback),
+ mTransientStateDelayMs(other.mTransientStateDelayMs) {}
+ StreamContext& operator=(StreamContext&& other) {
+ mCommandMQ = std::move(other.mCommandMQ);
+ mInternalCommandCookie = other.mInternalCommandCookie;
+ mReplyMQ = std::move(other.mReplyMQ);
+ mFrameSize = other.mFrameSize;
+ mDataMQ = std::move(other.mDataMQ);
+ mAsyncCallback = other.mAsyncCallback;
+ mTransientStateDelayMs = other.mTransientStateDelayMs;
+ return *this;
+ }
+
+ void fillDescriptor(StreamDescriptor* desc);
+ std::shared_ptr<IStreamCallback> getAsyncCallback() const { return mAsyncCallback; }
+ CommandMQ* getCommandMQ() const { return mCommandMQ.get(); }
+ DataMQ* getDataMQ() const { return mDataMQ.get(); }
+ size_t getFrameSize() const { return mFrameSize; }
+ int getInternalCommandCookie() const { return mInternalCommandCookie; }
+ ReplyMQ* getReplyMQ() const { return mReplyMQ.get(); }
+ int getTransientStateDelayMs() const { return mTransientStateDelayMs; }
+ bool isValid() const;
+ void reset();
+
+ private:
+ std::unique_ptr<CommandMQ> mCommandMQ;
+ int mInternalCommandCookie; // The value used to confirm that the command was posted internally
+ std::unique_ptr<ReplyMQ> mReplyMQ;
+ size_t mFrameSize;
+ std::unique_ptr<DataMQ> mDataMQ;
+ std::shared_ptr<IStreamCallback> mAsyncCallback;
+ int mTransientStateDelayMs;
+};
+
+class StreamWorkerCommonLogic : public ::android::hardware::audio::common::StreamLogic {
+ public:
+ bool isClosed() const {
+ return static_cast<int32_t>(mState.load()) == StreamContext::STATE_CLOSED;
+ }
+ void setClosed() { mState = static_cast<StreamDescriptor::State>(StreamContext::STATE_CLOSED); }
+ void setIsConnected(bool connected) { mIsConnected = connected; }
+
+ protected:
+ explicit StreamWorkerCommonLogic(const StreamContext& context)
+ : mInternalCommandCookie(context.getInternalCommandCookie()),
+ mFrameSize(context.getFrameSize()),
+ mCommandMQ(context.getCommandMQ()),
+ mReplyMQ(context.getReplyMQ()),
+ mDataMQ(context.getDataMQ()),
+ mAsyncCallback(context.getAsyncCallback()),
+ mTransientStateDelayMs(context.getTransientStateDelayMs()) {}
+ std::string init() override;
+ void populateReply(StreamDescriptor::Reply* reply, bool isConnected) const;
+ void populateReplyWrongState(StreamDescriptor::Reply* reply,
+ const StreamDescriptor::Command& command) const;
+ void switchToTransientState(StreamDescriptor::State state) {
+ mState = state;
+ mTransientStateStart = std::chrono::steady_clock::now();
+ }
+
+ // Atomic fields are used both by the main and worker threads.
+ std::atomic<bool> mIsConnected = false;
+ static_assert(std::atomic<StreamDescriptor::State>::is_always_lock_free);
+ std::atomic<StreamDescriptor::State> mState = StreamDescriptor::State::STANDBY;
+ // All fields are used on the worker thread only.
+ const int mInternalCommandCookie;
+ const size_t mFrameSize;
+ StreamContext::CommandMQ* mCommandMQ;
+ StreamContext::ReplyMQ* mReplyMQ;
+ StreamContext::DataMQ* mDataMQ;
+ std::shared_ptr<IStreamCallback> mAsyncCallback;
+ const std::chrono::duration<int, std::milli> mTransientStateDelayMs;
+ std::chrono::time_point<std::chrono::steady_clock> mTransientStateStart;
+ // We use an array and the "size" field instead of a vector to be able to detect
+ // memory allocation issues.
+ std::unique_ptr<int8_t[]> mDataBuffer;
+ size_t mDataBufferSize;
+ long mFrameCount = 0;
+};
+
+class StreamInWorkerLogic : public StreamWorkerCommonLogic {
+ public:
+ static const std::string kThreadName;
+ explicit StreamInWorkerLogic(const StreamContext& context) : StreamWorkerCommonLogic(context) {}
+
+ protected:
+ Status cycle() override;
+
+ private:
+ bool read(size_t clientSize, StreamDescriptor::Reply* reply);
+};
+using StreamInWorker = ::android::hardware::audio::common::StreamWorker<StreamInWorkerLogic>;
+
+class StreamOutWorkerLogic : public StreamWorkerCommonLogic {
+ public:
+ static const std::string kThreadName;
+ explicit StreamOutWorkerLogic(const StreamContext& context)
+ : StreamWorkerCommonLogic(context) {}
+
+ protected:
+ Status cycle() override;
+
+ private:
+ bool write(size_t clientSize, StreamDescriptor::Reply* reply);
+};
+using StreamOutWorker = ::android::hardware::audio::common::StreamWorker<StreamOutWorkerLogic>;
+
+template <class Metadata, class StreamWorker>
+class StreamCommon {
+ public:
+ ndk::ScopedAStatus close();
+ ndk::ScopedAStatus init() {
+ return mWorker.start(StreamWorker::kThreadName, ANDROID_PRIORITY_AUDIO)
+ ? ndk::ScopedAStatus::ok()
+ : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
+ bool isClosed() const { return mWorker.isClosed(); }
+ void setIsConnected(bool connected) { mWorker.setIsConnected(connected); }
+ ndk::ScopedAStatus updateMetadata(const Metadata& metadata);
+
+ protected:
+ StreamCommon(const Metadata& metadata, StreamContext context)
+ : mMetadata(metadata), mContext(std::move(context)), mWorker(mContext) {}
+ ~StreamCommon();
+ void stopWorker();
+
+ Metadata mMetadata;
+ StreamContext mContext;
+ StreamWorker mWorker;
+};
+
+class StreamIn
+ : public StreamCommon<::aidl::android::hardware::audio::common::SinkMetadata, StreamInWorker>,
+ public BnStreamIn {
+ ndk::ScopedAStatus close() override {
+ return StreamCommon<::aidl::android::hardware::audio::common::SinkMetadata,
+ StreamInWorker>::close();
+ }
+ ndk::ScopedAStatus updateMetadata(const ::aidl::android::hardware::audio::common::SinkMetadata&
+ in_sinkMetadata) override {
+ return StreamCommon<::aidl::android::hardware::audio::common::SinkMetadata,
+ StreamInWorker>::updateMetadata(in_sinkMetadata);
+ }
+
+ public:
+ StreamIn(const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
+ StreamContext context);
+};
+
+class StreamOut : public StreamCommon<::aidl::android::hardware::audio::common::SourceMetadata,
+ StreamOutWorker>,
+ public BnStreamOut {
+ ndk::ScopedAStatus close() override {
+ return StreamCommon<::aidl::android::hardware::audio::common::SourceMetadata,
+ StreamOutWorker>::close();
+ }
+ ndk::ScopedAStatus updateMetadata(
+ const ::aidl::android::hardware::audio::common::SourceMetadata& in_sourceMetadata)
+ override {
+ return StreamCommon<::aidl::android::hardware::audio::common::SourceMetadata,
+ StreamOutWorker>::updateMetadata(in_sourceMetadata);
+ }
+
+ public:
+ StreamOut(const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
+ StreamContext context,
+ const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
+ offloadInfo);
+
+ private:
+ std::optional<::aidl::android::media::audio::common::AudioOffloadInfo> mOffloadInfo;
+};
+
+class StreamWrapper {
+ public:
+ explicit StreamWrapper(std::shared_ptr<StreamIn> streamIn) : mStream(streamIn) {}
+ explicit StreamWrapper(std::shared_ptr<StreamOut> streamOut) : mStream(streamOut) {}
+ bool isStreamOpen() const {
+ return std::visit(
+ [](auto&& ws) -> bool {
+ auto s = ws.lock();
+ return s && !s->isClosed();
+ },
+ mStream);
+ }
+ void setStreamIsConnected(bool connected) {
+ std::visit(
+ [&](auto&& ws) {
+ auto s = ws.lock();
+ if (s) s->setIsConnected(connected);
+ },
+ mStream);
+ }
+
+ private:
+ std::variant<std::weak_ptr<StreamIn>, std::weak_ptr<StreamOut>> mStream;
+};
+
+class Streams {
+ public:
+ Streams() = default;
+ Streams(const Streams&) = delete;
+ Streams& operator=(const Streams&) = delete;
+ size_t count(int32_t id) {
+ // Streams do not remove themselves from the collection on close.
+ erase_if(mStreams, [](const auto& pair) { return !pair.second.isStreamOpen(); });
+ return mStreams.count(id);
+ }
+ void insert(int32_t portId, int32_t portConfigId, StreamWrapper sw) {
+ mStreams.insert(std::pair{portConfigId, sw});
+ mStreams.insert(std::pair{portId, std::move(sw)});
+ }
+ void setStreamIsConnected(int32_t portConfigId, bool connected) {
+ if (auto it = mStreams.find(portConfigId); it != mStreams.end()) {
+ it->second.setStreamIsConnected(connected);
+ }
+ }
+
+ private:
+ // Maps port ids and port config ids to streams. Multimap because a port
+ // (not port config) can have multiple streams opened on it.
+ std::multimap<int32_t, StreamWrapper> mStreams;
+};
+
+} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/Telephony.h b/audio/aidl/default/include/core-impl/Telephony.h
new file mode 100644
index 0000000..597f3d6
--- /dev/null
+++ b/audio/aidl/default/include/core-impl/Telephony.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/binder_enums.h>
+
+#include <aidl/android/hardware/audio/core/BnTelephony.h>
+
+namespace aidl::android::hardware::audio::core {
+
+class Telephony : public BnTelephony {
+ private:
+ ndk::ScopedAStatus getSupportedAudioModes(std::vector<AudioMode>* _aidl_return) override;
+ ndk::ScopedAStatus switchAudioMode(AudioMode in_mode) override;
+
+ const std::vector<AudioMode> mSupportedAudioModes = {::ndk::enum_range<AudioMode>().begin(),
+ ::ndk::enum_range<AudioMode>().end()};
+};
+
+} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/utils.h b/audio/aidl/default/include/core-impl/utils.h
new file mode 100644
index 0000000..9d06f08
--- /dev/null
+++ b/audio/aidl/default/include/core-impl/utils.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <algorithm>
+#include <set>
+#include <vector>
+
+namespace aidl::android::hardware::audio::core {
+
+// Return whether all the elements in the vector are unique.
+template <typename T>
+bool all_unique(const std::vector<T>& v) {
+ return std::set<T>(v.begin(), v.end()).size() == v.size();
+}
+
+// Erase all the specified elements from a map.
+template <typename C, typename V>
+auto erase_all(C& c, const V& keys) {
+ auto oldSize = c.size();
+ for (auto& k : keys) {
+ c.erase(k);
+ }
+ return oldSize - c.size();
+}
+
+// Erase all the elements in the container that satisfy the provided predicate.
+template <typename C, typename P>
+auto erase_if(C& c, P pred) {
+ auto oldSize = c.size();
+ for (auto it = c.begin(); it != c.end();) {
+ if (pred(*it)) {
+ it = c.erase(it);
+ } else {
+ ++it;
+ }
+ }
+ return oldSize - c.size();
+}
+
+// Erase all the elements in the map that have specified values.
+template <typename C, typename V>
+auto erase_all_values(C& c, const V& values) {
+ return erase_if(c, [values](const auto& pair) { return values.count(pair.second) != 0; });
+}
+
+// Return non-zero count of elements for any of the provided keys.
+template <typename M, typename V>
+size_t count_any(const M& m, const V& keys) {
+ for (auto& k : keys) {
+ if (size_t c = m.count(k); c != 0) return c;
+ }
+ return 0;
+}
+
+// Assuming that M is a map whose values have an 'id' field,
+// find an element with the specified id.
+template <typename M>
+auto findById(M& m, int32_t id) {
+ return std::find_if(m.begin(), m.end(), [&](const auto& p) { return p.second.id == id; });
+}
+
+// Assuming that the vector contains elements with an 'id' field,
+// find an element with the specified id.
+template <typename T>
+auto findById(std::vector<T>& v, int32_t id) {
+ return std::find_if(v.begin(), v.end(), [&](const auto& e) { return e.id == id; });
+}
+
+// Return elements from the vector that have specified ids, also
+// optionally return which ids were not found.
+template <typename T>
+std::vector<T*> selectByIds(std::vector<T>& v, const std::vector<int32_t>& ids,
+ std::vector<int32_t>* missingIds = nullptr) {
+ std::vector<T*> result;
+ std::set<int32_t> idsSet(ids.begin(), ids.end());
+ for (size_t i = 0; i < v.size(); ++i) {
+ T& e = v[i];
+ if (idsSet.count(e.id) != 0) {
+ result.push_back(&v[i]);
+ idsSet.erase(e.id);
+ }
+ }
+ if (missingIds) {
+ *missingIds = std::vector(idsSet.begin(), idsSet.end());
+ }
+ return result;
+}
+
+} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/effect-impl/EffectContext.h b/audio/aidl/default/include/effect-impl/EffectContext.h
new file mode 100644
index 0000000..f608e12
--- /dev/null
+++ b/audio/aidl/default/include/effect-impl/EffectContext.h
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+#include <Utils.h>
+#include <android-base/logging.h>
+#include <utils/Log.h>
+#include <cstddef>
+#include <cstdint>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include <aidl/android/hardware/audio/effect/BnEffect.h>
+#include <fmq/AidlMessageQueue.h>
+#include "EffectTypes.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+class EffectContext {
+ public:
+ typedef ::android::AidlMessageQueue<
+ IEffect::Status, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
+ StatusMQ;
+ typedef ::android::AidlMessageQueue<
+ float, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
+ DataMQ;
+
+ EffectContext(size_t statusDepth, const Parameter::Common& common) {
+ mSessionId = common.session;
+ auto& input = common.input;
+ auto& output = common.output;
+
+ LOG_ALWAYS_FATAL_IF(
+ input.base.format.pcm != aidl::android::media::audio::common::PcmType::FLOAT_32_BIT,
+ "inputFormatNotFloat");
+ LOG_ALWAYS_FATAL_IF(output.base.format.pcm !=
+ aidl::android::media::audio::common::PcmType::FLOAT_32_BIT,
+ "outputFormatNotFloat");
+ mInputFrameSize = ::android::hardware::audio::common::getFrameSizeInBytes(
+ input.base.format, input.base.channelMask);
+ mOutputFrameSize = ::android::hardware::audio::common::getFrameSizeInBytes(
+ output.base.format, output.base.channelMask);
+ // in/outBuffer size in float (FMQ data format defined for DataMQ)
+ size_t inBufferSizeInFloat = input.frameCount * mInputFrameSize / sizeof(float);
+ size_t outBufferSizeInFloat = output.frameCount * mOutputFrameSize / sizeof(float);
+
+ mStatusMQ = std::make_shared<StatusMQ>(statusDepth, true /*configureEventFlagWord*/);
+ mInputMQ = std::make_shared<DataMQ>(inBufferSizeInFloat);
+ mOutputMQ = std::make_shared<DataMQ>(outBufferSizeInFloat);
+
+ if (!mStatusMQ->isValid() || !mInputMQ->isValid() || !mOutputMQ->isValid()) {
+ LOG(ERROR) << __func__ << " created invalid FMQ";
+ }
+ mWorkBuffer.reserve(std::max(inBufferSizeInFloat, outBufferSizeInFloat));
+ }
+ virtual ~EffectContext() {}
+
+ std::shared_ptr<StatusMQ> getStatusFmq() { return mStatusMQ; }
+ std::shared_ptr<DataMQ> getInputDataFmq() { return mInputMQ; }
+ std::shared_ptr<DataMQ> getOutputDataFmq() { return mOutputMQ; }
+
+ float* getWorkBuffer() { return static_cast<float*>(mWorkBuffer.data()); }
+ // TODO: update with actual available size
+ size_t availableToRead() { return mWorkBuffer.capacity(); }
+ size_t availableToWrite() { return mWorkBuffer.capacity(); }
+
+ // reset buffer status by abandon all data and status in FMQ
+ void resetBuffer() {
+ auto buffer = getWorkBuffer();
+ std::vector<IEffect::Status> status(mStatusMQ->availableToRead());
+ mInputMQ->read(buffer, mInputMQ->availableToRead());
+ mOutputMQ->read(buffer, mOutputMQ->availableToRead());
+ mStatusMQ->read(status.data(), mStatusMQ->availableToRead());
+ }
+
+ void dupeFmq(IEffect::OpenEffectReturn* effectRet) {
+ if (effectRet) {
+ effectRet->statusMQ = getStatusFmq()->dupeDesc();
+ effectRet->inputDataMQ = getInputDataFmq()->dupeDesc();
+ effectRet->outputDataMQ = getOutputDataFmq()->dupeDesc();
+ }
+ }
+ size_t getInputFrameSize() { return mInputFrameSize; }
+ size_t getOutputFrameSize() { return mOutputFrameSize; }
+ int getSessionId() { return mSessionId; }
+
+ virtual RetCode setOutputDevice(
+ const aidl::android::media::audio::common::AudioDeviceDescription& device) {
+ mOutputDevice = device;
+ return RetCode::SUCCESS;
+ }
+ virtual aidl::android::media::audio::common::AudioDeviceDescription getOutputDevice() {
+ return mOutputDevice;
+ }
+
+ virtual RetCode setAudioMode(const aidl::android::media::audio::common::AudioMode& mode) {
+ mMode = mode;
+ return RetCode::SUCCESS;
+ }
+ virtual aidl::android::media::audio::common::AudioMode getAudioMode() { return mMode; }
+
+ virtual RetCode setAudioSource(const aidl::android::media::audio::common::AudioSource& source) {
+ mSource = source;
+ return RetCode::SUCCESS;
+ }
+ virtual aidl::android::media::audio::common::AudioSource getAudioSource() { return mSource; }
+
+ virtual RetCode setVolumeStereo(const Parameter::VolumeStereo& volumeStereo) {
+ mVolumeStereo = volumeStereo;
+ return RetCode::SUCCESS;
+ }
+ virtual Parameter::VolumeStereo getVolumeStereo() { return mVolumeStereo; }
+
+ virtual RetCode setCommon(const Parameter::Common& common) {
+ mCommon = common;
+ LOG(ERROR) << __func__ << mCommon.toString();
+ return RetCode::SUCCESS;
+ }
+ virtual Parameter::Common getCommon() {
+ LOG(ERROR) << __func__ << mCommon.toString();
+ return mCommon;
+ }
+
+ protected:
+ // common parameters
+ int mSessionId = INVALID_AUDIO_SESSION_ID;
+ size_t mInputFrameSize, mOutputFrameSize;
+ Parameter::Common mCommon;
+ aidl::android::media::audio::common::AudioDeviceDescription mOutputDevice;
+ aidl::android::media::audio::common::AudioMode mMode;
+ aidl::android::media::audio::common::AudioSource mSource;
+ Parameter::VolumeStereo mVolumeStereo;
+
+ private:
+ // fmq and buffers
+ std::shared_ptr<StatusMQ> mStatusMQ;
+ std::shared_ptr<DataMQ> mInputMQ;
+ std::shared_ptr<DataMQ> mOutputMQ;
+ // TODO handle effect process input and output
+ // work buffer set by effect instances, the access and update are in same thread
+ std::vector<float> mWorkBuffer;
+};
+} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/effect-impl/EffectImpl.h b/audio/aidl/default/include/effect-impl/EffectImpl.h
new file mode 100644
index 0000000..d9825da
--- /dev/null
+++ b/audio/aidl/default/include/effect-impl/EffectImpl.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+#include <aidl/android/hardware/audio/effect/BnEffect.h>
+#include <fmq/AidlMessageQueue.h>
+#include <cstdlib>
+#include <memory>
+#include <mutex>
+
+#include "EffectTypes.h"
+#include "effect-impl/EffectContext.h"
+#include "effect-impl/EffectTypes.h"
+#include "effect-impl/EffectWorker.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+class EffectImpl : public BnEffect, public EffectWorker {
+ public:
+ EffectImpl() = default;
+ virtual ~EffectImpl() = default;
+
+ /**
+ * Each effect implementation CAN override these methods if necessary
+ * If you would like implement IEffect::open completely, override EffectImpl::open(), if you
+ * want to keep most of EffectImpl logic but have a little customize, try override openImpl().
+ * openImpl() will be called at the beginning of EffectImpl::open() without lock protection.
+ *
+ * Same for closeImpl().
+ */
+ virtual ndk::ScopedAStatus open(const Parameter::Common& common,
+ const std::optional<Parameter::Specific>& specific,
+ OpenEffectReturn* ret) override;
+ virtual ndk::ScopedAStatus close() override;
+ virtual ndk::ScopedAStatus command(CommandId id) override;
+ virtual ndk::ScopedAStatus commandStart() { return ndk::ScopedAStatus::ok(); }
+ virtual ndk::ScopedAStatus commandStop() { return ndk::ScopedAStatus::ok(); }
+ virtual ndk::ScopedAStatus commandReset() { return ndk::ScopedAStatus::ok(); }
+
+ virtual ndk::ScopedAStatus getState(State* state) override;
+ virtual ndk::ScopedAStatus setParameter(const Parameter& param) override;
+ virtual ndk::ScopedAStatus getParameter(const Parameter::Id& id, Parameter* param) override;
+ virtual IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+
+ virtual ndk::ScopedAStatus setParameterCommon(const Parameter& param);
+ virtual ndk::ScopedAStatus getParameterCommon(const Parameter::Tag& tag, Parameter* param);
+
+ /* Methods MUST be implemented by each effect instances */
+ virtual ndk::ScopedAStatus getDescriptor(Descriptor* desc) = 0;
+ virtual ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) = 0;
+ virtual ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
+ Parameter::Specific* specific) = 0;
+ virtual std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) = 0;
+ virtual RetCode releaseContext() = 0;
+
+ protected:
+ /*
+ * Lock is required if effectProcessImpl (which is running in an independent thread) needs to
+ * access state and parameters.
+ */
+ std::mutex mMutex;
+ State mState GUARDED_BY(mMutex) = State::INIT;
+
+ IEffect::Status status(binder_status_t status, size_t consumed, size_t produced);
+ void cleanUp();
+
+ private:
+ std::shared_ptr<EffectContext> mContext GUARDED_BY(mMutex);
+};
+} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/effect-impl/EffectThread.h b/audio/aidl/default/include/effect-impl/EffectThread.h
new file mode 100644
index 0000000..09a0000
--- /dev/null
+++ b/audio/aidl/default/include/effect-impl/EffectThread.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+#include <atomic>
+#include <string>
+#include <thread>
+
+#include <android-base/thread_annotations.h>
+#include <system/thread_defs.h>
+
+#include "effect-impl/EffectTypes.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+class EffectThread {
+ public:
+ // default priority is same as HIDL: ANDROID_PRIORITY_URGENT_AUDIO
+ EffectThread();
+ virtual ~EffectThread();
+
+ // called by effect implementation.
+ RetCode createThread(const std::string& name,
+ const int priority = ANDROID_PRIORITY_URGENT_AUDIO);
+ RetCode destroyThread();
+ RetCode startThread();
+ RetCode stopThread();
+
+ // Will call process() in a loop if the thread is running.
+ void threadLoop();
+
+ // User of EffectThread must implement the effect processing logic in this method.
+ virtual void process() = 0;
+ const int MAX_TASK_COMM_LEN = 15;
+
+ private:
+ std::mutex mMutex;
+ std::condition_variable mCv;
+ bool mExit GUARDED_BY(mMutex) = false;
+ bool mStop GUARDED_BY(mMutex) = true;
+ std::thread mThread;
+ int mPriority;
+ std::string mName;
+};
+} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/effect-impl/EffectTypes.h b/audio/aidl/default/include/effect-impl/EffectTypes.h
new file mode 100644
index 0000000..fc6a01d
--- /dev/null
+++ b/audio/aidl/default/include/effect-impl/EffectTypes.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+#include <ostream>
+#include <string>
+
+#include <aidl/android/hardware/audio/effect/BnEffect.h>
+#include <android-base/logging.h>
+
+typedef binder_exception_t (*EffectCreateFunctor)(
+ const ::aidl::android::media::audio::common::AudioUuid*,
+ std::shared_ptr<aidl::android::hardware::audio::effect::IEffect>*);
+typedef binder_exception_t (*EffectDestroyFunctor)(
+ const std::shared_ptr<aidl::android::hardware::audio::effect::IEffect>&);
+
+struct effect_dl_interface_s {
+ EffectCreateFunctor createEffectFunc;
+ EffectDestroyFunctor destroyEffectFunc;
+};
+
+namespace aidl::android::hardware::audio::effect {
+
+enum class RetCode {
+ SUCCESS,
+ ERROR_ILLEGAL_PARAMETER, /* Illegal parameter */
+ ERROR_THREAD, /* Effect thread error */
+ ERROR_NULL_POINTER, /* NULL pointer */
+ ERROR_ALIGNMENT_ERROR, /* Memory alignment error */
+ ERROR_BLOCK_SIZE_EXCEED, /* Maximum block size exceeded */
+ ERROR_EFFECT_LIB_ERROR
+};
+
+static const int INVALID_AUDIO_SESSION_ID = -1;
+
+inline std::ostream& operator<<(std::ostream& out, const RetCode& code) {
+ switch (code) {
+ case RetCode::SUCCESS:
+ return out << "SUCCESS";
+ case RetCode::ERROR_ILLEGAL_PARAMETER:
+ return out << "ERROR_ILLEGAL_PARAMETER";
+ case RetCode::ERROR_THREAD:
+ return out << "ERROR_THREAD";
+ case RetCode::ERROR_NULL_POINTER:
+ return out << "ERROR_NULL_POINTER";
+ case RetCode::ERROR_ALIGNMENT_ERROR:
+ return out << "ERROR_ALIGNMENT_ERROR";
+ case RetCode::ERROR_BLOCK_SIZE_EXCEED:
+ return out << "ERROR_BLOCK_SIZE_EXCEED";
+ case RetCode::ERROR_EFFECT_LIB_ERROR:
+ return out << "ERROR_EFFECT_LIB_ERROR";
+ }
+
+ return out << "EnumError: " << code;
+}
+
+#define RETURN_IF_ASTATUS_NOT_OK(status, message) \
+ do { \
+ const ::ndk::ScopedAStatus curr_status = (status); \
+ if (!curr_status.isOk()) { \
+ LOG(ERROR) << __func__ << ":" << __LINE__ \
+ << "return with status: " << curr_status.getDescription() << (message); \
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage( \
+ curr_status.getExceptionCode(), (message)); \
+ } \
+ } while (0)
+
+#define RETURN_IF(expr, exception, message) \
+ do { \
+ if (expr) { \
+ LOG(ERROR) << __func__ << ":" << __LINE__ << " return with expr " << #expr; \
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage((exception), (message)); \
+ } \
+ } while (0)
+
+#define RETURN_OK_IF(expr) \
+ do { \
+ if (expr) { \
+ LOG(INFO) << __func__ << ":" << __LINE__ << " return with expr " << #expr; \
+ return ndk::ScopedAStatus::ok(); \
+ } \
+ } while (0)
+
+#define RETURN_VALUE_IF(expr, ret, log) \
+ do { \
+ if (expr) { \
+ LOG(ERROR) << __func__ << ":" << __LINE__ << " return with expr " << #expr << (log); \
+ return ret; \
+ } \
+ } while (0)
+
+static inline bool stringToUuid(const char* str,
+ ::aidl::android::media::audio::common::AudioUuid* uuid) {
+ RETURN_VALUE_IF(!uuid || !str, false, "nullPtr");
+
+ uint32_t tmp[10];
+ if (sscanf(str, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x", tmp, tmp + 1, tmp + 2, tmp + 3,
+ tmp + 4, tmp + 5, tmp + 6, tmp + 7, tmp + 8, tmp + 9) < 10) {
+ return false;
+ }
+
+ uuid->timeLow = (uint32_t)tmp[0];
+ uuid->timeMid = (uint16_t)tmp[1];
+ uuid->timeHiAndVersion = (uint16_t)tmp[2];
+ uuid->clockSeq = (uint16_t)tmp[3];
+ uuid->node.insert(uuid->node.end(), {(uint8_t)tmp[4], (uint8_t)tmp[5], (uint8_t)tmp[6],
+ (uint8_t)tmp[7], (uint8_t)tmp[8], (uint8_t)tmp[9]});
+ return true;
+}
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/effect-impl/EffectUUID.h b/audio/aidl/default/include/effect-impl/EffectUUID.h
new file mode 100644
index 0000000..7709eab
--- /dev/null
+++ b/audio/aidl/default/include/effect-impl/EffectUUID.h
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+#include <map>
+
+#include <aidl/android/media/audio/common/AudioUuid.h>
+
+namespace aidl::android::hardware::audio::effect {
+
+using ::aidl::android::media::audio::common::AudioUuid;
+
+// ec7178ec-e5e1-4432-a3f4-4657e6795210
+static const AudioUuid kEffectNullUuid = {static_cast<int32_t>(0xec7178ec),
+ 0xe5e1,
+ 0x4432,
+ 0xa3f4,
+ {0x46, 0x57, 0xe6, 0x79, 0x52, 0x10}};
+// Zero UUID
+static const AudioUuid kEffectZeroUuid = {
+ static_cast<int32_t>(0x0), 0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
+
+// 0634f220-ddd4-11db-a0fc-0002a5d5c51b
+static const AudioUuid kBassBoostTypeUUID = {static_cast<int32_t>(0x0634f220),
+ 0xddd4,
+ 0x11db,
+ 0xa0fc,
+ {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+// fa8181f2-588b-11ed-9b6a-0242ac120002
+static const AudioUuid kBassBoostSwImplUUID = {static_cast<int32_t>(0xfa8181f2),
+ 0x588b,
+ 0x11ed,
+ 0x9b6a,
+ {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// fa81862a-588b-11ed-9b6a-0242ac120002
+static const AudioUuid kDownmixTypeUUID = {static_cast<int32_t>(0xfa81862a),
+ 0x588b,
+ 0x11ed,
+ 0x9b6a,
+ {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// fa8187ba-588b-11ed-9b6a-0242ac120002
+static const AudioUuid kDownmixSwImplUUID = {static_cast<int32_t>(0xfa8187ba),
+ 0x588b,
+ 0x11ed,
+ 0x9b6a,
+ {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// 0bed4300-ddd6-11db-8f34-0002a5d5c51b.
+static const AudioUuid kEqualizerTypeUUID = {static_cast<int32_t>(0x0bed4300),
+ 0xddd6,
+ 0x11db,
+ 0x8f34,
+ {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+// 0bed4300-847d-11df-bb17-0002a5d5c51b
+static const AudioUuid kEqualizerSwImplUUID = {static_cast<int32_t>(0x0bed4300),
+ 0x847d,
+ 0x11df,
+ 0xbb17,
+ {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+// ce772f20-847d-11df-bb17-0002a5d5c51b
+static const AudioUuid kEqualizerBundleImplUUID = {static_cast<int32_t>(0xce772f20),
+ 0x847d,
+ 0x11df,
+ 0xbb17,
+ {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+// c8e70ecd-48ca-456e-8a4f-0002a5d5c51b
+static const AudioUuid kEqualizerProxyUUID = {static_cast<int32_t>(0xc8e70ecd),
+ 0x48ca,
+ 0x456e,
+ 0x8a4f,
+ {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+// 7261676f-6d75-7369-6364-28e2fd3ac39e
+static const AudioUuid kDynamicsProcessingTypeUUID = {static_cast<int32_t>(0x7261676f),
+ 0x6d75,
+ 0x7369,
+ 0x6364,
+ {0x28, 0xe2, 0xfd, 0x3a, 0xc3, 0x9e}};
+// fa818d78-588b-11ed-9b6a-0242ac120002
+static const AudioUuid kDynamicsProcessingSwImplUUID = {static_cast<int32_t>(0xfa818d78),
+ 0x588b,
+ 0x11ed,
+ 0x9b6a,
+ {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// 1411e6d6-aecd-4021-a1cf-a6aceb0d71e5
+static const AudioUuid kHapticGeneratorTypeUUID = {static_cast<int32_t>(0x1411e6d6),
+ 0xaecd,
+ 0x4021,
+ 0xa1cf,
+ {0xa6, 0xac, 0xeb, 0x0d, 0x71, 0xe5}};
+// fa819110-588b-11ed-9b6a-0242ac120002
+static const AudioUuid kHapticGeneratorSwImplUUID = {static_cast<int32_t>(0xfa819110),
+ 0x588b,
+ 0x11ed,
+ 0x9b6a,
+ {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// fe3199be-aed0-413f-87bb-11260eb63cf1
+static const AudioUuid kLoudnessEnhancerTypeUUID = {static_cast<int32_t>(0xfe3199be),
+ 0xaed0,
+ 0x413f,
+ 0x87bb,
+ {0x11, 0x26, 0x0e, 0xb6, 0x3c, 0xf1}};
+// fa819610-588b-11ed-9b6a-0242ac120002
+static const AudioUuid kLoudnessEnhancerSwImplUUID = {static_cast<int32_t>(0xfa819610),
+ 0x588b,
+ 0x11ed,
+ 0x9b6a,
+ {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// c2e5d5f0-94bd-4763-9cac-4e234d06839e
+static const AudioUuid kEnvReverbTypeUUID = {static_cast<int32_t>(0xc2e5d5f0),
+ 0x94bd,
+ 0x4763,
+ 0x9cac,
+ {0x4e, 0x23, 0x4d, 0x06, 0x83, 0x9e}};
+// fa819886-588b-11ed-9b6a-0242ac120002
+static const AudioUuid kEnvReverbSwImplUUID = {static_cast<int32_t>(0xfa819886),
+ 0x588b,
+ 0x11ed,
+ 0x9b6a,
+ {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// 47382d60-ddd8-11db-bf3a-0002a5d5c51b
+static const AudioUuid kPresetReverbTypeUUID = {static_cast<int32_t>(0x47382d60),
+ 0xddd8,
+ 0x11db,
+ 0xbf3a,
+ {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+// fa8199c6-588b-11ed-9b6a-0242ac120002
+static const AudioUuid kPresetReverbSwImplUUID = {static_cast<int32_t>(0xfa8199c6),
+ 0x588b,
+ 0x11ed,
+ 0x9b6a,
+ {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// 37cc2c00-dddd-11db-8577-0002a5d5c51b
+static const AudioUuid kVirtualizerTypeUUID = {static_cast<int32_t>(0x37cc2c00),
+ 0xdddd,
+ 0x11db,
+ 0x8577,
+ {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+// fa819d86-588b-11ed-9b6a-0242ac120002
+static const AudioUuid kVirtualizerSwImplUUID = {static_cast<int32_t>(0xfa819d86),
+ 0x588b,
+ 0x11ed,
+ 0x9b6a,
+ {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// fa819f3e-588b-11ed-9b6a-0242ac120002
+static const AudioUuid kVisualizerTypeUUID = {static_cast<int32_t>(0xfa819f3e),
+ 0x588b,
+ 0x11ed,
+ 0x9b6a,
+ {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// fa81a0f6-588b-11ed-9b6a-0242ac120002
+static const AudioUuid kVisualizerSwImplUUID = {static_cast<int32_t>(0xfa81a0f6),
+ 0x588b,
+ 0x11ed,
+ 0x9b6a,
+ {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// fa81a2b8-588b-11ed-9b6a-0242ac120002
+static const AudioUuid kVolumeTypeUUID = {static_cast<int32_t>(0xfa81a2b8),
+ 0x588b,
+ 0x11ed,
+ 0x9b6a,
+ {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// fa81a718-588b-11ed-9b6a-0242ac120002
+static const AudioUuid kVolumeSwImplUUID = {static_cast<int32_t>(0xfa81a718),
+ 0x588b,
+ 0x11ed,
+ 0x9b6a,
+ {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+
+/**
+ * @brief A map between effect name and effect type UUID.
+ * All <name> attribution in effect/effectProxy of audio_effects.xml should be listed in this map.
+ * We need this map is because existing audio_effects.xml don't have a type UUID defined.
+ */
+static const std::map<const std::string /* effect type */, const AudioUuid&> kUuidNameTypeMap = {
+ {"bassboost", kBassBoostTypeUUID},
+ {"downmix", kDownmixTypeUUID},
+ {"dynamics_processing", kDynamicsProcessingTypeUUID},
+ {"equalizer", kEqualizerTypeUUID},
+ {"haptic_generator", kHapticGeneratorTypeUUID},
+ {"loudness_enhancer", kLoudnessEnhancerTypeUUID},
+ {"env_reverb", kEnvReverbTypeUUID},
+ {"preset_reverb", kPresetReverbTypeUUID},
+ {"reverb_env_aux", kEnvReverbTypeUUID},
+ {"reverb_env_ins", kEnvReverbTypeUUID},
+ {"reverb_pre_aux", kPresetReverbTypeUUID},
+ {"reverb_pre_ins", kPresetReverbTypeUUID},
+ {"virtualizer", kVirtualizerTypeUUID},
+ {"visualizer", kVisualizerTypeUUID},
+ {"volume", kVolumeTypeUUID},
+};
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/effect-impl/EffectWorker.h b/audio/aidl/default/include/effect-impl/EffectWorker.h
new file mode 100644
index 0000000..6a78eab
--- /dev/null
+++ b/audio/aidl/default/include/effect-impl/EffectWorker.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+#include <algorithm>
+#include <memory>
+#include <mutex>
+#include <string>
+
+#include "EffectContext.h"
+#include "EffectThread.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+std::string toString(RetCode& code);
+
+class EffectWorker : public EffectThread {
+ public:
+ // set effect context for worker, suppose to only happen once here
+ void setContext(std::shared_ptr<EffectContext> context) {
+ std::call_once(mOnceFlag, [&]() { mContext = context; });
+ };
+
+ // handle FMQ and call effect implemented virtual function
+ void process() override {
+ RETURN_VALUE_IF(!mContext, void(), "nullContext");
+ std::shared_ptr<EffectContext::StatusMQ> statusMQ = mContext->getStatusFmq();
+ std::shared_ptr<EffectContext::DataMQ> inputMQ = mContext->getInputDataFmq();
+ std::shared_ptr<EffectContext::DataMQ> outputMQ = mContext->getOutputDataFmq();
+
+ // Only this worker will read from input data MQ and write to output data MQ.
+ auto readSamples = inputMQ->availableToRead(), writeSamples = outputMQ->availableToWrite();
+ if (readSamples && writeSamples) {
+ auto processSamples = std::min(readSamples, writeSamples);
+ LOG(DEBUG) << __func__ << " available to read " << readSamples << " available to write "
+ << writeSamples << " process " << processSamples;
+
+ auto buffer = mContext->getWorkBuffer();
+ inputMQ->read(buffer, processSamples);
+
+ IEffect::Status status = effectProcessImpl(buffer, buffer, processSamples);
+ outputMQ->write(buffer, status.fmqProduced);
+ statusMQ->writeBlocking(&status, 1);
+ LOG(DEBUG) << __func__ << " done processing, effect consumed " << status.fmqConsumed
+ << " produced " << status.fmqProduced;
+ } else {
+ // TODO: maybe add some sleep here to avoid busy waiting
+ }
+ }
+
+ // must implement by each effect implementation
+ // TODO: consider if this interface need adjustment to handle in-place processing
+ virtual IEffect::Status effectProcessImpl(float* in, float* out, int processSamples) = 0;
+
+ private:
+ // make sure the context only set once.
+ std::once_flag mOnceFlag;
+ std::shared_ptr<EffectContext> mContext;
+};
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/effectFactory-impl/EffectConfig.h b/audio/aidl/default/include/effectFactory-impl/EffectConfig.h
new file mode 100644
index 0000000..2b904f5
--- /dev/null
+++ b/audio/aidl/default/include/effectFactory-impl/EffectConfig.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <functional>
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include <cutils/properties.h>
+#include <tinyxml2.h>
+
+#include "effect-impl/EffectTypes.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+/**
+ * Library contains a mapping from library name to path.
+ * Effect contains a mapping from effect name to Libraries and implementation UUID.
+ * Pre/post processor contains a mapping from processing name to effect names.
+ */
+class EffectConfig {
+ public:
+ explicit EffectConfig(const std::string& file);
+
+ // <library>
+ struct Library {
+ std::string name;
+ std::string path;
+ };
+ struct LibraryUuid {
+ std::string name; // library name
+ ::aidl::android::media::audio::common::AudioUuid uuid;
+ };
+ // <effects>
+ struct EffectLibraries {
+ std::optional<struct LibraryUuid> proxyLibrary;
+ std::vector<struct LibraryUuid> libraries;
+ };
+
+ int getSkippedElements() const { return mSkippedElements; }
+ const std::unordered_map<std::string, std::string> getLibraryMap() const { return mLibraryMap; }
+ const std::unordered_map<std::string, struct EffectLibraries> getEffectsMap() const {
+ return mEffectsMap;
+ }
+ const std::unordered_map<std::string, std::vector<std::string>> getProcessingMap() const {
+ return mProcessingMap;
+ }
+
+ private:
+ int mSkippedElements;
+ /* Parsed Libraries result */
+ std::unordered_map<std::string, std::string> mLibraryMap;
+ /* Parsed Effects result */
+ std::unordered_map<std::string, struct EffectLibraries> mEffectsMap;
+ /* Parsed pre/post processing result */
+ std::unordered_map<std::string, std::vector<std::string>> mProcessingMap;
+
+ /** @return all `node`s children that are elements and match the tag if provided. */
+ std::vector<std::reference_wrapper<const tinyxml2::XMLElement>> getChildren(
+ const tinyxml2::XMLNode& node, const char* childTag = nullptr);
+
+ /** Parse a library xml note and push the result in mLibraryMap or return false on failure. */
+ bool parseLibrary(const tinyxml2::XMLElement& xml);
+
+ /** Parse an effect from an xml element describing it.
+ * @return true and pushes the effect in mEffectsMap on success, false on failure.
+ */
+ bool parseEffect(const tinyxml2::XMLElement& xml);
+
+ bool parseStream(const tinyxml2::XMLElement& xml);
+
+ // Function to parse effect.library name and effect.uuid from xml
+ bool parseLibraryUuid(const tinyxml2::XMLElement& xml, struct LibraryUuid& libraryUuid,
+ bool isProxy = false);
+
+ const char* dump(const tinyxml2::XMLElement& element,
+ tinyxml2::XMLPrinter&& printer = {}) const;
+};
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/effectFactory-impl/EffectFactory.h b/audio/aidl/default/include/effectFactory-impl/EffectFactory.h
new file mode 100644
index 0000000..7edace0
--- /dev/null
+++ b/audio/aidl/default/include/effectFactory-impl/EffectFactory.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <any>
+#include <map>
+#include <optional>
+#include <set>
+#include <vector>
+
+#include <aidl/android/hardware/audio/effect/BnFactory.h>
+#include "EffectConfig.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+class Factory : public BnFactory {
+ public:
+ explicit Factory(const std::string& file);
+ /**
+ * @brief Get identity of all effects supported by the device, with the optional filter by type
+ * and/or by instance UUID.
+ *
+ * @param in_type Type UUID.
+ * @param in_instance Instance UUID.
+ * @param in_proxy Proxy UUID.
+ * @param out_descriptor List of identities .
+ * @return ndk::ScopedAStatus
+ */
+ ndk::ScopedAStatus queryEffects(
+ const std::optional<::aidl::android::media::audio::common::AudioUuid>& in_type,
+ const std::optional<::aidl::android::media::audio::common::AudioUuid>& in_instance,
+ const std::optional<::aidl::android::media::audio::common::AudioUuid>& in_proxy,
+ std::vector<Descriptor::Identity>* out_descriptor) override;
+
+ /**
+ * @brief Query list of defined processing, with the optional filter by AudioStreamType
+ *
+ * @param in_type Type of processing, could be AudioStreamType or AudioSource. Optional.
+ * @param _aidl_return List of processing filtered by in_type.
+ * @return ndk::ScopedAStatus
+ */
+ ndk::ScopedAStatus queryProcessing(const std::optional<Processing::Type>& in_type,
+ std::vector<Processing>* _aidl_return) override;
+
+ /**
+ * @brief Create an effect instance for a certain implementation (identified by UUID).
+ *
+ * @param in_impl_uuid Effect implementation UUID.
+ * @param _aidl_return A pointer to created effect instance.
+ * @return ndk::ScopedAStatus
+ */
+ ndk::ScopedAStatus createEffect(
+ const ::aidl::android::media::audio::common::AudioUuid& in_impl_uuid,
+ std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>* _aidl_return)
+ override;
+
+ /**
+ * @brief Destroy an effect instance.
+ *
+ * @param in_handle Effect instance handle.
+ * @return ndk::ScopedAStatus
+ */
+ ndk::ScopedAStatus destroyEffect(
+ const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_handle)
+ override;
+
+ private:
+ const EffectConfig mConfig;
+ ~Factory();
+ // Set of effect descriptors supported by the devices.
+ std::set<Descriptor::Identity> mIdentitySet;
+
+ std::map<aidl::android::media::audio::common::AudioUuid /* implementationUUID */,
+ std::pair<std::unique_ptr<void, std::function<void(void*)>> /* dlHandle */,
+ std::unique_ptr<struct effect_dl_interface_s>>>
+ mEffectLibMap;
+ std::map<std::weak_ptr<IEffect>, aidl::android::media::audio::common::AudioUuid,
+ std::owner_less<>>
+ mEffectUuidMap;
+
+ ndk::ScopedAStatus destroyEffectImpl(const std::shared_ptr<IEffect>& in_handle);
+ void cleanupEffectMap();
+ void openEffectLibrary(const ::aidl::android::media::audio::common::AudioUuid& impl,
+ const std::string& libName);
+ void createIdentityWithConfig(
+ const EffectConfig::LibraryUuid& configLib,
+ const ::aidl::android::media::audio::common::AudioUuid& typeUuid,
+ const std::optional<::aidl::android::media::audio::common::AudioUuid> proxyUuid);
+ void loadEffectLibs();
+};
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/loudnessEnhancer/Android.bp b/audio/aidl/default/loudnessEnhancer/Android.bp
new file mode 100644
index 0000000..3a0ac73
--- /dev/null
+++ b/audio/aidl/default/loudnessEnhancer/Android.bp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_shared {
+ name: "libloudnessenhancersw",
+ defaults: [
+ "aidlaudioeffectservice_defaults",
+ "latest_android_media_audio_common_types_ndk_shared",
+ "latest_android_hardware_audio_effect_ndk_shared",
+ ],
+ srcs: [
+ "LoudnessEnhancerSw.cpp",
+ ":effectCommonFile",
+ ],
+ visibility: [
+ "//hardware/interfaces/audio/aidl/default",
+ ],
+}
diff --git a/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.cpp b/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.cpp
new file mode 100644
index 0000000..9d2b978
--- /dev/null
+++ b/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.cpp
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cstddef>
+#define LOG_TAG "AHAL_LoudnessEnhancerSw"
+#include <Utils.h>
+#include <algorithm>
+#include <unordered_set>
+
+#include <android-base/logging.h>
+#include <fmq/AidlMessageQueue.h>
+
+#include "LoudnessEnhancerSw.h"
+
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kLoudnessEnhancerSwImplUUID;
+using aidl::android::hardware::audio::effect::LoudnessEnhancerSw;
+using aidl::android::hardware::audio::effect::State;
+using aidl::android::media::audio::common::AudioUuid;
+
+extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
+ std::shared_ptr<IEffect>* instanceSpp) {
+ if (!in_impl_uuid || *in_impl_uuid != kLoudnessEnhancerSwImplUUID) {
+ LOG(ERROR) << __func__ << "uuid not supported";
+ return EX_ILLEGAL_ARGUMENT;
+ }
+ if (instanceSpp) {
+ *instanceSpp = ndk::SharedRefBase::make<LoudnessEnhancerSw>();
+ LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
+ return EX_NONE;
+ } else {
+ LOG(ERROR) << __func__ << " invalid input parameter!";
+ return EX_ILLEGAL_ARGUMENT;
+ }
+}
+
+extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
+ if (!instanceSp) {
+ return EX_NONE;
+ }
+ State state;
+ ndk::ScopedAStatus status = instanceSp->getState(&state);
+ if (!status.isOk() || State::INIT != state) {
+ LOG(ERROR) << __func__ << " instance " << instanceSp.get()
+ << " in state: " << toString(state) << ", status: " << status.getDescription();
+ return EX_ILLEGAL_STATE;
+ }
+ LOG(DEBUG) << __func__ << " instance " << instanceSp.get() << " destroyed";
+ return EX_NONE;
+}
+
+namespace aidl::android::hardware::audio::effect {
+
+ndk::ScopedAStatus LoudnessEnhancerSw::getDescriptor(Descriptor* _aidl_return) {
+ LOG(DEBUG) << __func__ << kDescriptor.toString();
+ *_aidl_return = kDescriptor;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus LoudnessEnhancerSw::setParameterSpecific(const Parameter::Specific& specific) {
+ RETURN_IF(Parameter::Specific::loudnessEnhancer != specific.getTag(), EX_ILLEGAL_ARGUMENT,
+ "EffectNotSupported");
+ std::lock_guard lg(mMutex);
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+ auto& leParam = specific.get<Parameter::Specific::loudnessEnhancer>();
+ auto tag = leParam.getTag();
+
+ switch (tag) {
+ case LoudnessEnhancer::gainMb: {
+ RETURN_IF(mContext->setLeGainMb(leParam.get<LoudnessEnhancer::gainMb>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setGainMbFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ default: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_ARGUMENT, "LoudnessEnhancerTagNotSupported");
+ }
+ }
+}
+
+ndk::ScopedAStatus LoudnessEnhancerSw::getParameterSpecific(const Parameter::Id& id,
+ Parameter::Specific* specific) {
+ auto tag = id.getTag();
+ RETURN_IF(Parameter::Id::loudnessEnhancerTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
+ auto leId = id.get<Parameter::Id::loudnessEnhancerTag>();
+ auto leIdTag = leId.getTag();
+ switch (leIdTag) {
+ case LoudnessEnhancer::Id::commonTag:
+ return getParameterLoudnessEnhancer(leId.get<LoudnessEnhancer::Id::commonTag>(),
+ specific);
+ default:
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(leIdTag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_ARGUMENT, "LoudnessEnhancerTagNotSupported");
+ }
+}
+
+ndk::ScopedAStatus LoudnessEnhancerSw::getParameterLoudnessEnhancer(
+ const LoudnessEnhancer::Tag& tag, Parameter::Specific* specific) {
+ std::lock_guard lg(mMutex);
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+ LoudnessEnhancer leParam;
+ switch (tag) {
+ case LoudnessEnhancer::gainMb: {
+ leParam.set<LoudnessEnhancer::gainMb>(mContext->getLeGainMb());
+ break;
+ }
+ default: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_ARGUMENT, "LoudnessEnhancerTagNotSupported");
+ }
+ }
+
+ specific->set<Parameter::Specific::loudnessEnhancer>(leParam);
+ return ndk::ScopedAStatus::ok();
+}
+
+std::shared_ptr<EffectContext> LoudnessEnhancerSw::createContext(const Parameter::Common& common) {
+ if (mContext) {
+ LOG(DEBUG) << __func__ << " context already exist";
+ return mContext;
+ }
+ mContext = std::make_shared<LoudnessEnhancerSwContext>(1 /* statusFmqDepth */, common);
+ return mContext;
+}
+
+RetCode LoudnessEnhancerSw::releaseContext() {
+ if (mContext) {
+ mContext.reset();
+ }
+ return RetCode::SUCCESS;
+}
+
+// Processing method running in EffectWorker thread.
+IEffect::Status LoudnessEnhancerSw::effectProcessImpl(float* in, float* out, int process) {
+ // TODO: get data buffer and process.
+ LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
+ for (int i = 0; i < process; i++) {
+ *out++ = *in++;
+ }
+ return {STATUS_OK, process, process};
+}
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.h b/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.h
new file mode 100644
index 0000000..856bf0b
--- /dev/null
+++ b/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/audio/effect/BnEffect.h>
+#include <fmq/AidlMessageQueue.h>
+#include <cstdlib>
+#include <memory>
+
+#include "effect-impl/EffectImpl.h"
+#include "effect-impl/EffectUUID.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+class LoudnessEnhancerSwContext final : public EffectContext {
+ public:
+ LoudnessEnhancerSwContext(int statusDepth, const Parameter::Common& common)
+ : EffectContext(statusDepth, common) {
+ LOG(DEBUG) << __func__;
+ }
+
+ RetCode setLeGainMb(int gainMb) {
+ // TODO : Add implementation to apply new gain
+ mGainMb = gainMb;
+ return RetCode::SUCCESS;
+ }
+ int getLeGainMb() const { return mGainMb; }
+
+ private:
+ int mGainMb = 0; // Default Gain
+};
+
+class LoudnessEnhancerSw final : public EffectImpl {
+ public:
+ LoudnessEnhancerSw() { LOG(DEBUG) << __func__; }
+ ~LoudnessEnhancerSw() {
+ cleanUp();
+ LOG(DEBUG) << __func__;
+ }
+
+ ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
+ ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
+ ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
+ Parameter::Specific* specific) override;
+ IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+ std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+ RetCode releaseContext() override;
+
+ private:
+ std::shared_ptr<LoudnessEnhancerSwContext> mContext;
+ /* capabilities */
+ const LoudnessEnhancer::Capability kCapability;
+ /* Effect descriptor */
+ const Descriptor kDescriptor = {
+ .common = {.id = {.type = kLoudnessEnhancerTypeUUID,
+ .uuid = kLoudnessEnhancerSwImplUUID,
+ .proxy = std::nullopt},
+ .flags = {.type = Flags::Type::INSERT,
+ .insert = Flags::Insert::FIRST,
+ .volume = Flags::Volume::CTRL},
+ .name = "LoudnessEnhancerSw",
+ .implementor = "The Android Open Source Project"},
+ .capability = Capability::make<Capability::loudnessEnhancer>(kCapability)};
+
+ ndk::ScopedAStatus getParameterLoudnessEnhancer(const LoudnessEnhancer::Tag& tag,
+ Parameter::Specific* specific);
+};
+} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/main.cpp b/audio/aidl/default/main.cpp
new file mode 100644
index 0000000..15874a0
--- /dev/null
+++ b/audio/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 <cstdlib>
+#include <ctime>
+
+#include "core-impl/Config.h"
+#include "core-impl/Module.h"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+using aidl::android::hardware::audio::core::Config;
+using aidl::android::hardware::audio::core::Module;
+
+int main() {
+ // Random values are used in the implementation.
+ std::srand(std::time(nullptr));
+
+ // This is a debug implementation, always enable debug logging.
+ android::base::SetMinimumLogSeverity(::android::base::DEBUG);
+ ABinderProcess_setThreadPoolMaxThreadCount(16);
+
+ // Make the default config service
+ auto config = ndk::SharedRefBase::make<Config>();
+ const std::string configName = std::string() + Config::descriptor + "/default";
+ binder_status_t status =
+ AServiceManager_addService(config->asBinder().get(), configName.c_str());
+ CHECK_EQ(STATUS_OK, status);
+
+ // Make the default module
+ auto moduleDefault = ndk::SharedRefBase::make<Module>();
+ const std::string moduleDefaultName = std::string() + Module::descriptor + "/default";
+ status = AServiceManager_addService(moduleDefault->asBinder().get(), moduleDefaultName.c_str());
+ CHECK_EQ(STATUS_OK, status);
+
+ ABinderProcess_joinThreadPool();
+ return EXIT_FAILURE; // should not reach
+}
diff --git a/audio/aidl/default/presetReverb/Android.bp b/audio/aidl/default/presetReverb/Android.bp
new file mode 100644
index 0000000..4148511
--- /dev/null
+++ b/audio/aidl/default/presetReverb/Android.bp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_shared {
+ name: "libpresetreverbsw",
+ defaults: [
+ "aidlaudioeffectservice_defaults",
+ "latest_android_media_audio_common_types_ndk_shared",
+ "latest_android_hardware_audio_effect_ndk_shared",
+ ],
+ srcs: [
+ "PresetReverbSw.cpp",
+ ":effectCommonFile",
+ ],
+ visibility: [
+ "//hardware/interfaces/audio/aidl/default",
+ ],
+}
diff --git a/audio/aidl/default/presetReverb/PresetReverbSw.cpp b/audio/aidl/default/presetReverb/PresetReverbSw.cpp
new file mode 100644
index 0000000..069d0ff
--- /dev/null
+++ b/audio/aidl/default/presetReverb/PresetReverbSw.cpp
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cstddef>
+#define LOG_TAG "AHAL_PresetReverbSw"
+#include <Utils.h>
+#include <algorithm>
+#include <unordered_set>
+
+#include <android-base/logging.h>
+#include <fmq/AidlMessageQueue.h>
+
+#include "PresetReverbSw.h"
+
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kPresetReverbSwImplUUID;
+using aidl::android::hardware::audio::effect::PresetReverbSw;
+using aidl::android::hardware::audio::effect::State;
+using aidl::android::media::audio::common::AudioUuid;
+
+extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
+ std::shared_ptr<IEffect>* instanceSpp) {
+ if (!in_impl_uuid || *in_impl_uuid != kPresetReverbSwImplUUID) {
+ LOG(ERROR) << __func__ << "uuid not supported";
+ return EX_ILLEGAL_ARGUMENT;
+ }
+ if (instanceSpp) {
+ *instanceSpp = ndk::SharedRefBase::make<PresetReverbSw>();
+ LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
+ return EX_NONE;
+ } else {
+ LOG(ERROR) << __func__ << " invalid input parameter!";
+ return EX_ILLEGAL_ARGUMENT;
+ }
+}
+
+extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
+ if (!instanceSp) {
+ return EX_NONE;
+ }
+ State state;
+ ndk::ScopedAStatus status = instanceSp->getState(&state);
+ if (!status.isOk() || State::INIT != state) {
+ LOG(ERROR) << __func__ << " instance " << instanceSp.get()
+ << " in state: " << toString(state) << ", status: " << status.getDescription();
+ return EX_ILLEGAL_STATE;
+ }
+ LOG(DEBUG) << __func__ << " instance " << instanceSp.get() << " destroyed";
+ return EX_NONE;
+}
+
+namespace aidl::android::hardware::audio::effect {
+
+ndk::ScopedAStatus PresetReverbSw::getDescriptor(Descriptor* _aidl_return) {
+ LOG(DEBUG) << __func__ << kDescriptor.toString();
+ *_aidl_return = kDescriptor;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus PresetReverbSw::setParameterSpecific(const Parameter::Specific& specific) {
+ RETURN_IF(Parameter::Specific::reverb != specific.getTag(), EX_ILLEGAL_ARGUMENT,
+ "EffectNotSupported");
+ std::lock_guard lg(mMutex);
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+ mSpecificParam = specific.get<Parameter::Specific::reverb>();
+ LOG(DEBUG) << __func__ << " success with: " << specific.toString();
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus PresetReverbSw::getParameterSpecific(const Parameter::Id& id,
+ Parameter::Specific* specific) {
+ auto tag = id.getTag();
+ RETURN_IF(Parameter::Id::reverbTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
+ specific->set<Parameter::Specific::reverb>(mSpecificParam);
+ return ndk::ScopedAStatus::ok();
+}
+
+std::shared_ptr<EffectContext> PresetReverbSw::createContext(const Parameter::Common& common) {
+ if (mContext) {
+ LOG(DEBUG) << __func__ << " context already exist";
+ return mContext;
+ }
+ mContext = std::make_shared<PresetReverbSwContext>(1 /* statusFmqDepth */, common);
+ return mContext;
+}
+
+RetCode PresetReverbSw::releaseContext() {
+ if (mContext) {
+ mContext.reset();
+ }
+ return RetCode::SUCCESS;
+}
+
+// Processing method running in EffectWorker thread.
+IEffect::Status PresetReverbSw::effectProcessImpl(float* in, float* out, int process) {
+ // TODO: get data buffer and process.
+ LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
+ for (int i = 0; i < process; i++) {
+ *out++ = *in++;
+ }
+ return {STATUS_OK, process, process};
+}
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/presetReverb/PresetReverbSw.h b/audio/aidl/default/presetReverb/PresetReverbSw.h
new file mode 100644
index 0000000..75a5a94
--- /dev/null
+++ b/audio/aidl/default/presetReverb/PresetReverbSw.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/audio/effect/BnEffect.h>
+#include <fmq/AidlMessageQueue.h>
+#include <cstdlib>
+#include <memory>
+
+#include "effect-impl/EffectImpl.h"
+#include "effect-impl/EffectUUID.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+class PresetReverbSwContext final : public EffectContext {
+ public:
+ PresetReverbSwContext(int statusDepth, const Parameter::Common& common)
+ : EffectContext(statusDepth, common) {
+ LOG(DEBUG) << __func__;
+ }
+ // TODO: add specific context here
+};
+
+class PresetReverbSw final : public EffectImpl {
+ public:
+ PresetReverbSw() { LOG(DEBUG) << __func__; }
+ ~PresetReverbSw() {
+ cleanUp();
+ LOG(DEBUG) << __func__;
+ }
+
+ ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
+ ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
+ ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
+ Parameter::Specific* specific) override;
+ IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+ std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+ RetCode releaseContext() override;
+
+ private:
+ std::shared_ptr<PresetReverbSwContext> mContext;
+ /* capabilities */
+ const Reverb::Capability kCapability;
+ /* Effect descriptor */
+ const Descriptor kDescriptor = {
+ .common = {.id = {.type = kPresetReverbTypeUUID,
+ .uuid = kPresetReverbSwImplUUID,
+ .proxy = std::nullopt},
+ .flags = {.type = Flags::Type::INSERT,
+ .insert = Flags::Insert::FIRST,
+ .volume = Flags::Volume::CTRL},
+ .name = "PresetReverbSw",
+ .implementor = "The Android Open Source Project"},
+ .capability = Capability::make<Capability::reverb>(kCapability)};
+
+ /* parameters */
+ Reverb mSpecificParam;
+};
+} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/virtualizer/Android.bp b/audio/aidl/default/virtualizer/Android.bp
new file mode 100644
index 0000000..ba38f5c
--- /dev/null
+++ b/audio/aidl/default/virtualizer/Android.bp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_shared {
+ name: "libvirtualizersw",
+ defaults: [
+ "aidlaudioeffectservice_defaults",
+ "latest_android_media_audio_common_types_ndk_shared",
+ "latest_android_hardware_audio_effect_ndk_shared",
+ ],
+ srcs: [
+ "VirtualizerSw.cpp",
+ ":effectCommonFile",
+ ],
+ visibility: [
+ "//hardware/interfaces/audio/aidl/default",
+ ],
+}
diff --git a/audio/aidl/default/virtualizer/VirtualizerSw.cpp b/audio/aidl/default/virtualizer/VirtualizerSw.cpp
new file mode 100644
index 0000000..9688fc8
--- /dev/null
+++ b/audio/aidl/default/virtualizer/VirtualizerSw.cpp
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cstddef>
+#define LOG_TAG "AHAL_VirtualizerSw"
+#include <Utils.h>
+#include <algorithm>
+#include <unordered_set>
+
+#include <android-base/logging.h>
+#include <fmq/AidlMessageQueue.h>
+
+#include "VirtualizerSw.h"
+
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kVirtualizerSwImplUUID;
+using aidl::android::hardware::audio::effect::State;
+using aidl::android::hardware::audio::effect::VirtualizerSw;
+using aidl::android::media::audio::common::AudioUuid;
+
+extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
+ std::shared_ptr<IEffect>* instanceSpp) {
+ if (!in_impl_uuid || *in_impl_uuid != kVirtualizerSwImplUUID) {
+ LOG(ERROR) << __func__ << "uuid not supported";
+ return EX_ILLEGAL_ARGUMENT;
+ }
+ if (instanceSpp) {
+ *instanceSpp = ndk::SharedRefBase::make<VirtualizerSw>();
+ LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
+ return EX_NONE;
+ } else {
+ LOG(ERROR) << __func__ << " invalid input parameter!";
+ return EX_ILLEGAL_ARGUMENT;
+ }
+}
+
+extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
+ if (!instanceSp) {
+ return EX_NONE;
+ }
+ State state;
+ ndk::ScopedAStatus status = instanceSp->getState(&state);
+ if (!status.isOk() || State::INIT != state) {
+ LOG(ERROR) << __func__ << " instance " << instanceSp.get()
+ << " in state: " << toString(state) << ", status: " << status.getDescription();
+ return EX_ILLEGAL_STATE;
+ }
+ LOG(DEBUG) << __func__ << " instance " << instanceSp.get() << " destroyed";
+ return EX_NONE;
+}
+
+namespace aidl::android::hardware::audio::effect {
+
+ndk::ScopedAStatus VirtualizerSw::getDescriptor(Descriptor* _aidl_return) {
+ LOG(DEBUG) << __func__ << kDescriptor.toString();
+ *_aidl_return = kDescriptor;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus VirtualizerSw::setParameterSpecific(const Parameter::Specific& specific) {
+ RETURN_IF(Parameter::Specific::virtualizer != specific.getTag(), EX_ILLEGAL_ARGUMENT,
+ "EffectNotSupported");
+ std::lock_guard lg(mMutex);
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+ mSpecificParam = specific.get<Parameter::Specific::virtualizer>();
+ LOG(DEBUG) << __func__ << " success with: " << specific.toString();
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus VirtualizerSw::getParameterSpecific(const Parameter::Id& id,
+ Parameter::Specific* specific) {
+ auto tag = id.getTag();
+ RETURN_IF(Parameter::Id::virtualizerTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
+ specific->set<Parameter::Specific::virtualizer>(mSpecificParam);
+ return ndk::ScopedAStatus::ok();
+}
+
+std::shared_ptr<EffectContext> VirtualizerSw::createContext(const Parameter::Common& common) {
+ if (mContext) {
+ LOG(DEBUG) << __func__ << " context already exist";
+ return mContext;
+ }
+ mContext = std::make_shared<VirtualizerSwContext>(1 /* statusFmqDepth */, common);
+ return mContext;
+}
+
+RetCode VirtualizerSw::releaseContext() {
+ if (mContext) {
+ mContext.reset();
+ }
+ return RetCode::SUCCESS;
+}
+
+// Processing method running in EffectWorker thread.
+IEffect::Status VirtualizerSw::effectProcessImpl(float* in, float* out, int process) {
+ // TODO: get data buffer and process.
+ LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
+ for (int i = 0; i < process; i++) {
+ *out++ = *in++;
+ }
+ return {STATUS_OK, process, process};
+}
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/virtualizer/VirtualizerSw.h b/audio/aidl/default/virtualizer/VirtualizerSw.h
new file mode 100644
index 0000000..e4de8b3
--- /dev/null
+++ b/audio/aidl/default/virtualizer/VirtualizerSw.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/audio/effect/BnEffect.h>
+#include <fmq/AidlMessageQueue.h>
+#include <cstdlib>
+#include <memory>
+
+#include "effect-impl/EffectImpl.h"
+#include "effect-impl/EffectUUID.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+class VirtualizerSwContext final : public EffectContext {
+ public:
+ VirtualizerSwContext(int statusDepth, const Parameter::Common& common)
+ : EffectContext(statusDepth, common) {
+ LOG(DEBUG) << __func__;
+ }
+ // TODO: add specific context here
+};
+
+class VirtualizerSw final : public EffectImpl {
+ public:
+ VirtualizerSw() { LOG(DEBUG) << __func__; }
+ ~VirtualizerSw() {
+ cleanUp();
+ LOG(DEBUG) << __func__;
+ }
+
+ ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
+ ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
+ ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
+ Parameter::Specific* specific) override;
+ IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+ std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+ RetCode releaseContext() override;
+
+ private:
+ std::shared_ptr<VirtualizerSwContext> mContext;
+ /* capabilities */
+ const Virtualizer::Capability kCapability;
+ /* Effect descriptor */
+ const Descriptor kDescriptor = {
+ .common = {.id = {.type = kVirtualizerTypeUUID,
+ .uuid = kVirtualizerSwImplUUID,
+ .proxy = std::nullopt},
+ .flags = {.type = Flags::Type::INSERT,
+ .insert = Flags::Insert::FIRST,
+ .volume = Flags::Volume::CTRL},
+ .name = "VirtualizerSw",
+ .implementor = "The Android Open Source Project"},
+ .capability = Capability::make<Capability::virtualizer>(kCapability)};
+
+ /* parameters */
+ Virtualizer mSpecificParam;
+};
+} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/visualizer/Android.bp b/audio/aidl/default/visualizer/Android.bp
new file mode 100644
index 0000000..5041be8
--- /dev/null
+++ b/audio/aidl/default/visualizer/Android.bp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_shared {
+ name: "libvisualizersw",
+ defaults: [
+ "aidlaudioeffectservice_defaults",
+ "latest_android_media_audio_common_types_ndk_shared",
+ "latest_android_hardware_audio_effect_ndk_shared",
+ ],
+ srcs: [
+ "VisualizerSw.cpp",
+ ":effectCommonFile",
+ ],
+ visibility: [
+ "//hardware/interfaces/audio/aidl/default",
+ ],
+}
diff --git a/audio/aidl/default/visualizer/VisualizerSw.cpp b/audio/aidl/default/visualizer/VisualizerSw.cpp
new file mode 100644
index 0000000..24a7bef
--- /dev/null
+++ b/audio/aidl/default/visualizer/VisualizerSw.cpp
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cstddef>
+#define LOG_TAG "AHAL_VisualizerSw"
+#include <Utils.h>
+#include <algorithm>
+#include <unordered_set>
+
+#include <android-base/logging.h>
+#include <fmq/AidlMessageQueue.h>
+
+#include "VisualizerSw.h"
+
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kVisualizerSwImplUUID;
+using aidl::android::hardware::audio::effect::State;
+using aidl::android::hardware::audio::effect::VisualizerSw;
+using aidl::android::media::audio::common::AudioUuid;
+
+extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
+ std::shared_ptr<IEffect>* instanceSpp) {
+ if (!in_impl_uuid || *in_impl_uuid != kVisualizerSwImplUUID) {
+ LOG(ERROR) << __func__ << "uuid not supported";
+ return EX_ILLEGAL_ARGUMENT;
+ }
+ if (instanceSpp) {
+ *instanceSpp = ndk::SharedRefBase::make<VisualizerSw>();
+ LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
+ return EX_NONE;
+ } else {
+ LOG(ERROR) << __func__ << " invalid input parameter!";
+ return EX_ILLEGAL_ARGUMENT;
+ }
+}
+
+extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
+ if (!instanceSp) {
+ return EX_NONE;
+ }
+ State state;
+ ndk::ScopedAStatus status = instanceSp->getState(&state);
+ if (!status.isOk() || State::INIT != state) {
+ LOG(ERROR) << __func__ << " instance " << instanceSp.get()
+ << " in state: " << toString(state) << ", status: " << status.getDescription();
+ return EX_ILLEGAL_STATE;
+ }
+ LOG(DEBUG) << __func__ << " instance " << instanceSp.get() << " destroyed";
+ return EX_NONE;
+}
+
+namespace aidl::android::hardware::audio::effect {
+
+ndk::ScopedAStatus VisualizerSw::getDescriptor(Descriptor* _aidl_return) {
+ LOG(DEBUG) << __func__ << kDescriptor.toString();
+ *_aidl_return = kDescriptor;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus VisualizerSw::setParameterSpecific(const Parameter::Specific& specific) {
+ RETURN_IF(Parameter::Specific::visualizer != specific.getTag(), EX_ILLEGAL_ARGUMENT,
+ "EffectNotSupported");
+ std::lock_guard lg(mMutex);
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+ mSpecificParam = specific.get<Parameter::Specific::visualizer>();
+ LOG(DEBUG) << __func__ << " success with: " << specific.toString();
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus VisualizerSw::getParameterSpecific(const Parameter::Id& id,
+ Parameter::Specific* specific) {
+ auto tag = id.getTag();
+ RETURN_IF(Parameter::Id::visualizerTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
+ specific->set<Parameter::Specific::visualizer>(mSpecificParam);
+ return ndk::ScopedAStatus::ok();
+}
+
+std::shared_ptr<EffectContext> VisualizerSw::createContext(const Parameter::Common& common) {
+ if (mContext) {
+ LOG(DEBUG) << __func__ << " context already exist";
+ return mContext;
+ }
+ mContext = std::make_shared<VisualizerSwContext>(1 /* statusFmqDepth */, common);
+ return mContext;
+}
+
+RetCode VisualizerSw::releaseContext() {
+ if (mContext) {
+ mContext.reset();
+ }
+ return RetCode::SUCCESS;
+}
+
+// Processing method running in EffectWorker thread.
+IEffect::Status VisualizerSw::effectProcessImpl(float* in, float* out, int process) {
+ // TODO: get data buffer and process.
+ LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
+ for (int i = 0; i < process; i++) {
+ *out++ = *in++;
+ }
+ return {STATUS_OK, process, process};
+}
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/visualizer/VisualizerSw.h b/audio/aidl/default/visualizer/VisualizerSw.h
new file mode 100644
index 0000000..bccd6e9
--- /dev/null
+++ b/audio/aidl/default/visualizer/VisualizerSw.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/audio/effect/BnEffect.h>
+#include <fmq/AidlMessageQueue.h>
+#include <cstdlib>
+#include <memory>
+
+#include "effect-impl/EffectImpl.h"
+#include "effect-impl/EffectUUID.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+class VisualizerSwContext final : public EffectContext {
+ public:
+ VisualizerSwContext(int statusDepth, const Parameter::Common& common)
+ : EffectContext(statusDepth, common) {
+ LOG(DEBUG) << __func__;
+ }
+ // TODO: add specific context here
+};
+
+class VisualizerSw final : public EffectImpl {
+ public:
+ VisualizerSw() { LOG(DEBUG) << __func__; }
+ ~VisualizerSw() {
+ cleanUp();
+ LOG(DEBUG) << __func__;
+ }
+
+ ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
+ ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
+ ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
+ Parameter::Specific* specific) override;
+ IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+ std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+ RetCode releaseContext() override;
+
+ private:
+ std::shared_ptr<VisualizerSwContext> mContext;
+ /* capabilities */
+ const Visualizer::Capability kCapability;
+ /* Effect descriptor */
+ const Descriptor kDescriptor = {
+ .common = {.id = {.type = kVisualizerTypeUUID,
+ .uuid = kVisualizerSwImplUUID,
+ .proxy = std::nullopt},
+ .flags = {.type = Flags::Type::INSERT,
+ .insert = Flags::Insert::FIRST,
+ .volume = Flags::Volume::CTRL},
+ .name = "VisualizerSw",
+ .implementor = "The Android Open Source Project"},
+ .capability = Capability::make<Capability::visualizer>(kCapability)};
+
+ /* parameters */
+ Visualizer mSpecificParam;
+};
+} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/volume/Android.bp b/audio/aidl/default/volume/Android.bp
new file mode 100644
index 0000000..505ee67
--- /dev/null
+++ b/audio/aidl/default/volume/Android.bp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_shared {
+ name: "libvolumesw",
+ defaults: [
+ "aidlaudioeffectservice_defaults",
+ "latest_android_media_audio_common_types_ndk_shared",
+ "latest_android_hardware_audio_effect_ndk_shared",
+ ],
+ srcs: [
+ "VolumeSw.cpp",
+ ":effectCommonFile",
+ ],
+ visibility: [
+ "//hardware/interfaces/audio/aidl/default",
+ ],
+}
diff --git a/audio/aidl/default/volume/VolumeSw.cpp b/audio/aidl/default/volume/VolumeSw.cpp
new file mode 100644
index 0000000..b8af921
--- /dev/null
+++ b/audio/aidl/default/volume/VolumeSw.cpp
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cstddef>
+#define LOG_TAG "AHAL_VolumeSw"
+#include <Utils.h>
+#include <algorithm>
+#include <unordered_set>
+
+#include <android-base/logging.h>
+#include <fmq/AidlMessageQueue.h>
+
+#include "VolumeSw.h"
+
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kVolumeSwImplUUID;
+using aidl::android::hardware::audio::effect::State;
+using aidl::android::hardware::audio::effect::VolumeSw;
+using aidl::android::media::audio::common::AudioUuid;
+
+extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
+ std::shared_ptr<IEffect>* instanceSpp) {
+ if (!in_impl_uuid || *in_impl_uuid != kVolumeSwImplUUID) {
+ LOG(ERROR) << __func__ << "uuid not supported";
+ return EX_ILLEGAL_ARGUMENT;
+ }
+ if (instanceSpp) {
+ *instanceSpp = ndk::SharedRefBase::make<VolumeSw>();
+ LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
+ return EX_NONE;
+ } else {
+ LOG(ERROR) << __func__ << " invalid input parameter!";
+ return EX_ILLEGAL_ARGUMENT;
+ }
+}
+
+extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
+ if (!instanceSp) {
+ return EX_NONE;
+ }
+ State state;
+ ndk::ScopedAStatus status = instanceSp->getState(&state);
+ if (!status.isOk() || State::INIT != state) {
+ LOG(ERROR) << __func__ << " instance " << instanceSp.get()
+ << " in state: " << toString(state) << ", status: " << status.getDescription();
+ return EX_ILLEGAL_STATE;
+ }
+ LOG(DEBUG) << __func__ << " instance " << instanceSp.get() << " destroyed";
+ return EX_NONE;
+}
+
+namespace aidl::android::hardware::audio::effect {
+
+ndk::ScopedAStatus VolumeSw::getDescriptor(Descriptor* _aidl_return) {
+ LOG(DEBUG) << __func__ << kDescriptor.toString();
+ *_aidl_return = kDescriptor;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus VolumeSw::setParameterSpecific(const Parameter::Specific& specific) {
+ RETURN_IF(Parameter::Specific::volume != specific.getTag(), EX_ILLEGAL_ARGUMENT,
+ "EffectNotSupported");
+ std::lock_guard lg(mMutex);
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+ mSpecificParam = specific.get<Parameter::Specific::volume>();
+ LOG(DEBUG) << __func__ << " success with: " << specific.toString();
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus VolumeSw::getParameterSpecific(const Parameter::Id& id,
+ Parameter::Specific* specific) {
+ auto tag = id.getTag();
+ RETURN_IF(Parameter::Id::volumeTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
+ specific->set<Parameter::Specific::volume>(mSpecificParam);
+ return ndk::ScopedAStatus::ok();
+}
+
+std::shared_ptr<EffectContext> VolumeSw::createContext(const Parameter::Common& common) {
+ if (mContext) {
+ LOG(DEBUG) << __func__ << " context already exist";
+ return mContext;
+ }
+ mContext = std::make_shared<VolumeSwContext>(1 /* statusFmqDepth */, common);
+ return mContext;
+}
+
+RetCode VolumeSw::releaseContext() {
+ if (mContext) {
+ mContext.reset();
+ }
+ return RetCode::SUCCESS;
+}
+
+// Processing method running in EffectWorker thread.
+IEffect::Status VolumeSw::effectProcessImpl(float* in, float* out, int process) {
+ // TODO: get data buffer and process.
+ LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
+ for (int i = 0; i < process; i++) {
+ *out++ = *in++;
+ }
+ return {STATUS_OK, process, process};
+}
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/volume/VolumeSw.h b/audio/aidl/default/volume/VolumeSw.h
new file mode 100644
index 0000000..86e01c1
--- /dev/null
+++ b/audio/aidl/default/volume/VolumeSw.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/audio/effect/BnEffect.h>
+#include <fmq/AidlMessageQueue.h>
+#include <cstdlib>
+#include <memory>
+
+#include "effect-impl/EffectImpl.h"
+#include "effect-impl/EffectUUID.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+class VolumeSwContext final : public EffectContext {
+ public:
+ VolumeSwContext(int statusDepth, const Parameter::Common& common)
+ : EffectContext(statusDepth, common) {
+ LOG(DEBUG) << __func__;
+ }
+ // TODO: add specific context here
+};
+
+class VolumeSw final : public EffectImpl {
+ public:
+ VolumeSw() { LOG(DEBUG) << __func__; }
+ ~VolumeSw() {
+ cleanUp();
+ LOG(DEBUG) << __func__;
+ }
+
+ ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
+ ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
+ ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
+ Parameter::Specific* specific) override;
+ IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+ std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+ RetCode releaseContext() override;
+
+ private:
+ std::shared_ptr<VolumeSwContext> mContext;
+ /* capabilities */
+ const Volume::Capability kCapability;
+ /* Effect descriptor */
+ const Descriptor kDescriptor = {
+ .common = {.id = {.type = kVolumeTypeUUID,
+ .uuid = kVolumeSwImplUUID,
+ .proxy = std::nullopt},
+ .flags = {.type = Flags::Type::INSERT,
+ .insert = Flags::Insert::FIRST,
+ .volume = Flags::Volume::CTRL},
+ .name = "VolumeSw",
+ .implementor = "The Android Open Source Project"},
+ .capability = Capability::make<Capability::volume>(kCapability)};
+
+ /* parameters */
+ Volume mSpecificParam;
+};
+} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/vts/Android.bp b/audio/aidl/vts/Android.bp
new file mode 100644
index 0000000..03e9fca
--- /dev/null
+++ b/audio/aidl/vts/Android.bp
@@ -0,0 +1,78 @@
+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: "VtsHalAudioTargetTestDefaults",
+ defaults: [
+ "latest_android_hardware_audio_common_ndk_static",
+ "latest_android_media_audio_common_types_ndk_static",
+ "use_libaidlvintf_gtest_helper_static",
+ "VtsHalTargetTestDefaults",
+ ],
+ shared_libs: [
+ "libbinder_ndk",
+ "libfmq",
+ ],
+ static_libs: [
+ "android.hardware.audio.effect-V1-ndk",
+ "android.hardware.common-V2-ndk",
+ "android.hardware.common.fmq-V1-ndk",
+ "libaudioaidlcommon",
+ ],
+ header_libs: ["libaudioaidl_headers"],
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-Wthread-safety",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+}
+
+cc_test {
+ name: "VtsHalAudioCoreTargetTest",
+ defaults: [
+ "VtsHalAudioTargetTestDefaults",
+ "latest_android_hardware_audio_core_ndk_static",
+ ],
+ shared_libs: [
+ "libcutils",
+ ],
+ srcs: [
+ "ModuleConfig.cpp",
+ "VtsHalAudioCoreTargetTest.cpp",
+ ],
+}
+
+cc_test {
+ name: "VtsHalAudioEffectFactoryTargetTest",
+ defaults: ["VtsHalAudioTargetTestDefaults"],
+ srcs: ["VtsHalAudioEffectFactoryTargetTest.cpp"],
+}
+
+cc_test {
+ name: "VtsHalAudioEffectTargetTest",
+ defaults: ["VtsHalAudioTargetTestDefaults"],
+ srcs: ["VtsHalAudioEffectTargetTest.cpp"],
+}
+
+cc_test {
+ name: "VtsHalEqualizerTargetTest",
+ defaults: ["VtsHalAudioTargetTestDefaults"],
+ srcs: ["VtsHalEqualizerTargetTest.cpp"],
+}
+
+cc_test {
+ name: "VtsHalLoudnessEnhancerTargetTest",
+ defaults: ["VtsHalAudioTargetTestDefaults"],
+ srcs: ["VtsHalLoudnessEnhancerTargetTest.cpp"],
+}
diff --git a/audio/aidl/vts/AudioHalBinderServiceUtil.h b/audio/aidl/vts/AudioHalBinderServiceUtil.h
new file mode 100644
index 0000000..c8d81b1
--- /dev/null
+++ b/audio/aidl/vts/AudioHalBinderServiceUtil.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+
+#include <android-base/properties.h>
+#include <android/binder_auto_utils.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+#include <android-base/logging.h>
+
+class AudioHalBinderServiceUtil {
+ public:
+ ndk::SpAIBinder connectToService(const std::string& serviceName) {
+ mServiceName = serviceName;
+ mBinder = ndk::SpAIBinder(AServiceManager_getService(serviceName.c_str()));
+ if (mBinder == nullptr) {
+ LOG(ERROR) << "Failed to get service " << serviceName;
+ } else {
+ LOG(DEBUG) << "Succeeded to get service " << serviceName;
+ }
+ return mBinder;
+ }
+
+ 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 (!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);
+ }
+
+ private:
+ class AidlDeathRecipient {
+ public:
+ explicit AidlDeathRecipient(const ndk::SpAIBinder& binder)
+ : binder(binder), recipient(AIBinder_DeathRecipient_new(&binderDiedCallbackAidl)) {}
+
+ binder_status_t linkToDeath() {
+ return AIBinder_linkToDeath(binder.get(), recipient.get(), this);
+ }
+
+ bool waitForFired(std::chrono::milliseconds timeoutMs) {
+ std::unique_lock<std::mutex> lock(mutex);
+ condition.wait_for(lock, timeoutMs, [this]() { return fired; });
+ return fired;
+ }
+
+ private:
+ const ndk::SpAIBinder binder;
+ const ndk::ScopedAIBinder_DeathRecipient recipient;
+ std::mutex mutex;
+ std::condition_variable condition;
+ bool fired = false;
+
+ void binderDied() {
+ std::unique_lock<std::mutex> lock(mutex);
+ fired = true;
+ condition.notify_one();
+ };
+
+ static void binderDiedCallbackAidl(void* cookie) {
+ AidlDeathRecipient* self = static_cast<AidlDeathRecipient*>(cookie);
+ self->binderDied();
+ }
+ };
+
+ std::string mServiceName;
+ ndk::SpAIBinder mBinder;
+ std::unique_ptr<AidlDeathRecipient> mDeathHandler;
+};
diff --git a/audio/aidl/vts/EffectFactoryHelper.h b/audio/aidl/vts/EffectFactoryHelper.h
new file mode 100644
index 0000000..dc766dd
--- /dev/null
+++ b/audio/aidl/vts/EffectFactoryHelper.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include <android/binder_auto_utils.h>
+
+#include "TestUtils.h"
+#include "effect-impl/EffectUUID.h"
+
+using namespace android;
+
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::media::audio::common::AudioUuid;
+
+class EffectFactoryHelper {
+ public:
+ explicit EffectFactoryHelper(const std::string& name) : mServiceName(name) {}
+
+ void ConnectToFactoryService() {
+ mEffectFactory = IFactory::fromBinder(binderUtil.connectToService(mServiceName));
+ ASSERT_NE(mEffectFactory, nullptr);
+ }
+
+ void RestartFactoryService() {
+ ASSERT_NE(mEffectFactory, nullptr);
+ mEffectFactory = IFactory::fromBinder(binderUtil.restartService());
+ ASSERT_NE(mEffectFactory, nullptr);
+ }
+
+ std::shared_ptr<IFactory> GetFactory() const { return mEffectFactory; }
+
+ static std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor::Identity>>
+ getAllEffectDescriptors(std::string serviceName, std::optional<AudioUuid> type = std::nullopt) {
+ AudioHalBinderServiceUtil util;
+ auto names = android::getAidlHalInstanceNames(serviceName);
+ std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor::Identity>> result;
+
+ for (const auto& name : names) {
+ auto factory = IFactory::fromBinder(util.connectToService(name));
+ if (factory) {
+ if (std::vector<Descriptor::Identity> ids;
+ factory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids).isOk()) {
+ for (const auto& id : ids) {
+ if (type.has_value() && id.type != type.value()) {
+ continue;
+ }
+ result.emplace_back(factory, id);
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+ private:
+ std::shared_ptr<IFactory> mEffectFactory;
+ std::string mServiceName;
+ AudioHalBinderServiceUtil binderUtil;
+};
diff --git a/audio/aidl/vts/EffectHelper.h b/audio/aidl/vts/EffectHelper.h
new file mode 100644
index 0000000..73a1f49
--- /dev/null
+++ b/audio/aidl/vts/EffectHelper.h
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <algorithm>
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include <aidl/android/hardware/audio/effect/IEffect.h>
+#include <aidl/android/hardware/audio/effect/IFactory.h>
+#include <aidl/android/media/audio/common/AudioChannelLayout.h>
+#include <android/binder_auto_utils.h>
+#include <fmq/AidlMessageQueue.h>
+
+#include "AudioHalBinderServiceUtil.h"
+#include "EffectFactoryHelper.h"
+#include "TestUtils.h"
+
+using namespace android;
+using aidl::android::hardware::audio::effect::CommandId;
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::Parameter;
+using aidl::android::hardware::audio::effect::State;
+using aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using aidl::android::media::audio::common::AudioChannelLayout;
+using aidl::android::media::audio::common::AudioFormatDescription;
+using aidl::android::media::audio::common::AudioFormatType;
+using aidl::android::media::audio::common::AudioUuid;
+using aidl::android::media::audio::common::PcmType;
+
+const AudioFormatDescription kDefaultFormatDescription = {
+ .type = AudioFormatType::PCM, .pcm = PcmType::FLOAT_32_BIT, .encoding = ""};
+
+typedef ::android::AidlMessageQueue<IEffect::Status,
+ ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
+ StatusMQ;
+typedef ::android::AidlMessageQueue<float,
+ ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
+ DataMQ;
+
+class EffectHelper {
+ public:
+ static void create(std::shared_ptr<IFactory> factory, std::shared_ptr<IEffect>& effect,
+ Descriptor::Identity id, binder_status_t status = EX_NONE) {
+ ASSERT_NE(factory, nullptr);
+ EXPECT_STATUS(status, factory->createEffect(id.uuid, &effect));
+ if (status == EX_NONE) {
+ ASSERT_NE(effect, nullptr) << id.uuid.toString();
+ }
+ }
+
+ static void destroy(std::shared_ptr<IFactory> factory, std::shared_ptr<IEffect> effect,
+ binder_status_t status = EX_NONE) {
+ ASSERT_NE(factory, nullptr);
+ ASSERT_NE(effect, nullptr);
+ EXPECT_STATUS(status, factory->destroyEffect(effect));
+ }
+
+ static void open(std::shared_ptr<IEffect> effect, const Parameter::Common& common,
+ const std::optional<Parameter::Specific>& specific,
+ IEffect::OpenEffectReturn* ret, binder_status_t status = EX_NONE) {
+ ASSERT_NE(effect, nullptr);
+ EXPECT_STATUS(status, effect->open(common, specific, ret));
+ }
+
+ static void open(std::shared_ptr<IEffect> effect, int session = 0,
+ binder_status_t status = EX_NONE) {
+ ASSERT_NE(effect, nullptr);
+ Parameter::Common common = EffectHelper::createParamCommon(session);
+ IEffect::OpenEffectReturn ret;
+ open(effect, common, std::nullopt /* specific */, &ret, status);
+ }
+
+ static void close(std::shared_ptr<IEffect> effect, binder_status_t status = EX_NONE) {
+ if (effect) {
+ EXPECT_STATUS(status, effect->close());
+ }
+ }
+ static void getDescriptor(std::shared_ptr<IEffect> effect, Descriptor& desc,
+ binder_status_t status = EX_NONE) {
+ ASSERT_NE(effect, nullptr);
+ EXPECT_STATUS(status, effect->getDescriptor(&desc));
+ }
+ static void expectState(std::shared_ptr<IEffect> effect, State expectState,
+ binder_status_t status = EX_NONE) {
+ ASSERT_NE(effect, nullptr);
+ State state;
+ EXPECT_STATUS(status, effect->getState(&state));
+ EXPECT_EQ(expectState, state);
+ }
+ static void command(std::shared_ptr<IEffect> effect, CommandId command,
+ binder_status_t status = EX_NONE) {
+ ASSERT_NE(effect, nullptr);
+ EXPECT_STATUS(status, effect->command(command));
+ }
+ static void allocateInputData(const Parameter::Common common, std::unique_ptr<DataMQ>& mq,
+ std::vector<float>& buffer) {
+ ASSERT_NE(mq, nullptr);
+ auto frameSize = android::hardware::audio::common::getFrameSizeInBytes(
+ common.input.base.format, common.input.base.channelMask);
+ const size_t floatsToWrite = mq->availableToWrite();
+ EXPECT_NE(0UL, floatsToWrite);
+ EXPECT_EQ(frameSize * common.input.frameCount, floatsToWrite * sizeof(float));
+ buffer.resize(floatsToWrite);
+ std::fill(buffer.begin(), buffer.end(), 0x5a);
+ }
+ static void writeToFmq(std::unique_ptr<DataMQ>& mq, const std::vector<float>& buffer) {
+ const size_t available = mq->availableToWrite();
+ EXPECT_NE(0Ul, available);
+ auto bufferFloats = buffer.size();
+ auto floatsToWrite = std::min(available, bufferFloats);
+ EXPECT_TRUE(mq->write(buffer.data(), floatsToWrite));
+ }
+ static void readFromFmq(std::unique_ptr<StatusMQ>& statusMq, size_t statusNum,
+ std::unique_ptr<DataMQ>& dataMq, size_t expectFloats,
+ std::vector<float>& buffer) {
+ IEffect::Status status{};
+ EXPECT_TRUE(statusMq->readBlocking(&status, statusNum));
+ EXPECT_EQ(STATUS_OK, status.status);
+ if (statusNum != 0) {
+ EXPECT_EQ(expectFloats, (unsigned)status.fmqProduced);
+ EXPECT_EQ(expectFloats, dataMq->availableToRead());
+ if (expectFloats != 0) {
+ EXPECT_TRUE(dataMq->read(buffer.data(), expectFloats));
+ }
+ }
+ }
+ static Parameter::Common createParamCommon(
+ int session = 0, int ioHandle = -1, int iSampleRate = 48000, int oSampleRate = 48000,
+ long iFrameCount = 0x100, long oFrameCount = 0x100,
+ AudioChannelLayout inputChannelLayout =
+ AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
+ AudioChannelLayout::LAYOUT_STEREO),
+ AudioChannelLayout outputChannelLayout =
+ AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
+ AudioChannelLayout::LAYOUT_STEREO)) {
+ Parameter::Common common;
+ common.session = session;
+ common.ioHandle = ioHandle;
+
+ auto& input = common.input;
+ auto& output = common.output;
+ input.base.sampleRate = iSampleRate;
+ input.base.channelMask = inputChannelLayout;
+ input.base.format = kDefaultFormatDescription;
+ input.frameCount = iFrameCount;
+ output.base.sampleRate = oSampleRate;
+ output.base.channelMask = outputChannelLayout;
+ output.base.format = kDefaultFormatDescription;
+ output.frameCount = oFrameCount;
+ return common;
+ }
+
+ typedef ::android::AidlMessageQueue<
+ IEffect::Status, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
+ StatusMQ;
+ typedef ::android::AidlMessageQueue<
+ float, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
+ DataMQ;
+
+ class EffectParam {
+ public:
+ std::unique_ptr<StatusMQ> statusMQ;
+ std::unique_ptr<DataMQ> inputMQ;
+ std::unique_ptr<DataMQ> outputMQ;
+ };
+};
diff --git a/audio/aidl/vts/ModuleConfig.cpp b/audio/aidl/vts/ModuleConfig.cpp
new file mode 100644
index 0000000..c081402
--- /dev/null
+++ b/audio/aidl/vts/ModuleConfig.cpp
@@ -0,0 +1,403 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <algorithm>
+#include <chrono>
+
+#include <Utils.h>
+#include <aidl/android/media/audio/common/AudioIoFlags.h>
+#include <aidl/android/media/audio/common/AudioOutputFlags.h>
+
+#include "ModuleConfig.h"
+
+using namespace android;
+using namespace std::chrono_literals;
+
+using aidl::android::hardware::audio::core::IModule;
+using aidl::android::media::audio::common::AudioChannelLayout;
+using aidl::android::media::audio::common::AudioEncapsulationMode;
+using aidl::android::media::audio::common::AudioFormatDescription;
+using aidl::android::media::audio::common::AudioFormatType;
+using aidl::android::media::audio::common::AudioIoFlags;
+using aidl::android::media::audio::common::AudioOffloadInfo;
+using aidl::android::media::audio::common::AudioOutputFlags;
+using aidl::android::media::audio::common::AudioPort;
+using aidl::android::media::audio::common::AudioPortConfig;
+using aidl::android::media::audio::common::AudioPortExt;
+using aidl::android::media::audio::common::AudioProfile;
+using aidl::android::media::audio::common::AudioUsage;
+using aidl::android::media::audio::common::Int;
+using android::hardware::audio::common::isBitPositionFlagSet;
+
+// static
+std::optional<AudioOffloadInfo> ModuleConfig::generateOffloadInfoIfNeeded(
+ const AudioPortConfig& portConfig) {
+ if (portConfig.flags.has_value() &&
+ portConfig.flags.value().getTag() == AudioIoFlags::Tag::output &&
+ isBitPositionFlagSet(portConfig.flags.value().get<AudioIoFlags::Tag::output>(),
+ AudioOutputFlags::COMPRESS_OFFLOAD)) {
+ AudioOffloadInfo offloadInfo;
+ offloadInfo.base.sampleRate = portConfig.sampleRate.value().value;
+ offloadInfo.base.channelMask = portConfig.channelMask.value();
+ offloadInfo.base.format = portConfig.format.value();
+ offloadInfo.bitRatePerSecond = 256; // Arbitrary value.
+ offloadInfo.durationUs = std::chrono::microseconds(1min).count(); // Arbitrary value.
+ offloadInfo.usage = AudioUsage::MEDIA;
+ offloadInfo.encapsulationMode = AudioEncapsulationMode::NONE;
+ return offloadInfo;
+ }
+ return {};
+}
+
+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; });
+}
+
+ModuleConfig::ModuleConfig(IModule* module) {
+ mStatus = module->getAudioPorts(&mPorts);
+ if (!mStatus.isOk()) return;
+ for (const auto& port : mPorts) {
+ if (port.ext.getTag() != AudioPortExt::Tag::device) continue;
+ const auto& devicePort = port.ext.get<AudioPortExt::Tag::device>();
+ if (devicePort.device.type.connection.empty()) {
+ const bool isInput = port.flags.getTag() == AudioIoFlags::Tag::input;
+ // Permanently attached device.
+ if (isInput) {
+ mAttachedSourceDevicePorts.insert(port.id);
+ } else {
+ mAttachedSinkDevicePorts.insert(port.id);
+ }
+ } else if (port.profiles.empty()) {
+ mExternalDevicePorts.insert(port.id);
+ }
+ }
+ if (!mStatus.isOk()) return;
+ mStatus = module->getAudioRoutes(&mRoutes);
+ if (!mStatus.isOk()) return;
+ mStatus = module->getAudioPortConfigs(&mInitialConfigs);
+}
+
+std::vector<AudioPort> ModuleConfig::getAttachedDevicePorts() const {
+ std::vector<AudioPort> result;
+ std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result), [&](const auto& port) {
+ return mAttachedSinkDevicePorts.count(port.id) != 0 ||
+ mAttachedSourceDevicePorts.count(port.id) != 0;
+ });
+ return result;
+}
+
+std::vector<AudioPort> ModuleConfig::getExternalDevicePorts() const {
+ std::vector<AudioPort> result;
+ std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result),
+ [&](const auto& port) { return mExternalDevicePorts.count(port.id) != 0; });
+ return result;
+}
+
+std::vector<AudioPort> ModuleConfig::getInputMixPorts() const {
+ std::vector<AudioPort> result;
+ std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result), [](const auto& port) {
+ return port.ext.getTag() == AudioPortExt::Tag::mix &&
+ port.flags.getTag() == AudioIoFlags::Tag::input;
+ });
+ return result;
+}
+
+std::vector<AudioPort> ModuleConfig::getOutputMixPorts() const {
+ std::vector<AudioPort> result;
+ std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result), [](const auto& port) {
+ return port.ext.getTag() == AudioPortExt::Tag::mix &&
+ port.flags.getTag() == AudioIoFlags::Tag::output;
+ });
+ return result;
+}
+
+std::vector<AudioPort> ModuleConfig::getNonBlockingMixPorts(bool attachedOnly,
+ bool singlePort) const {
+ return findMixPorts(false /*isInput*/, singlePort, [&](const AudioPort& port) {
+ return isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::output>(),
+ AudioOutputFlags::NON_BLOCKING) &&
+ (!attachedOnly || !getAttachedSinkDevicesPortsForMixPort(port).empty());
+ });
+}
+
+std::vector<AudioPort> ModuleConfig::getOffloadMixPorts(bool attachedOnly, bool singlePort) const {
+ return findMixPorts(false /*isInput*/, singlePort, [&](const AudioPort& port) {
+ return isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::output>(),
+ AudioOutputFlags::COMPRESS_OFFLOAD) &&
+ (!attachedOnly || !getAttachedSinkDevicesPortsForMixPort(port).empty());
+ });
+}
+
+std::vector<AudioPort> ModuleConfig::getAttachedDevicesPortsForMixPort(
+ bool isInput, const AudioPortConfig& mixPortConfig) const {
+ const auto mixPortIt = findById<AudioPort>(mPorts, mixPortConfig.portId);
+ if (mixPortIt != mPorts.end()) {
+ return getAttachedDevicesPortsForMixPort(isInput, *mixPortIt);
+ }
+ return {};
+}
+
+std::vector<AudioPort> ModuleConfig::getAttachedSinkDevicesPortsForMixPort(
+ const AudioPort& mixPort) const {
+ std::vector<AudioPort> result;
+ for (const auto& route : mRoutes) {
+ if (mAttachedSinkDevicePorts.count(route.sinkPortId) != 0 &&
+ std::find(route.sourcePortIds.begin(), route.sourcePortIds.end(), mixPort.id) !=
+ route.sourcePortIds.end()) {
+ const auto devicePortIt = findById<AudioPort>(mPorts, route.sinkPortId);
+ if (devicePortIt != mPorts.end()) result.push_back(*devicePortIt);
+ }
+ }
+ return result;
+}
+
+std::vector<AudioPort> ModuleConfig::getAttachedSourceDevicesPortsForMixPort(
+ const AudioPort& mixPort) const {
+ std::vector<AudioPort> result;
+ for (const auto& route : mRoutes) {
+ if (route.sinkPortId == mixPort.id) {
+ for (const auto srcId : route.sourcePortIds) {
+ if (mAttachedSourceDevicePorts.count(srcId) != 0) {
+ const auto devicePortIt = findById<AudioPort>(mPorts, srcId);
+ if (devicePortIt != mPorts.end()) result.push_back(*devicePortIt);
+ }
+ }
+ }
+ }
+ return result;
+}
+
+std::optional<AudioPort> ModuleConfig::getSourceMixPortForAttachedDevice() const {
+ for (const auto& route : mRoutes) {
+ if (mAttachedSinkDevicePorts.count(route.sinkPortId) != 0) {
+ const auto mixPortIt = findById<AudioPort>(mPorts, route.sourcePortIds[0]);
+ if (mixPortIt != mPorts.end()) return *mixPortIt;
+ }
+ }
+ return {};
+}
+
+std::optional<ModuleConfig::SrcSinkPair> ModuleConfig::getNonRoutableSrcSinkPair(
+ bool isInput) const {
+ const auto mixPorts = getMixPorts(isInput);
+ std::set<std::pair<int32_t, int32_t>> allowedRoutes;
+ for (const auto& route : mRoutes) {
+ for (const auto srcPortId : route.sourcePortIds) {
+ allowedRoutes.emplace(std::make_pair(srcPortId, route.sinkPortId));
+ }
+ }
+ auto make_pair = [isInput](auto& device, auto& mix) {
+ return isInput ? std::make_pair(device, mix) : std::make_pair(mix, device);
+ };
+ for (const auto portId : isInput ? mAttachedSourceDevicePorts : mAttachedSinkDevicePorts) {
+ const auto devicePortIt = findById<AudioPort>(mPorts, portId);
+ if (devicePortIt == mPorts.end()) continue;
+ auto devicePortConfig = getSingleConfigForDevicePort(*devicePortIt);
+ for (const auto& mixPort : mixPorts) {
+ if (std::find(allowedRoutes.begin(), allowedRoutes.end(),
+ make_pair(portId, mixPort.id)) == allowedRoutes.end()) {
+ auto mixPortConfig = getSingleConfigForMixPort(isInput, mixPort);
+ if (mixPortConfig.has_value()) {
+ return make_pair(devicePortConfig, mixPortConfig.value());
+ }
+ }
+ }
+ }
+ return {};
+}
+
+std::optional<ModuleConfig::SrcSinkPair> ModuleConfig::getRoutableSrcSinkPair(bool isInput) const {
+ if (isInput) {
+ for (const auto& route : mRoutes) {
+ auto srcPortIdIt = std::find_if(
+ route.sourcePortIds.begin(), route.sourcePortIds.end(),
+ [&](const auto& portId) { return mAttachedSourceDevicePorts.count(portId); });
+ if (srcPortIdIt == route.sourcePortIds.end()) continue;
+ const auto devicePortIt = findById<AudioPort>(mPorts, *srcPortIdIt);
+ const auto mixPortIt = findById<AudioPort>(mPorts, route.sinkPortId);
+ if (devicePortIt == mPorts.end() || mixPortIt == mPorts.end()) continue;
+ auto devicePortConfig = getSingleConfigForDevicePort(*devicePortIt);
+ auto mixPortConfig = getSingleConfigForMixPort(isInput, *mixPortIt);
+ if (!mixPortConfig.has_value()) continue;
+ return std::make_pair(devicePortConfig, mixPortConfig.value());
+ }
+ } else {
+ for (const auto& route : mRoutes) {
+ if (mAttachedSinkDevicePorts.count(route.sinkPortId) == 0) continue;
+ const auto mixPortIt = findById<AudioPort>(mPorts, route.sourcePortIds[0]);
+ const auto devicePortIt = findById<AudioPort>(mPorts, route.sinkPortId);
+ if (devicePortIt == mPorts.end() || mixPortIt == mPorts.end()) continue;
+ auto mixPortConfig = getSingleConfigForMixPort(isInput, *mixPortIt);
+ auto devicePortConfig = getSingleConfigForDevicePort(*devicePortIt);
+ if (!mixPortConfig.has_value()) continue;
+ return std::make_pair(mixPortConfig.value(), devicePortConfig);
+ }
+ }
+ return {};
+}
+
+std::vector<ModuleConfig::SrcSinkGroup> ModuleConfig::getRoutableSrcSinkGroups(bool isInput) const {
+ std::vector<SrcSinkGroup> result;
+ if (isInput) {
+ for (const auto& route : mRoutes) {
+ std::vector<int32_t> srcPortIds;
+ std::copy_if(route.sourcePortIds.begin(), route.sourcePortIds.end(),
+ std::back_inserter(srcPortIds), [&](const auto& portId) {
+ return mAttachedSourceDevicePorts.count(portId);
+ });
+ if (srcPortIds.empty()) continue;
+ const auto mixPortIt = findById<AudioPort>(mPorts, route.sinkPortId);
+ if (mixPortIt == mPorts.end()) continue;
+ auto mixPortConfig = getSingleConfigForMixPort(isInput, *mixPortIt);
+ if (!mixPortConfig.has_value()) continue;
+ std::vector<SrcSinkPair> pairs;
+ for (const auto srcPortId : srcPortIds) {
+ const auto devicePortIt = findById<AudioPort>(mPorts, srcPortId);
+ if (devicePortIt == mPorts.end()) continue;
+ // Using all configs for every source would be too much.
+ auto devicePortConfig = getSingleConfigForDevicePort(*devicePortIt);
+ pairs.emplace_back(devicePortConfig, mixPortConfig.value());
+ }
+ if (!pairs.empty()) {
+ result.emplace_back(route, std::move(pairs));
+ }
+ }
+ } else {
+ for (const auto& route : mRoutes) {
+ if (mAttachedSinkDevicePorts.count(route.sinkPortId) == 0) continue;
+ const auto devicePortIt = findById<AudioPort>(mPorts, route.sinkPortId);
+ if (devicePortIt == mPorts.end()) continue;
+ auto devicePortConfig = getSingleConfigForDevicePort(*devicePortIt);
+ std::vector<SrcSinkPair> pairs;
+ for (const auto srcPortId : route.sourcePortIds) {
+ const auto mixPortIt = findById<AudioPort>(mPorts, srcPortId);
+ if (mixPortIt == mPorts.end()) continue;
+ // Using all configs for every source would be too much.
+ auto mixPortConfig = getSingleConfigForMixPort(isInput, *mixPortIt);
+ if (mixPortConfig.has_value()) {
+ pairs.emplace_back(mixPortConfig.value(), devicePortConfig);
+ }
+ }
+ if (!pairs.empty()) {
+ result.emplace_back(route, std::move(pairs));
+ }
+ }
+ }
+ return result;
+}
+
+std::string ModuleConfig::toString() const {
+ std::string result;
+ result.append("Ports: ");
+ result.append(android::internal::ToString(mPorts));
+ result.append("\nInitial configs: ");
+ result.append(android::internal::ToString(mInitialConfigs));
+ result.append("\nAttached sink device ports: ");
+ result.append(android::internal::ToString(mAttachedSinkDevicePorts));
+ result.append("\nAttached source device ports: ");
+ result.append(android::internal::ToString(mAttachedSourceDevicePorts));
+ result.append("\nExternal device ports: ");
+ result.append(android::internal::ToString(mExternalDevicePorts));
+ result.append("\nRoutes: ");
+ result.append(android::internal::ToString(mRoutes));
+ return result;
+}
+
+static size_t combineAudioConfigs(const AudioPort& port, const AudioProfile& profile,
+ std::vector<AudioPortConfig>* result) {
+ const size_t newConfigCount = profile.channelMasks.size() * profile.sampleRates.size();
+ result->reserve(result->capacity() + newConfigCount);
+ for (auto channelMask : profile.channelMasks) {
+ for (auto sampleRate : profile.sampleRates) {
+ AudioPortConfig config{};
+ config.portId = port.id;
+ Int sr;
+ sr.value = sampleRate;
+ config.sampleRate = sr;
+ config.channelMask = channelMask;
+ config.format = profile.format;
+ config.flags = port.flags;
+ config.ext = port.ext;
+ result->push_back(std::move(config));
+ }
+ }
+ return newConfigCount;
+}
+
+static bool isDynamicProfile(const AudioProfile& profile) {
+ return (profile.format.type == AudioFormatType::DEFAULT && profile.format.encoding.empty()) ||
+ profile.sampleRates.empty() || profile.channelMasks.empty();
+}
+
+std::vector<AudioPort> ModuleConfig::findMixPorts(
+ bool isInput, bool singlePort, std::function<bool(const AudioPort&)> pred) const {
+ std::vector<AudioPort> result;
+ const auto mixPorts = getMixPorts(isInput);
+ for (auto mixPortIt = mixPorts.begin(); mixPortIt != mixPorts.end();) {
+ mixPortIt = std::find_if(mixPortIt, mixPorts.end(), pred);
+ if (mixPortIt == mixPorts.end()) break;
+ result.push_back(*mixPortIt++);
+ if (singlePort) break;
+ }
+ return result;
+}
+
+std::vector<AudioPortConfig> ModuleConfig::generateAudioMixPortConfigs(
+ const std::vector<AudioPort>& ports, bool isInput, bool singleProfile) const {
+ std::vector<AudioPortConfig> result;
+ for (const auto& mixPort : ports) {
+ if (getAttachedDevicesPortsForMixPort(isInput, mixPort).empty()) {
+ continue;
+ }
+ for (const auto& profile : mixPort.profiles) {
+ if (isDynamicProfile(profile)) continue;
+ combineAudioConfigs(mixPort, profile, &result);
+ if (singleProfile && !result.empty()) {
+ result.resize(1);
+ return result;
+ }
+ }
+ }
+ return result;
+}
+
+std::vector<AudioPortConfig> ModuleConfig::generateAudioDevicePortConfigs(
+ const std::vector<AudioPort>& ports, bool singleProfile) const {
+ std::vector<AudioPortConfig> result;
+ for (const auto& devicePort : ports) {
+ const size_t resultSizeBefore = result.size();
+ for (const auto& profile : devicePort.profiles) {
+ combineAudioConfigs(devicePort, profile, &result);
+ if (singleProfile && !result.empty()) {
+ result.resize(1);
+ return result;
+ }
+ }
+ if (resultSizeBefore == result.size()) {
+ std::copy_if(mInitialConfigs.begin(), mInitialConfigs.end(), std::back_inserter(result),
+ [&](const auto& config) { return config.portId == devicePort.id; });
+ if (resultSizeBefore == result.size()) {
+ AudioPortConfig empty;
+ empty.portId = devicePort.id;
+ empty.ext = devicePort.ext;
+ result.push_back(empty);
+ }
+ }
+ if (singleProfile) return result;
+ }
+ return result;
+}
diff --git a/audio/aidl/vts/ModuleConfig.h b/audio/aidl/vts/ModuleConfig.h
new file mode 100644
index 0000000..a85aa7f
--- /dev/null
+++ b/audio/aidl/vts/ModuleConfig.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <functional>
+#include <optional>
+#include <set>
+#include <utility>
+#include <vector>
+
+#include <aidl/android/hardware/audio/core/AudioRoute.h>
+#include <aidl/android/hardware/audio/core/IModule.h>
+#include <aidl/android/media/audio/common/AudioOffloadInfo.h>
+#include <aidl/android/media/audio/common/AudioPort.h>
+
+class ModuleConfig {
+ public:
+ using SrcSinkPair = std::pair<aidl::android::media::audio::common::AudioPortConfig,
+ aidl::android::media::audio::common::AudioPortConfig>;
+ using SrcSinkGroup =
+ std::pair<aidl::android::hardware::audio::core::AudioRoute, std::vector<SrcSinkPair>>;
+
+ static std::optional<aidl::android::media::audio::common::AudioOffloadInfo>
+ generateOffloadInfoIfNeeded(
+ const aidl::android::media::audio::common::AudioPortConfig& portConfig);
+
+ explicit ModuleConfig(aidl::android::hardware::audio::core::IModule* module);
+ const ndk::ScopedAStatus& getStatus() const { return mStatus; }
+ std::string getError() const { return mStatus.getMessage(); }
+
+ std::vector<aidl::android::media::audio::common::AudioPort> getAttachedDevicePorts() const;
+ std::vector<aidl::android::media::audio::common::AudioPort> getExternalDevicePorts() const;
+ std::vector<aidl::android::media::audio::common::AudioPort> getInputMixPorts() const;
+ std::vector<aidl::android::media::audio::common::AudioPort> getOutputMixPorts() const;
+ std::vector<aidl::android::media::audio::common::AudioPort> getMixPorts(bool isInput) const {
+ return isInput ? getInputMixPorts() : getOutputMixPorts();
+ }
+ std::vector<aidl::android::media::audio::common::AudioPort> getNonBlockingMixPorts(
+ bool attachedOnly, bool singlePort) const;
+ std::vector<aidl::android::media::audio::common::AudioPort> getOffloadMixPorts(
+ bool attachedOnly, bool singlePort) const;
+
+ std::vector<aidl::android::media::audio::common::AudioPort> getAttachedDevicesPortsForMixPort(
+ bool isInput, const aidl::android::media::audio::common::AudioPort& mixPort) const {
+ return isInput ? getAttachedSourceDevicesPortsForMixPort(mixPort)
+ : getAttachedSinkDevicesPortsForMixPort(mixPort);
+ }
+ std::vector<aidl::android::media::audio::common::AudioPort> getAttachedDevicesPortsForMixPort(
+ bool isInput,
+ const aidl::android::media::audio::common::AudioPortConfig& mixPortConfig) const;
+ std::vector<aidl::android::media::audio::common::AudioPort>
+ getAttachedSinkDevicesPortsForMixPort(
+ const aidl::android::media::audio::common::AudioPort& mixPort) const;
+ std::vector<aidl::android::media::audio::common::AudioPort>
+ getAttachedSourceDevicesPortsForMixPort(
+ const aidl::android::media::audio::common::AudioPort& mixPort) const;
+ std::optional<aidl::android::media::audio::common::AudioPort>
+ getSourceMixPortForAttachedDevice() const;
+
+ std::optional<SrcSinkPair> getNonRoutableSrcSinkPair(bool isInput) const;
+ std::optional<SrcSinkPair> getRoutableSrcSinkPair(bool isInput) const;
+ std::vector<SrcSinkGroup> getRoutableSrcSinkGroups(bool isInput) const;
+
+ std::vector<aidl::android::media::audio::common::AudioPortConfig>
+ getPortConfigsForAttachedDevicePorts() const {
+ return generateAudioDevicePortConfigs(getAttachedDevicePorts(), false);
+ }
+ std::vector<aidl::android::media::audio::common::AudioPortConfig> getPortConfigsForMixPorts()
+ const {
+ auto inputs = generateAudioMixPortConfigs(getInputMixPorts(), true, false);
+ auto outputs = generateAudioMixPortConfigs(getOutputMixPorts(), false, false);
+ inputs.insert(inputs.end(), outputs.begin(), outputs.end());
+ return inputs;
+ }
+ std::vector<aidl::android::media::audio::common::AudioPortConfig> getPortConfigsForMixPorts(
+ bool isInput) const {
+ return generateAudioMixPortConfigs(getMixPorts(isInput), isInput, false);
+ }
+ std::vector<aidl::android::media::audio::common::AudioPortConfig> getPortConfigsForMixPorts(
+ bool isInput, const aidl::android::media::audio::common::AudioPort& port) const {
+ return generateAudioMixPortConfigs({port}, isInput, false);
+ }
+ std::optional<aidl::android::media::audio::common::AudioPortConfig> getSingleConfigForMixPort(
+ bool isInput) const {
+ const auto config = generateAudioMixPortConfigs(getMixPorts(isInput), isInput, true);
+ if (!config.empty()) {
+ return *config.begin();
+ }
+ return {};
+ }
+ std::optional<aidl::android::media::audio::common::AudioPortConfig> getSingleConfigForMixPort(
+ bool isInput, const aidl::android::media::audio::common::AudioPort& port) const {
+ const auto config = generateAudioMixPortConfigs({port}, isInput, true);
+ if (!config.empty()) {
+ return *config.begin();
+ }
+ return {};
+ }
+
+ std::vector<aidl::android::media::audio::common::AudioPortConfig> getPortConfigsForDevicePort(
+ const aidl::android::media::audio::common::AudioPort& port) const {
+ return generateAudioDevicePortConfigs({port}, false);
+ }
+ aidl::android::media::audio::common::AudioPortConfig getSingleConfigForDevicePort(
+ const aidl::android::media::audio::common::AudioPort& port) const {
+ const auto config = generateAudioDevicePortConfigs({port}, true);
+ return *config.begin();
+ }
+
+ std::string toString() const;
+
+ private:
+ std::vector<aidl::android::media::audio::common::AudioPort> findMixPorts(
+ bool isInput, bool singlePort,
+ std::function<bool(const aidl::android::media::audio::common::AudioPort&)> pred) const;
+ std::vector<aidl::android::media::audio::common::AudioPortConfig> generateAudioMixPortConfigs(
+ const std::vector<aidl::android::media::audio::common::AudioPort>& ports, bool isInput,
+ bool singleProfile) const;
+
+ // Unlike MixPorts, the generator for DevicePorts always returns a non-empty
+ // vector for a non-empty input port list. If there are no profiles in the
+ // port, its initial configs are looked up, if there are none,
+ // then an empty config is used, assuming further negotiation via setAudioPortConfig.
+ std::vector<aidl::android::media::audio::common::AudioPortConfig>
+ generateAudioDevicePortConfigs(
+ const std::vector<aidl::android::media::audio::common::AudioPort>& ports,
+ bool singleProfile) const;
+
+ ndk::ScopedAStatus mStatus = ndk::ScopedAStatus::ok();
+ std::vector<aidl::android::media::audio::common::AudioPort> mPorts;
+ std::vector<aidl::android::media::audio::common::AudioPortConfig> mInitialConfigs;
+ std::set<int32_t> mAttachedSinkDevicePorts;
+ std::set<int32_t> mAttachedSourceDevicePorts;
+ std::set<int32_t> mExternalDevicePorts;
+ std::vector<aidl::android::hardware::audio::core::AudioRoute> mRoutes;
+};
diff --git a/audio/aidl/vts/TestUtils.h b/audio/aidl/vts/TestUtils.h
new file mode 100644
index 0000000..5e4d56a
--- /dev/null
+++ b/audio/aidl/vts/TestUtils.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <iostream>
+
+#include <android/binder_auto_utils.h>
+#include <gtest/gtest_pred_impl.h>
+
+namespace android::hardware::audio::common::testing {
+
+namespace detail {
+
+inline ::testing::AssertionResult assertIsOk(const char* expr, const ::ndk::ScopedAStatus& status) {
+ if (status.isOk()) {
+ return ::testing::AssertionSuccess();
+ }
+ return ::testing::AssertionFailure()
+ << "Expected the transaction \'" << expr << "\' to succeed\n"
+ << " but it has failed with: " << status;
+}
+
+inline ::testing::AssertionResult assertResult(const char* exp_expr, const char* act_expr,
+ int32_t expected,
+ const ::ndk::ScopedAStatus& status) {
+ if (status.getExceptionCode() == expected) {
+ return ::testing::AssertionSuccess();
+ }
+ return ::testing::AssertionFailure()
+ << "Expected the transaction \'" << act_expr << "\' to fail with " << exp_expr
+ << "\n but is has completed with: " << status;
+}
+
+} // namespace detail
+
+} // namespace android::hardware::audio::common::testing
+
+// Test that the transaction status 'isOk'
+#define ASSERT_IS_OK(ret) \
+ ASSERT_PRED_FORMAT1(::android::hardware::audio::common::testing::detail::assertIsOk, ret)
+#define EXPECT_IS_OK(ret) \
+ EXPECT_PRED_FORMAT1(::android::hardware::audio::common::testing::detail::assertIsOk, ret)
+
+// Test that the transaction status is as expected.
+#define ASSERT_STATUS(expected, ret) \
+ ASSERT_PRED_FORMAT2(::android::hardware::audio::common::testing::detail::assertResult, \
+ expected, ret)
+#define EXPECT_STATUS(expected, ret) \
+ EXPECT_PRED_FORMAT2(::android::hardware::audio::common::testing::detail::assertResult, \
+ expected, ret)
diff --git a/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp
new file mode 100644
index 0000000..79b20fe
--- /dev/null
+++ b/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp
@@ -0,0 +1,2580 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <algorithm>
+#include <chrono>
+#include <cmath>
+#include <condition_variable>
+#include <limits>
+#include <memory>
+#include <mutex>
+#include <optional>
+#include <set>
+#include <string>
+#include <variant>
+#include <vector>
+
+#define LOG_TAG "VtsHalAudioCore"
+#include <android-base/logging.h>
+
+#include <StreamWorker.h>
+#include <Utils.h>
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/audio/core/BnStreamCallback.h>
+#include <aidl/android/hardware/audio/core/IModule.h>
+#include <aidl/android/hardware/audio/core/ITelephony.h>
+#include <aidl/android/media/audio/common/AudioIoFlags.h>
+#include <aidl/android/media/audio/common/AudioOutputFlags.h>
+#include <android-base/chrono_utils.h>
+#include <android/binder_enums.h>
+#include <fmq/AidlMessageQueue.h>
+
+#include "AudioHalBinderServiceUtil.h"
+#include "ModuleConfig.h"
+#include "TestUtils.h"
+
+using namespace android;
+using aidl::android::hardware::audio::common::PlaybackTrackMetadata;
+using aidl::android::hardware::audio::common::RecordTrackMetadata;
+using aidl::android::hardware::audio::common::SinkMetadata;
+using aidl::android::hardware::audio::common::SourceMetadata;
+using aidl::android::hardware::audio::core::AudioMode;
+using aidl::android::hardware::audio::core::AudioPatch;
+using aidl::android::hardware::audio::core::AudioRoute;
+using aidl::android::hardware::audio::core::IModule;
+using aidl::android::hardware::audio::core::IStreamIn;
+using aidl::android::hardware::audio::core::IStreamOut;
+using aidl::android::hardware::audio::core::ITelephony;
+using aidl::android::hardware::audio::core::ModuleDebug;
+using aidl::android::hardware::audio::core::StreamDescriptor;
+using aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using aidl::android::media::audio::common::AudioContentType;
+using aidl::android::media::audio::common::AudioDevice;
+using aidl::android::media::audio::common::AudioDeviceAddress;
+using aidl::android::media::audio::common::AudioDeviceType;
+using aidl::android::media::audio::common::AudioFormatType;
+using aidl::android::media::audio::common::AudioIoFlags;
+using aidl::android::media::audio::common::AudioOutputFlags;
+using aidl::android::media::audio::common::AudioPort;
+using aidl::android::media::audio::common::AudioPortConfig;
+using aidl::android::media::audio::common::AudioPortDeviceExt;
+using aidl::android::media::audio::common::AudioPortExt;
+using aidl::android::media::audio::common::AudioSource;
+using aidl::android::media::audio::common::AudioUsage;
+using aidl::android::media::audio::common::Void;
+using android::hardware::audio::common::isBitPositionFlagSet;
+using android::hardware::audio::common::StreamLogic;
+using android::hardware::audio::common::StreamWorker;
+using ndk::enum_range;
+using ndk::ScopedAStatus;
+
+template <typename T>
+auto findById(std::vector<T>& v, int32_t id) {
+ return std::find_if(v.begin(), v.end(), [&](const auto& e) { return e.id == id; });
+}
+
+template <typename C>
+std::vector<int32_t> GetNonExistentIds(const C& allIds) {
+ if (allIds.empty()) {
+ return std::vector<int32_t>{-1, 0, 1};
+ }
+ std::vector<int32_t> nonExistentIds;
+ nonExistentIds.push_back(*std::min_element(allIds.begin(), allIds.end()) - 1);
+ nonExistentIds.push_back(*std::max_element(allIds.begin(), allIds.end()) + 1);
+ return nonExistentIds;
+}
+
+AudioDeviceAddress GenerateUniqueDeviceAddress() {
+ static int nextId = 1;
+ // TODO: Use connection-specific ID.
+ return AudioDeviceAddress::make<AudioDeviceAddress::Tag::id>(std::to_string(++nextId));
+}
+
+// All 'With*' classes are move-only because they are associated with some
+// resource or state of a HAL module.
+class WithDebugFlags {
+ public:
+ static WithDebugFlags createNested(const WithDebugFlags& parent) {
+ return WithDebugFlags(parent.mFlags);
+ }
+
+ WithDebugFlags() {}
+ explicit WithDebugFlags(const ModuleDebug& initial) : mInitial(initial), mFlags(initial) {}
+ WithDebugFlags(const WithDebugFlags&) = delete;
+ WithDebugFlags& operator=(const WithDebugFlags&) = delete;
+ ~WithDebugFlags() {
+ if (mModule != nullptr) {
+ EXPECT_IS_OK(mModule->setModuleDebug(mInitial));
+ }
+ }
+ void SetUp(IModule* module) { ASSERT_IS_OK(module->setModuleDebug(mFlags)); }
+ ModuleDebug& flags() { return mFlags; }
+
+ private:
+ ModuleDebug mInitial;
+ ModuleDebug mFlags;
+ IModule* mModule = nullptr;
+};
+
+// For consistency, WithAudioPortConfig can start both with a non-existent
+// port config, and with an existing one. Existence is determined by the
+// id of the provided config. If it's not 0, then WithAudioPortConfig is
+// essentially a no-op wrapper.
+class WithAudioPortConfig {
+ public:
+ WithAudioPortConfig() {}
+ explicit WithAudioPortConfig(const AudioPortConfig& config) : mInitialConfig(config) {}
+ WithAudioPortConfig(const WithAudioPortConfig&) = delete;
+ WithAudioPortConfig& operator=(const WithAudioPortConfig&) = delete;
+ ~WithAudioPortConfig() {
+ if (mModule != nullptr) {
+ EXPECT_IS_OK(mModule->resetAudioPortConfig(getId())) << "port config id " << getId();
+ }
+ }
+ void SetUp(IModule* module) {
+ ASSERT_NE(AudioPortExt::Tag::unspecified, mInitialConfig.ext.getTag())
+ << "config: " << mInitialConfig.toString();
+ // Negotiation is allowed for device ports because the HAL module is
+ // allowed to provide an empty profiles list for attached devices.
+ ASSERT_NO_FATAL_FAILURE(
+ SetUpImpl(module, mInitialConfig.ext.getTag() == AudioPortExt::Tag::device));
+ }
+ int32_t getId() const { return mConfig.id; }
+ const AudioPortConfig& get() const { return mConfig; }
+
+ private:
+ void SetUpImpl(IModule* module, bool negotiate) {
+ if (mInitialConfig.id == 0) {
+ AudioPortConfig suggested;
+ bool applied = false;
+ ASSERT_IS_OK(module->setAudioPortConfig(mInitialConfig, &suggested, &applied))
+ << "Config: " << mInitialConfig.toString();
+ if (!applied && negotiate) {
+ mInitialConfig = suggested;
+ ASSERT_NO_FATAL_FAILURE(SetUpImpl(module, false))
+ << " while applying suggested config: " << suggested.toString();
+ } else {
+ ASSERT_TRUE(applied) << "Suggested: " << suggested.toString();
+ mConfig = suggested;
+ mModule = module;
+ }
+ } else {
+ mConfig = mInitialConfig;
+ }
+ }
+
+ AudioPortConfig mInitialConfig;
+ IModule* mModule = nullptr;
+ AudioPortConfig mConfig;
+};
+
+template <typename PropType, class Instance, typename Getter, typename Setter>
+void TestAccessors(Instance* inst, Getter getter, Setter setter,
+ const std::vector<PropType>& validValues,
+ const std::vector<PropType>& invalidValues, bool* isSupported) {
+ PropType initialValue{};
+ ScopedAStatus status = (inst->*getter)(&initialValue);
+ if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+ *isSupported = false;
+ return;
+ }
+ *isSupported = true;
+ for (const auto v : validValues) {
+ EXPECT_IS_OK((inst->*setter)(v)) << "for valid value: " << v;
+ PropType currentValue{};
+ EXPECT_IS_OK((inst->*getter)(¤tValue));
+ EXPECT_EQ(v, currentValue);
+ }
+ for (const auto v : invalidValues) {
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, (inst->*setter)(v)) << "for invalid value: " << v;
+ }
+ EXPECT_IS_OK((inst->*setter)(initialValue)) << "Failed to restore the initial value";
+}
+
+// Can be used as a base for any test here, does not depend on the fixture GTest parameters.
+class AudioCoreModuleBase {
+ public:
+ // The default buffer size is used mostly for negative tests.
+ static constexpr int kDefaultBufferSizeFrames = 256;
+
+ void SetUpImpl(const std::string& moduleName) {
+ ASSERT_NO_FATAL_FAILURE(ConnectToService(moduleName));
+ debug.flags().simulateDeviceConnections = true;
+ ASSERT_NO_FATAL_FAILURE(debug.SetUp(module.get()));
+ }
+
+ void TearDownImpl() {
+ if (module != nullptr) {
+ EXPECT_IS_OK(module->setModuleDebug(ModuleDebug{}));
+ }
+ }
+
+ void ConnectToService(const std::string& moduleName) {
+ module = IModule::fromBinder(binderUtil.connectToService(moduleName));
+ ASSERT_NE(module, nullptr);
+ }
+
+ void RestartService() {
+ ASSERT_NE(module, nullptr);
+ moduleConfig.reset();
+ module = IModule::fromBinder(binderUtil.restartService());
+ ASSERT_NE(module, nullptr);
+ }
+
+ void ApplyEveryConfig(const std::vector<AudioPortConfig>& configs) {
+ for (const auto& config : configs) {
+ ASSERT_NE(0, config.portId);
+ WithAudioPortConfig portConfig(config);
+ ASSERT_NO_FATAL_FAILURE(portConfig.SetUp(module.get())); // calls setAudioPortConfig
+ EXPECT_EQ(config.portId, portConfig.get().portId);
+ std::vector<AudioPortConfig> retrievedPortConfigs;
+ ASSERT_IS_OK(module->getAudioPortConfigs(&retrievedPortConfigs));
+ const int32_t portConfigId = portConfig.getId();
+ auto configIt = std::find_if(
+ retrievedPortConfigs.begin(), retrievedPortConfigs.end(),
+ [&portConfigId](const auto& retrConf) { return retrConf.id == portConfigId; });
+ EXPECT_NE(configIt, retrievedPortConfigs.end())
+ << "Port config id returned by setAudioPortConfig: " << portConfigId
+ << " is not found in the list returned by getAudioPortConfigs";
+ if (configIt != retrievedPortConfigs.end()) {
+ EXPECT_EQ(portConfig.get(), *configIt)
+ << "Applied port config returned by setAudioPortConfig: "
+ << portConfig.get().toString()
+ << " is not the same as retrieved via getAudioPortConfigs: "
+ << configIt->toString();
+ }
+ }
+ }
+
+ template <typename Entity>
+ void GetAllEntityIds(std::set<int32_t>* entityIds,
+ ScopedAStatus (IModule::*getter)(std::vector<Entity>*),
+ const std::string& errorMessage) {
+ std::vector<Entity> entities;
+ { ASSERT_IS_OK((module.get()->*getter)(&entities)); }
+ std::transform(entities.begin(), entities.end(),
+ std::inserter(*entityIds, entityIds->begin()),
+ [](const auto& entity) { return entity.id; });
+ EXPECT_EQ(entities.size(), entityIds->size()) << errorMessage;
+ }
+
+ void GetAllPatchIds(std::set<int32_t>* patchIds) {
+ return GetAllEntityIds<AudioPatch>(
+ patchIds, &IModule::getAudioPatches,
+ "IDs of audio patches returned by IModule.getAudioPatches are not unique");
+ }
+
+ void GetAllPortIds(std::set<int32_t>* portIds) {
+ return GetAllEntityIds<AudioPort>(
+ portIds, &IModule::getAudioPorts,
+ "IDs of audio ports returned by IModule.getAudioPorts are not unique");
+ }
+
+ void GetAllPortConfigIds(std::set<int32_t>* portConfigIds) {
+ return GetAllEntityIds<AudioPortConfig>(
+ portConfigIds, &IModule::getAudioPortConfigs,
+ "IDs of audio port configs returned by IModule.getAudioPortConfigs are not unique");
+ }
+
+ void SetUpModuleConfig() {
+ if (moduleConfig == nullptr) {
+ moduleConfig = std::make_unique<ModuleConfig>(module.get());
+ ASSERT_EQ(EX_NONE, moduleConfig->getStatus().getExceptionCode())
+ << "ModuleConfig init error: " << moduleConfig->getError();
+ }
+ }
+
+ std::shared_ptr<IModule> module;
+ std::unique_ptr<ModuleConfig> moduleConfig;
+ AudioHalBinderServiceUtil binderUtil;
+ WithDebugFlags debug;
+};
+
+class AudioCoreModule : public AudioCoreModuleBase, public testing::TestWithParam<std::string> {
+ public:
+ void SetUp() override { ASSERT_NO_FATAL_FAILURE(SetUpImpl(GetParam())); }
+
+ void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownImpl()); }
+};
+
+class WithDevicePortConnectedState {
+ public:
+ explicit WithDevicePortConnectedState(const AudioPort& idAndData) : mIdAndData(idAndData) {}
+ WithDevicePortConnectedState(const AudioPort& id, const AudioDeviceAddress& address)
+ : mIdAndData(setAudioPortAddress(id, address)) {}
+ WithDevicePortConnectedState(const WithDevicePortConnectedState&) = delete;
+ WithDevicePortConnectedState& operator=(const WithDevicePortConnectedState&) = delete;
+ ~WithDevicePortConnectedState() {
+ if (mModule != nullptr) {
+ EXPECT_IS_OK(mModule->disconnectExternalDevice(getId()))
+ << "when disconnecting device port ID " << getId();
+ }
+ }
+ void SetUp(IModule* module) {
+ ASSERT_IS_OK(module->connectExternalDevice(mIdAndData, &mConnectedPort))
+ << "when connecting device port ID & data " << mIdAndData.toString();
+ ASSERT_NE(mIdAndData.id, getId())
+ << "ID of the connected port must not be the same as the ID of the template port";
+ mModule = module;
+ }
+ int32_t getId() const { return mConnectedPort.id; }
+ const AudioPort& get() { return mConnectedPort; }
+
+ private:
+ static AudioPort setAudioPortAddress(const AudioPort& id, const AudioDeviceAddress& address) {
+ AudioPort result = id;
+ result.ext.get<AudioPortExt::Tag::device>().device.address = address;
+ return result;
+ }
+
+ const AudioPort mIdAndData;
+ IModule* mModule = nullptr;
+ AudioPort mConnectedPort;
+};
+
+class StreamContext {
+ public:
+ typedef AidlMessageQueue<StreamDescriptor::Command, SynchronizedReadWrite> CommandMQ;
+ typedef AidlMessageQueue<StreamDescriptor::Reply, SynchronizedReadWrite> ReplyMQ;
+ typedef AidlMessageQueue<int8_t, SynchronizedReadWrite> DataMQ;
+
+ explicit StreamContext(const StreamDescriptor& descriptor)
+ : mFrameSizeBytes(descriptor.frameSizeBytes),
+ mCommandMQ(new CommandMQ(descriptor.command)),
+ mReplyMQ(new ReplyMQ(descriptor.reply)),
+ mBufferSizeFrames(descriptor.bufferSizeFrames),
+ mDataMQ(maybeCreateDataMQ(descriptor)) {}
+ void checkIsValid() const {
+ EXPECT_NE(0UL, mFrameSizeBytes);
+ ASSERT_NE(nullptr, mCommandMQ);
+ EXPECT_TRUE(mCommandMQ->isValid());
+ ASSERT_NE(nullptr, mReplyMQ);
+ EXPECT_TRUE(mReplyMQ->isValid());
+ if (mDataMQ != nullptr) {
+ EXPECT_TRUE(mDataMQ->isValid());
+ EXPECT_GE(mDataMQ->getQuantumCount() * mDataMQ->getQuantumSize(),
+ mFrameSizeBytes * mBufferSizeFrames)
+ << "Data MQ actual buffer size is "
+ "less than the buffer size as specified by the descriptor";
+ }
+ }
+ size_t getBufferSizeBytes() const { return mFrameSizeBytes * mBufferSizeFrames; }
+ size_t getBufferSizeFrames() const { return mBufferSizeFrames; }
+ CommandMQ* getCommandMQ() const { return mCommandMQ.get(); }
+ DataMQ* getDataMQ() const { return mDataMQ.get(); }
+ ReplyMQ* getReplyMQ() const { return mReplyMQ.get(); }
+
+ private:
+ static std::unique_ptr<DataMQ> maybeCreateDataMQ(const StreamDescriptor& descriptor) {
+ using Tag = StreamDescriptor::AudioBuffer::Tag;
+ if (descriptor.audio.getTag() == Tag::fmq) {
+ return std::make_unique<DataMQ>(descriptor.audio.get<Tag::fmq>());
+ }
+ return nullptr;
+ }
+
+ const size_t mFrameSizeBytes;
+ std::unique_ptr<CommandMQ> mCommandMQ;
+ std::unique_ptr<ReplyMQ> mReplyMQ;
+ const size_t mBufferSizeFrames;
+ std::unique_ptr<DataMQ> mDataMQ;
+};
+
+struct StreamEventReceiver {
+ virtual ~StreamEventReceiver() = default;
+ enum class Event { None, DrainReady, Error, TransferReady };
+ virtual std::tuple<int, Event> getLastEvent() const = 0;
+ virtual std::tuple<int, Event> waitForEvent(int clientEventSeq) = 0;
+ static constexpr int kEventSeqInit = -1;
+};
+std::string toString(StreamEventReceiver::Event event) {
+ switch (event) {
+ case StreamEventReceiver::Event::None:
+ return "None";
+ case StreamEventReceiver::Event::DrainReady:
+ return "DrainReady";
+ case StreamEventReceiver::Event::Error:
+ return "Error";
+ case StreamEventReceiver::Event::TransferReady:
+ return "TransferReady";
+ }
+ return std::to_string(static_cast<int32_t>(event));
+}
+
+// Transition to the next state happens either due to a command from the client,
+// or after an event received from the server.
+using TransitionTrigger = std::variant<StreamDescriptor::Command, StreamEventReceiver::Event>;
+using StateTransition = std::pair<TransitionTrigger, StreamDescriptor::State>;
+struct StateSequence {
+ virtual ~StateSequence() = default;
+ virtual void rewind() = 0;
+ virtual bool done() const = 0;
+ virtual TransitionTrigger getTrigger() = 0;
+ virtual std::set<StreamDescriptor::State> getExpectedStates() = 0;
+ virtual void advance(StreamDescriptor::State state) = 0;
+};
+
+static const StreamDescriptor::Command kGetStatusCommand =
+ StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::getStatus>(Void{});
+static const StreamDescriptor::Command kStartCommand =
+ StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::start>(Void{});
+static const StreamDescriptor::Command kBurstCommand =
+ StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::burst>(0);
+static const StreamDescriptor::Command kDrainInCommand =
+ StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::drain>(
+ StreamDescriptor::DrainMode::DRAIN_UNSPECIFIED);
+static const StreamDescriptor::Command kDrainOutAllCommand =
+ StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::drain>(
+ StreamDescriptor::DrainMode::DRAIN_ALL);
+static const StreamDescriptor::Command kDrainOutEarlyCommand =
+ StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::drain>(
+ StreamDescriptor::DrainMode::DRAIN_EARLY_NOTIFY);
+static const StreamDescriptor::Command kStandbyCommand =
+ StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::standby>(Void{});
+static const StreamDescriptor::Command kPauseCommand =
+ StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::pause>(Void{});
+static const StreamDescriptor::Command kFlushCommand =
+ StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::flush>(Void{});
+static const StreamEventReceiver::Event kTransferReadyEvent =
+ StreamEventReceiver::Event::TransferReady;
+static const StreamEventReceiver::Event kDrainReadyEvent = StreamEventReceiver::Event::DrainReady;
+
+// Handle possible bifurcations:
+// - on burst and on start: 'TRANSFERRING' -> {'ACTIVE', 'TRANSFERRING'}
+// - on pause: 'TRANSFER_PAUSED' -> {'PAUSED', 'TRANSFER_PAUSED'}
+// It is assumed that the 'steps' provided on the construction contain the sequence
+// for the async case, which gets corrected in the case when the HAL decided to do
+// a synchronous transfer.
+class SmartStateSequence : public StateSequence {
+ public:
+ explicit SmartStateSequence(const std::vector<StateTransition>& steps) : mSteps(steps) {}
+ explicit SmartStateSequence(std::vector<StateTransition>&& steps) : mSteps(std::move(steps)) {}
+ void rewind() override { mCurrentStep = 0; }
+ bool done() const override { return mCurrentStep >= mSteps.size(); }
+ TransitionTrigger getTrigger() override { return mSteps[mCurrentStep].first; }
+ std::set<StreamDescriptor::State> getExpectedStates() override {
+ std::set<StreamDescriptor::State> result = {getState()};
+ if (isBurstBifurcation() || isStartBifurcation()) {
+ result.insert(StreamDescriptor::State::ACTIVE);
+ } else if (isPauseBifurcation()) {
+ result.insert(StreamDescriptor::State::PAUSED);
+ }
+ return result;
+ }
+ void advance(StreamDescriptor::State state) override {
+ if (isBurstBifurcation() && state == StreamDescriptor::State::ACTIVE &&
+ mCurrentStep + 1 < mSteps.size() &&
+ mSteps[mCurrentStep + 1].first == TransitionTrigger{kTransferReadyEvent}) {
+ mCurrentStep++;
+ }
+ mCurrentStep++;
+ }
+
+ private:
+ StreamDescriptor::State getState() const { return mSteps[mCurrentStep].second; }
+ bool isBurstBifurcation() {
+ return getTrigger() == TransitionTrigger{kBurstCommand}&& getState() ==
+ StreamDescriptor::State::TRANSFERRING;
+ }
+ bool isPauseBifurcation() {
+ return getTrigger() == TransitionTrigger{kPauseCommand}&& getState() ==
+ StreamDescriptor::State::TRANSFER_PAUSED;
+ }
+ bool isStartBifurcation() {
+ return getTrigger() == TransitionTrigger{kStartCommand}&& getState() ==
+ StreamDescriptor::State::TRANSFERRING;
+ }
+ const std::vector<StateTransition> mSteps;
+ size_t mCurrentStep = 0;
+};
+
+std::string toString(const TransitionTrigger& trigger) {
+ if (std::holds_alternative<StreamDescriptor::Command>(trigger)) {
+ return std::string("'")
+ .append(toString(std::get<StreamDescriptor::Command>(trigger).getTag()))
+ .append("' command");
+ }
+ return std::string("'")
+ .append(toString(std::get<StreamEventReceiver::Event>(trigger)))
+ .append("' event");
+}
+
+struct StreamLogicDriver {
+ virtual ~StreamLogicDriver() = default;
+ // Return 'true' to stop the worker.
+ virtual bool done() = 0;
+ // For 'Writer' logic, if the 'actualSize' is 0, write is skipped.
+ // The 'fmqByteCount' from the returned command is passed as is to the HAL.
+ virtual TransitionTrigger getNextTrigger(int maxDataSize, int* actualSize = nullptr) = 0;
+ // Return 'true' to indicate that no further processing is needed,
+ // for example, the driver is expecting a bad status to be returned.
+ // The logic cycle will return with 'CONTINUE' status. Otherwise,
+ // the reply will be validated and then passed to 'processValidReply'.
+ virtual bool interceptRawReply(const StreamDescriptor::Reply& reply) = 0;
+ // Return 'false' to indicate that the contents of the reply are unexpected.
+ // Will abort the logic cycle.
+ virtual bool processValidReply(const StreamDescriptor::Reply& reply) = 0;
+};
+
+class StreamCommonLogic : public StreamLogic {
+ protected:
+ StreamCommonLogic(const StreamContext& context, StreamLogicDriver* driver,
+ StreamEventReceiver* eventReceiver)
+ : mCommandMQ(context.getCommandMQ()),
+ mReplyMQ(context.getReplyMQ()),
+ mDataMQ(context.getDataMQ()),
+ mData(context.getBufferSizeBytes()),
+ mDriver(driver),
+ mEventReceiver(eventReceiver) {}
+ StreamContext::CommandMQ* getCommandMQ() const { return mCommandMQ; }
+ StreamContext::ReplyMQ* getReplyMQ() const { return mReplyMQ; }
+ StreamContext::DataMQ* getDataMQ() const { return mDataMQ; }
+ StreamLogicDriver* getDriver() const { return mDriver; }
+ StreamEventReceiver* getEventReceiver() const { return mEventReceiver; }
+
+ std::string init() override {
+ LOG(DEBUG) << __func__;
+ return "";
+ }
+ std::optional<StreamDescriptor::Command> maybeGetNextCommand(int* actualSize = nullptr) {
+ TransitionTrigger trigger = mDriver->getNextTrigger(mData.size(), actualSize);
+ if (StreamEventReceiver::Event* expEvent =
+ std::get_if<StreamEventReceiver::Event>(&trigger);
+ expEvent != nullptr) {
+ auto [eventSeq, event] = mEventReceiver->waitForEvent(mLastEventSeq);
+ mLastEventSeq = eventSeq;
+ if (event != *expEvent) {
+ LOG(ERROR) << __func__ << ": expected event " << toString(*expEvent) << ", got "
+ << toString(event);
+ return {};
+ }
+ // If we were waiting for an event, the new stream state must be retrieved
+ // via 'getStatus'.
+ return StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::getStatus>(
+ Void{});
+ }
+ return std::get<StreamDescriptor::Command>(trigger);
+ }
+ bool readDataFromMQ(size_t readCount) {
+ std::vector<int8_t> data(readCount);
+ if (mDataMQ->read(data.data(), readCount)) {
+ memcpy(mData.data(), data.data(), std::min(mData.size(), data.size()));
+ return true;
+ }
+ LOG(ERROR) << __func__ << ": reading of " << readCount << " bytes from MQ failed";
+ return false;
+ }
+ bool writeDataToMQ() {
+ if (mDataMQ->write(mData.data(), mData.size())) {
+ return true;
+ }
+ LOG(ERROR) << __func__ << ": writing of " << mData.size() << " bytes to MQ failed";
+ return false;
+ }
+
+ private:
+ StreamContext::CommandMQ* mCommandMQ;
+ StreamContext::ReplyMQ* mReplyMQ;
+ StreamContext::DataMQ* mDataMQ;
+ std::vector<int8_t> mData;
+ StreamLogicDriver* const mDriver;
+ StreamEventReceiver* const mEventReceiver;
+ int mLastEventSeq = StreamEventReceiver::kEventSeqInit;
+};
+
+class StreamReaderLogic : public StreamCommonLogic {
+ public:
+ StreamReaderLogic(const StreamContext& context, StreamLogicDriver* driver,
+ StreamEventReceiver* eventReceiver)
+ : StreamCommonLogic(context, driver, eventReceiver) {}
+
+ protected:
+ Status cycle() override {
+ if (getDriver()->done()) {
+ LOG(DEBUG) << __func__ << ": clean exit";
+ return Status::EXIT;
+ }
+ StreamDescriptor::Command command;
+ if (auto maybeCommand = maybeGetNextCommand(); maybeCommand.has_value()) {
+ command = std::move(maybeCommand.value());
+ } else {
+ LOG(ERROR) << __func__ << ": no next command";
+ return Status::ABORT;
+ }
+ LOG(DEBUG) << "Writing command: " << command.toString();
+ if (!getCommandMQ()->writeBlocking(&command, 1)) {
+ LOG(ERROR) << __func__ << ": writing of command into MQ failed";
+ return Status::ABORT;
+ }
+ StreamDescriptor::Reply reply{};
+ LOG(DEBUG) << "Reading reply...";
+ if (!getReplyMQ()->readBlocking(&reply, 1)) {
+ return Status::ABORT;
+ }
+ LOG(DEBUG) << "Reply received: " << reply.toString();
+ if (getDriver()->interceptRawReply(reply)) {
+ LOG(DEBUG) << __func__ << ": reply has been intercepted by the driver";
+ return Status::CONTINUE;
+ }
+ if (reply.status != STATUS_OK) {
+ LOG(ERROR) << __func__ << ": received error status: " << statusToString(reply.status);
+ return Status::ABORT;
+ }
+ if (reply.fmqByteCount < 0 ||
+ (command.getTag() == StreamDescriptor::Command::Tag::burst &&
+ reply.fmqByteCount > command.get<StreamDescriptor::Command::Tag::burst>())) {
+ LOG(ERROR) << __func__
+ << ": received invalid byte count in the reply: " << reply.fmqByteCount;
+ return Status::ABORT;
+ }
+ if (static_cast<size_t>(reply.fmqByteCount) != getDataMQ()->availableToRead()) {
+ LOG(ERROR) << __func__
+ << ": the byte count in the reply is not the same as the amount of "
+ << "data available in the MQ: " << reply.fmqByteCount
+ << " != " << getDataMQ()->availableToRead();
+ }
+ if (reply.latencyMs < 0 && reply.latencyMs != StreamDescriptor::LATENCY_UNKNOWN) {
+ LOG(ERROR) << __func__ << ": received invalid latency value: " << reply.latencyMs;
+ return Status::ABORT;
+ }
+ if (reply.xrunFrames < 0) {
+ LOG(ERROR) << __func__ << ": received invalid xrunFrames value: " << reply.xrunFrames;
+ return Status::ABORT;
+ }
+ if (std::find(enum_range<StreamDescriptor::State>().begin(),
+ enum_range<StreamDescriptor::State>().end(),
+ reply.state) == enum_range<StreamDescriptor::State>().end()) {
+ LOG(ERROR) << __func__ << ": received invalid stream state: " << toString(reply.state);
+ return Status::ABORT;
+ }
+ const bool acceptedReply = getDriver()->processValidReply(reply);
+ if (const size_t readCount = getDataMQ()->availableToRead(); readCount > 0) {
+ if (readDataFromMQ(readCount)) {
+ goto checkAcceptedReply;
+ }
+ LOG(ERROR) << __func__ << ": reading of " << readCount << " data bytes from MQ failed";
+ return Status::ABORT;
+ } // readCount == 0
+ checkAcceptedReply:
+ if (acceptedReply) {
+ return Status::CONTINUE;
+ }
+ LOG(ERROR) << __func__ << ": unacceptable reply: " << reply.toString();
+ return Status::ABORT;
+ }
+};
+using StreamReader = StreamWorker<StreamReaderLogic>;
+
+class StreamWriterLogic : public StreamCommonLogic {
+ public:
+ StreamWriterLogic(const StreamContext& context, StreamLogicDriver* driver,
+ StreamEventReceiver* eventReceiver)
+ : StreamCommonLogic(context, driver, eventReceiver) {}
+
+ protected:
+ Status cycle() override {
+ if (getDriver()->done()) {
+ LOG(DEBUG) << __func__ << ": clean exit";
+ return Status::EXIT;
+ }
+ int actualSize = 0;
+ StreamDescriptor::Command command;
+ if (auto maybeCommand = maybeGetNextCommand(&actualSize); maybeCommand.has_value()) {
+ command = std::move(maybeCommand.value());
+ } else {
+ LOG(ERROR) << __func__ << ": no next command";
+ return Status::ABORT;
+ }
+ if (actualSize != 0 && !writeDataToMQ()) {
+ return Status::ABORT;
+ }
+ LOG(DEBUG) << "Writing command: " << command.toString();
+ if (!getCommandMQ()->writeBlocking(&command, 1)) {
+ LOG(ERROR) << __func__ << ": writing of command into MQ failed";
+ return Status::ABORT;
+ }
+ StreamDescriptor::Reply reply{};
+ LOG(DEBUG) << "Reading reply...";
+ if (!getReplyMQ()->readBlocking(&reply, 1)) {
+ LOG(ERROR) << __func__ << ": reading of reply from MQ failed";
+ return Status::ABORT;
+ }
+ LOG(DEBUG) << "Reply received: " << reply.toString();
+ if (getDriver()->interceptRawReply(reply)) {
+ return Status::CONTINUE;
+ }
+ if (reply.status != STATUS_OK) {
+ LOG(ERROR) << __func__ << ": received error status: " << statusToString(reply.status);
+ return Status::ABORT;
+ }
+ if (reply.fmqByteCount < 0 ||
+ (command.getTag() == StreamDescriptor::Command::Tag::burst &&
+ reply.fmqByteCount > command.get<StreamDescriptor::Command::Tag::burst>())) {
+ LOG(ERROR) << __func__
+ << ": received invalid byte count in the reply: " << reply.fmqByteCount;
+ return Status::ABORT;
+ }
+ if (getDataMQ()->availableToWrite() != getDataMQ()->getQuantumCount()) {
+ LOG(ERROR) << __func__ << ": the HAL module did not consume all data from the data MQ: "
+ << "available to write " << getDataMQ()->availableToWrite()
+ << ", total size: " << getDataMQ()->getQuantumCount();
+ return Status::ABORT;
+ }
+ if (reply.latencyMs < 0 && reply.latencyMs != StreamDescriptor::LATENCY_UNKNOWN) {
+ LOG(ERROR) << __func__ << ": received invalid latency value: " << reply.latencyMs;
+ return Status::ABORT;
+ }
+ if (reply.xrunFrames < 0) {
+ LOG(ERROR) << __func__ << ": received invalid xrunFrames value: " << reply.xrunFrames;
+ return Status::ABORT;
+ }
+ if (std::find(enum_range<StreamDescriptor::State>().begin(),
+ enum_range<StreamDescriptor::State>().end(),
+ reply.state) == enum_range<StreamDescriptor::State>().end()) {
+ LOG(ERROR) << __func__ << ": received invalid stream state: " << toString(reply.state);
+ return Status::ABORT;
+ }
+ if (getDriver()->processValidReply(reply)) {
+ return Status::CONTINUE;
+ }
+ LOG(ERROR) << __func__ << ": unacceptable reply: " << reply.toString();
+ return Status::ABORT;
+ }
+};
+using StreamWriter = StreamWorker<StreamWriterLogic>;
+
+class DefaultStreamCallback : public ::aidl::android::hardware::audio::core::BnStreamCallback,
+ public StreamEventReceiver {
+ ndk::ScopedAStatus onTransferReady() override {
+ LOG(DEBUG) << __func__;
+ putLastEvent(Event::TransferReady);
+ return ndk::ScopedAStatus::ok();
+ }
+ ndk::ScopedAStatus onError() override {
+ LOG(DEBUG) << __func__;
+ putLastEvent(Event::Error);
+ return ndk::ScopedAStatus::ok();
+ }
+ ndk::ScopedAStatus onDrainReady() override {
+ LOG(DEBUG) << __func__;
+ putLastEvent(Event::DrainReady);
+ return ndk::ScopedAStatus::ok();
+ }
+
+ public:
+ // To avoid timing out the whole test suite in case no event is received
+ // from the HAL, use a local timeout for event waiting.
+ static constexpr auto kEventTimeoutMs = std::chrono::milliseconds(1000);
+
+ StreamEventReceiver* getEventReceiver() { return this; }
+ std::tuple<int, Event> getLastEvent() const override {
+ std::lock_guard l(mLock);
+ return getLastEvent_l();
+ }
+ std::tuple<int, Event> waitForEvent(int clientEventSeq) override {
+ std::unique_lock l(mLock);
+ android::base::ScopedLockAssertion lock_assertion(mLock);
+ LOG(DEBUG) << __func__ << ": client " << clientEventSeq << ", last " << mLastEventSeq;
+ if (mCv.wait_for(l, kEventTimeoutMs, [&]() {
+ android::base::ScopedLockAssertion lock_assertion(mLock);
+ return clientEventSeq < mLastEventSeq;
+ })) {
+ } else {
+ LOG(WARNING) << __func__ << ": timed out waiting for an event";
+ putLastEvent_l(Event::None);
+ }
+ return getLastEvent_l();
+ }
+
+ private:
+ std::tuple<int, Event> getLastEvent_l() const REQUIRES(mLock) {
+ return std::make_tuple(mLastEventSeq, mLastEvent);
+ }
+ void putLastEvent(Event event) {
+ {
+ std::lock_guard l(mLock);
+ putLastEvent_l(event);
+ }
+ mCv.notify_one();
+ }
+ void putLastEvent_l(Event event) REQUIRES(mLock) {
+ mLastEventSeq++;
+ mLastEvent = event;
+ }
+
+ mutable std::mutex mLock;
+ std::condition_variable mCv;
+ int mLastEventSeq GUARDED_BY(mLock) = kEventSeqInit;
+ Event mLastEvent GUARDED_BY(mLock) = Event::None;
+};
+
+template <typename T>
+struct IOTraits {
+ static constexpr bool is_input = std::is_same_v<T, IStreamIn>;
+ using Worker = std::conditional_t<is_input, StreamReader, StreamWriter>;
+};
+
+template <typename Stream>
+class WithStream {
+ public:
+ WithStream() {}
+ explicit WithStream(const AudioPortConfig& portConfig) : mPortConfig(portConfig) {}
+ WithStream(const WithStream&) = delete;
+ WithStream& operator=(const WithStream&) = delete;
+ ~WithStream() {
+ if (mStream != nullptr) {
+ mContext.reset();
+ EXPECT_IS_OK(mStream->close()) << "port config id " << getPortId();
+ }
+ }
+ void SetUpPortConfig(IModule* module) { ASSERT_NO_FATAL_FAILURE(mPortConfig.SetUp(module)); }
+ ScopedAStatus SetUpNoChecks(IModule* module, long bufferSizeFrames) {
+ return SetUpNoChecks(module, mPortConfig.get(), bufferSizeFrames);
+ }
+ ScopedAStatus SetUpNoChecks(IModule* module, const AudioPortConfig& portConfig,
+ long bufferSizeFrames);
+ void SetUp(IModule* module, long bufferSizeFrames) {
+ ASSERT_NO_FATAL_FAILURE(SetUpPortConfig(module));
+ ASSERT_IS_OK(SetUpNoChecks(module, bufferSizeFrames)) << "port config id " << getPortId();
+ ASSERT_NE(nullptr, mStream) << "port config id " << getPortId();
+ EXPECT_GE(mDescriptor.bufferSizeFrames, bufferSizeFrames)
+ << "actual buffer size must be no less than requested";
+ mContext.emplace(mDescriptor);
+ ASSERT_NO_FATAL_FAILURE(mContext.value().checkIsValid());
+ }
+ Stream* get() const { return mStream.get(); }
+ const StreamContext* getContext() const { return mContext ? &(mContext.value()) : nullptr; }
+ StreamEventReceiver* getEventReceiver() { return mStreamCallback->getEventReceiver(); }
+ std::shared_ptr<Stream> getSharedPointer() const { return mStream; }
+ const AudioPortConfig& getPortConfig() const { return mPortConfig.get(); }
+ int32_t getPortId() const { return mPortConfig.getId(); }
+
+ private:
+ WithAudioPortConfig mPortConfig;
+ std::shared_ptr<Stream> mStream;
+ StreamDescriptor mDescriptor;
+ std::optional<StreamContext> mContext;
+ std::shared_ptr<DefaultStreamCallback> mStreamCallback;
+};
+
+SinkMetadata GenerateSinkMetadata(const AudioPortConfig& portConfig) {
+ RecordTrackMetadata trackMeta;
+ trackMeta.source = AudioSource::MIC;
+ trackMeta.gain = 1.0;
+ trackMeta.channelMask = portConfig.channelMask.value();
+ SinkMetadata metadata;
+ metadata.tracks.push_back(trackMeta);
+ return metadata;
+}
+
+template <>
+ScopedAStatus WithStream<IStreamIn>::SetUpNoChecks(IModule* module,
+ const AudioPortConfig& portConfig,
+ long bufferSizeFrames) {
+ aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments args;
+ args.portConfigId = portConfig.id;
+ args.sinkMetadata = GenerateSinkMetadata(portConfig);
+ args.bufferSizeFrames = bufferSizeFrames;
+ auto callback = ndk::SharedRefBase::make<DefaultStreamCallback>();
+ // TODO: Uncomment when support for asynchronous input is implemented.
+ // args.callback = callback;
+ aidl::android::hardware::audio::core::IModule::OpenInputStreamReturn ret;
+ ScopedAStatus status = module->openInputStream(args, &ret);
+ if (status.isOk()) {
+ mStream = std::move(ret.stream);
+ mDescriptor = std::move(ret.desc);
+ mStreamCallback = std::move(callback);
+ }
+ return status;
+}
+
+SourceMetadata GenerateSourceMetadata(const AudioPortConfig& portConfig) {
+ PlaybackTrackMetadata trackMeta;
+ trackMeta.usage = AudioUsage::MEDIA;
+ trackMeta.contentType = AudioContentType::MUSIC;
+ trackMeta.gain = 1.0;
+ trackMeta.channelMask = portConfig.channelMask.value();
+ SourceMetadata metadata;
+ metadata.tracks.push_back(trackMeta);
+ return metadata;
+}
+
+template <>
+ScopedAStatus WithStream<IStreamOut>::SetUpNoChecks(IModule* module,
+ const AudioPortConfig& portConfig,
+ long bufferSizeFrames) {
+ aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
+ args.portConfigId = portConfig.id;
+ args.sourceMetadata = GenerateSourceMetadata(portConfig);
+ args.offloadInfo = ModuleConfig::generateOffloadInfoIfNeeded(portConfig);
+ args.bufferSizeFrames = bufferSizeFrames;
+ auto callback = ndk::SharedRefBase::make<DefaultStreamCallback>();
+ args.callback = callback;
+ aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
+ ScopedAStatus status = module->openOutputStream(args, &ret);
+ if (status.isOk()) {
+ mStream = std::move(ret.stream);
+ mDescriptor = std::move(ret.desc);
+ mStreamCallback = std::move(callback);
+ }
+ return status;
+}
+
+class WithAudioPatch {
+ public:
+ WithAudioPatch() {}
+ WithAudioPatch(const AudioPortConfig& srcPortConfig, const AudioPortConfig& sinkPortConfig)
+ : mSrcPortConfig(srcPortConfig), mSinkPortConfig(sinkPortConfig) {}
+ WithAudioPatch(bool sinkIsCfg1, const AudioPortConfig& portConfig1,
+ const AudioPortConfig& portConfig2)
+ : mSrcPortConfig(sinkIsCfg1 ? portConfig2 : portConfig1),
+ mSinkPortConfig(sinkIsCfg1 ? portConfig1 : portConfig2) {}
+ WithAudioPatch(const WithAudioPatch&) = delete;
+ WithAudioPatch& operator=(const WithAudioPatch&) = delete;
+ ~WithAudioPatch() {
+ if (mModule != nullptr && mPatch.id != 0) {
+ EXPECT_IS_OK(mModule->resetAudioPatch(mPatch.id)) << "patch id " << getId();
+ }
+ }
+ void SetUpPortConfigs(IModule* module) {
+ ASSERT_NO_FATAL_FAILURE(mSrcPortConfig.SetUp(module));
+ ASSERT_NO_FATAL_FAILURE(mSinkPortConfig.SetUp(module));
+ }
+ ScopedAStatus SetUpNoChecks(IModule* module) {
+ mModule = module;
+ mPatch.sourcePortConfigIds = std::vector<int32_t>{mSrcPortConfig.getId()};
+ mPatch.sinkPortConfigIds = std::vector<int32_t>{mSinkPortConfig.getId()};
+ return mModule->setAudioPatch(mPatch, &mPatch);
+ }
+ void SetUp(IModule* module) {
+ ASSERT_NO_FATAL_FAILURE(SetUpPortConfigs(module));
+ ASSERT_IS_OK(SetUpNoChecks(module)) << "source port config id " << mSrcPortConfig.getId()
+ << "; sink port config id " << mSinkPortConfig.getId();
+ EXPECT_GT(mPatch.minimumStreamBufferSizeFrames, 0) << "patch id " << getId();
+ for (auto latencyMs : mPatch.latenciesMs) {
+ EXPECT_GT(latencyMs, 0) << "patch id " << getId();
+ }
+ }
+ int32_t getId() const { return mPatch.id; }
+ const AudioPatch& get() const { return mPatch; }
+ const AudioPortConfig& getSinkPortConfig() const { return mSinkPortConfig.get(); }
+ const AudioPortConfig& getSrcPortConfig() const { return mSrcPortConfig.get(); }
+ const AudioPortConfig& getPortConfig(bool getSink) const {
+ return getSink ? getSinkPortConfig() : getSrcPortConfig();
+ }
+
+ private:
+ WithAudioPortConfig mSrcPortConfig;
+ WithAudioPortConfig mSinkPortConfig;
+ IModule* mModule = nullptr;
+ AudioPatch mPatch;
+};
+
+TEST_P(AudioCoreModule, Published) {
+ // SetUp must complete with no failures.
+}
+
+TEST_P(AudioCoreModule, CanBeRestarted) {
+ ASSERT_NO_FATAL_FAILURE(RestartService());
+}
+
+TEST_P(AudioCoreModule, PortIdsAreUnique) {
+ std::set<int32_t> portIds;
+ ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
+}
+
+TEST_P(AudioCoreModule, GetAudioPortsIsStable) {
+ std::vector<AudioPort> ports1;
+ ASSERT_IS_OK(module->getAudioPorts(&ports1));
+ std::vector<AudioPort> ports2;
+ ASSERT_IS_OK(module->getAudioPorts(&ports2));
+ ASSERT_EQ(ports1.size(), ports2.size())
+ << "Sizes of audio port arrays do not match across consequent calls to getAudioPorts";
+ std::sort(ports1.begin(), ports1.end());
+ std::sort(ports2.begin(), ports2.end());
+ EXPECT_EQ(ports1, ports2);
+}
+
+TEST_P(AudioCoreModule, GetAudioRoutesIsStable) {
+ std::vector<AudioRoute> routes1;
+ ASSERT_IS_OK(module->getAudioRoutes(&routes1));
+ std::vector<AudioRoute> routes2;
+ ASSERT_IS_OK(module->getAudioRoutes(&routes2));
+ ASSERT_EQ(routes1.size(), routes2.size())
+ << "Sizes of audio route arrays do not match across consequent calls to getAudioRoutes";
+ std::sort(routes1.begin(), routes1.end());
+ std::sort(routes2.begin(), routes2.end());
+ EXPECT_EQ(routes1, routes2);
+}
+
+TEST_P(AudioCoreModule, GetAudioRoutesAreValid) {
+ std::vector<AudioRoute> routes;
+ ASSERT_IS_OK(module->getAudioRoutes(&routes));
+ for (const auto& route : routes) {
+ std::set<int32_t> sources(route.sourcePortIds.begin(), route.sourcePortIds.end());
+ EXPECT_NE(0UL, sources.size())
+ << "empty audio port sinks in the audio route: " << route.toString();
+ EXPECT_EQ(sources.size(), route.sourcePortIds.size())
+ << "IDs of audio port sinks are not unique in the audio route: "
+ << route.toString();
+ }
+}
+
+TEST_P(AudioCoreModule, GetAudioRoutesPortIdsAreValid) {
+ std::set<int32_t> portIds;
+ ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
+ std::vector<AudioRoute> routes;
+ ASSERT_IS_OK(module->getAudioRoutes(&routes));
+ for (const auto& route : routes) {
+ EXPECT_EQ(1UL, portIds.count(route.sinkPortId))
+ << route.sinkPortId << " sink port id is unknown";
+ for (const auto& source : route.sourcePortIds) {
+ EXPECT_EQ(1UL, portIds.count(source)) << source << " source port id is unknown";
+ }
+ }
+}
+
+TEST_P(AudioCoreModule, GetAudioRoutesForAudioPort) {
+ std::set<int32_t> portIds;
+ ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
+ if (portIds.empty()) {
+ GTEST_SKIP() << "No ports in the module.";
+ }
+ for (const auto portId : portIds) {
+ std::vector<AudioRoute> routes;
+ EXPECT_IS_OK(module->getAudioRoutesForAudioPort(portId, &routes));
+ for (const auto& r : routes) {
+ if (r.sinkPortId != portId) {
+ const auto& srcs = r.sourcePortIds;
+ EXPECT_TRUE(std::find(srcs.begin(), srcs.end(), portId) != srcs.end())
+ << " port ID " << portId << " does not used by the route " << r.toString();
+ }
+ }
+ }
+ for (const auto portId : GetNonExistentIds(portIds)) {
+ std::vector<AudioRoute> routes;
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->getAudioRoutesForAudioPort(portId, &routes))
+ << "port ID " << portId;
+ }
+}
+
+TEST_P(AudioCoreModule, CheckDevicePorts) {
+ std::vector<AudioPort> ports;
+ ASSERT_IS_OK(module->getAudioPorts(&ports));
+ std::optional<int32_t> defaultOutput, defaultInput;
+ std::set<AudioDevice> inputs, outputs;
+ const int defaultDeviceFlag = 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE;
+ for (const auto& port : ports) {
+ if (port.ext.getTag() != AudioPortExt::Tag::device) continue;
+ const auto& devicePort = port.ext.get<AudioPortExt::Tag::device>();
+ EXPECT_NE(AudioDeviceType::NONE, devicePort.device.type.type);
+ EXPECT_NE(AudioDeviceType::IN_DEFAULT, devicePort.device.type.type);
+ EXPECT_NE(AudioDeviceType::OUT_DEFAULT, devicePort.device.type.type);
+ if (devicePort.device.type.type > AudioDeviceType::IN_DEFAULT &&
+ devicePort.device.type.type < AudioDeviceType::OUT_DEFAULT) {
+ EXPECT_EQ(AudioIoFlags::Tag::input, port.flags.getTag());
+ } else if (devicePort.device.type.type > AudioDeviceType::OUT_DEFAULT) {
+ EXPECT_EQ(AudioIoFlags::Tag::output, port.flags.getTag());
+ }
+ EXPECT_FALSE((devicePort.flags & defaultDeviceFlag) != 0 &&
+ !devicePort.device.type.connection.empty())
+ << "Device port " << port.id
+ << " must be permanently attached to be set as default";
+ if ((devicePort.flags & defaultDeviceFlag) != 0) {
+ if (port.flags.getTag() == AudioIoFlags::Tag::output) {
+ EXPECT_FALSE(defaultOutput.has_value())
+ << "At least two output device ports are declared as default: "
+ << defaultOutput.value() << " and " << port.id;
+ defaultOutput = port.id;
+ EXPECT_EQ(0UL, outputs.count(devicePort.device))
+ << "Non-unique output device: " << devicePort.device.toString();
+ outputs.insert(devicePort.device);
+ } else if (port.flags.getTag() == AudioIoFlags::Tag::input) {
+ EXPECT_FALSE(defaultInput.has_value())
+ << "At least two input device ports are declared as default: "
+ << defaultInput.value() << " and " << port.id;
+ defaultInput = port.id;
+ EXPECT_EQ(0UL, inputs.count(devicePort.device))
+ << "Non-unique input device: " << devicePort.device.toString();
+ inputs.insert(devicePort.device);
+ } else {
+ FAIL() << "Invalid AudioIoFlags Tag: " << toString(port.flags.getTag());
+ }
+ }
+ }
+}
+
+TEST_P(AudioCoreModule, CheckMixPorts) {
+ std::vector<AudioPort> ports;
+ ASSERT_IS_OK(module->getAudioPorts(&ports));
+ std::optional<int32_t> primaryMixPort;
+ for (const auto& port : ports) {
+ if (port.ext.getTag() != AudioPortExt::Tag::mix) continue;
+ const auto& mixPort = port.ext.get<AudioPortExt::Tag::mix>();
+ if (port.flags.getTag() == AudioIoFlags::Tag::output &&
+ isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::output>(),
+ AudioOutputFlags::PRIMARY)) {
+ EXPECT_FALSE(primaryMixPort.has_value())
+ << "At least two mix ports have PRIMARY flag set: " << primaryMixPort.value()
+ << " and " << port.id;
+ primaryMixPort = port.id;
+ EXPECT_EQ(1, mixPort.maxOpenStreamCount)
+ << "Primary mix port " << port.id << " can not have maxOpenStreamCount "
+ << mixPort.maxOpenStreamCount;
+ }
+ }
+}
+
+TEST_P(AudioCoreModule, GetAudioPort) {
+ std::set<int32_t> portIds;
+ ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
+ if (portIds.empty()) {
+ GTEST_SKIP() << "No ports in the module.";
+ }
+ for (const auto portId : portIds) {
+ AudioPort port;
+ EXPECT_IS_OK(module->getAudioPort(portId, &port));
+ EXPECT_EQ(portId, port.id);
+ }
+ for (const auto portId : GetNonExistentIds(portIds)) {
+ AudioPort port;
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->getAudioPort(portId, &port))
+ << "port ID " << portId;
+ }
+}
+
+TEST_P(AudioCoreModule, SetUpModuleConfig) {
+ ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+ // Send the module config to logcat to facilitate failures investigation.
+ LOG(INFO) << "SetUpModuleConfig: " << moduleConfig->toString();
+}
+
+// Verify that HAL module reports for a connected device port at least one non-dynamic profile,
+// that is, a profile with actual supported configuration.
+// Note: This test relies on simulation of external device connections by the HAL module.
+TEST_P(AudioCoreModule, GetAudioPortWithExternalDevices) {
+ ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+ std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
+ if (ports.empty()) {
+ GTEST_SKIP() << "No external devices in the module.";
+ }
+ for (const auto& port : ports) {
+ AudioPort portWithData = port;
+ portWithData.ext.get<AudioPortExt::Tag::device>().device.address =
+ GenerateUniqueDeviceAddress();
+ WithDevicePortConnectedState portConnected(portWithData);
+ ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
+ const int32_t connectedPortId = portConnected.getId();
+ ASSERT_NE(portWithData.id, connectedPortId);
+ ASSERT_EQ(portWithData.ext.getTag(), portConnected.get().ext.getTag());
+ EXPECT_EQ(portWithData.ext.get<AudioPortExt::Tag::device>().device,
+ portConnected.get().ext.get<AudioPortExt::Tag::device>().device);
+ // Verify that 'getAudioPort' and 'getAudioPorts' return the same connected port.
+ AudioPort connectedPort;
+ EXPECT_IS_OK(module->getAudioPort(connectedPortId, &connectedPort))
+ << "port ID " << connectedPortId;
+ EXPECT_EQ(portConnected.get(), connectedPort);
+ const auto& portProfiles = connectedPort.profiles;
+ EXPECT_NE(0UL, portProfiles.size())
+ << "Connected port has no profiles: " << connectedPort.toString();
+ const auto dynamicProfileIt =
+ std::find_if(portProfiles.begin(), portProfiles.end(), [](const auto& profile) {
+ return profile.format.type == AudioFormatType::DEFAULT;
+ });
+ EXPECT_EQ(portProfiles.end(), dynamicProfileIt) << "Connected port contains dynamic "
+ << "profiles: " << connectedPort.toString();
+
+ std::vector<AudioPort> allPorts;
+ ASSERT_IS_OK(module->getAudioPorts(&allPorts));
+ const auto allPortsIt = findById(allPorts, connectedPortId);
+ EXPECT_NE(allPorts.end(), allPortsIt);
+ if (allPortsIt != allPorts.end()) {
+ EXPECT_EQ(portConnected.get(), *allPortsIt);
+ }
+ }
+}
+
+TEST_P(AudioCoreModule, OpenStreamInvalidPortConfigId) {
+ std::set<int32_t> portConfigIds;
+ ASSERT_NO_FATAL_FAILURE(GetAllPortConfigIds(&portConfigIds));
+ for (const auto portConfigId : GetNonExistentIds(portConfigIds)) {
+ {
+ aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments args;
+ args.portConfigId = portConfigId;
+ args.bufferSizeFrames = kDefaultBufferSizeFrames;
+ aidl::android::hardware::audio::core::IModule::OpenInputStreamReturn ret;
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->openInputStream(args, &ret))
+ << "port config ID " << portConfigId;
+ EXPECT_EQ(nullptr, ret.stream);
+ }
+ {
+ aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
+ args.portConfigId = portConfigId;
+ args.bufferSizeFrames = kDefaultBufferSizeFrames;
+ aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->openOutputStream(args, &ret))
+ << "port config ID " << portConfigId;
+ EXPECT_EQ(nullptr, ret.stream);
+ }
+ }
+}
+
+TEST_P(AudioCoreModule, PortConfigIdsAreUnique) {
+ std::set<int32_t> portConfigIds;
+ ASSERT_NO_FATAL_FAILURE(GetAllPortConfigIds(&portConfigIds));
+}
+
+TEST_P(AudioCoreModule, PortConfigPortIdsAreValid) {
+ std::set<int32_t> portIds;
+ ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
+ std::vector<AudioPortConfig> portConfigs;
+ ASSERT_IS_OK(module->getAudioPortConfigs(&portConfigs));
+ for (const auto& config : portConfigs) {
+ EXPECT_EQ(1UL, portIds.count(config.portId))
+ << config.portId << " port id is unknown, config id " << config.id;
+ }
+}
+
+TEST_P(AudioCoreModule, ResetAudioPortConfigInvalidId) {
+ std::set<int32_t> portConfigIds;
+ ASSERT_NO_FATAL_FAILURE(GetAllPortConfigIds(&portConfigIds));
+ for (const auto portConfigId : GetNonExistentIds(portConfigIds)) {
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->resetAudioPortConfig(portConfigId))
+ << "port config ID " << portConfigId;
+ }
+}
+
+// Verify that for the audio port configs provided by the HAL after init, resetting
+// the config does not delete it, but brings it back to the initial config.
+TEST_P(AudioCoreModule, ResetAudioPortConfigToInitialValue) {
+ std::vector<AudioPortConfig> portConfigsBefore;
+ ASSERT_IS_OK(module->getAudioPortConfigs(&portConfigsBefore));
+ // TODO: Change port configs according to port profiles.
+ for (const auto& c : portConfigsBefore) {
+ EXPECT_IS_OK(module->resetAudioPortConfig(c.id)) << "port config ID " << c.id;
+ }
+ std::vector<AudioPortConfig> portConfigsAfter;
+ ASSERT_IS_OK(module->getAudioPortConfigs(&portConfigsAfter));
+ for (const auto& c : portConfigsBefore) {
+ auto afterIt = findById<AudioPortConfig>(portConfigsAfter, c.id);
+ EXPECT_NE(portConfigsAfter.end(), afterIt)
+ << " port config ID " << c.id << " was removed by reset";
+ if (afterIt != portConfigsAfter.end()) {
+ EXPECT_EQ(c, *afterIt);
+ }
+ }
+}
+
+TEST_P(AudioCoreModule, SetAudioPortConfigSuggestedConfig) {
+ ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+ auto srcMixPort = moduleConfig->getSourceMixPortForAttachedDevice();
+ if (!srcMixPort.has_value()) {
+ GTEST_SKIP() << "No mix port for attached output devices";
+ }
+ AudioPortConfig portConfig;
+ AudioPortConfig suggestedConfig;
+ portConfig.portId = srcMixPort.value().id;
+ {
+ bool applied = true;
+ ASSERT_IS_OK(module->setAudioPortConfig(portConfig, &suggestedConfig, &applied))
+ << "Config: " << portConfig.toString();
+ EXPECT_FALSE(applied);
+ }
+ EXPECT_EQ(0, suggestedConfig.id);
+ EXPECT_TRUE(suggestedConfig.sampleRate.has_value());
+ EXPECT_TRUE(suggestedConfig.channelMask.has_value());
+ EXPECT_TRUE(suggestedConfig.format.has_value());
+ EXPECT_TRUE(suggestedConfig.flags.has_value());
+ WithAudioPortConfig applied(suggestedConfig);
+ ASSERT_NO_FATAL_FAILURE(applied.SetUp(module.get()));
+ const AudioPortConfig& appliedConfig = applied.get();
+ EXPECT_NE(0, appliedConfig.id);
+ EXPECT_TRUE(appliedConfig.sampleRate.has_value());
+ EXPECT_EQ(suggestedConfig.sampleRate.value(), appliedConfig.sampleRate.value());
+ EXPECT_TRUE(appliedConfig.channelMask.has_value());
+ EXPECT_EQ(suggestedConfig.channelMask.value(), appliedConfig.channelMask.value());
+ EXPECT_TRUE(appliedConfig.format.has_value());
+ EXPECT_EQ(suggestedConfig.format.value(), appliedConfig.format.value());
+ EXPECT_TRUE(appliedConfig.flags.has_value());
+ EXPECT_EQ(suggestedConfig.flags.value(), appliedConfig.flags.value());
+}
+
+TEST_P(AudioCoreModule, SetAllAttachedDevicePortConfigs) {
+ ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+ ASSERT_NO_FATAL_FAILURE(ApplyEveryConfig(moduleConfig->getPortConfigsForAttachedDevicePorts()));
+}
+
+// Note: This test relies on simulation of external device connections by the HAL module.
+TEST_P(AudioCoreModule, SetAllExternalDevicePortConfigs) {
+ ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+ std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
+ if (ports.empty()) {
+ GTEST_SKIP() << "No external devices in the module.";
+ }
+ for (const auto& port : ports) {
+ WithDevicePortConnectedState portConnected(port, GenerateUniqueDeviceAddress());
+ ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
+ ASSERT_NO_FATAL_FAILURE(
+ ApplyEveryConfig(moduleConfig->getPortConfigsForDevicePort(portConnected.get())));
+ }
+}
+
+TEST_P(AudioCoreModule, SetAllStaticAudioPortConfigs) {
+ ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+ ASSERT_NO_FATAL_FAILURE(ApplyEveryConfig(moduleConfig->getPortConfigsForMixPorts()));
+}
+
+TEST_P(AudioCoreModule, SetAudioPortConfigInvalidPortId) {
+ std::set<int32_t> portIds;
+ ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
+ for (const auto portId : GetNonExistentIds(portIds)) {
+ AudioPortConfig portConfig, suggestedConfig;
+ bool applied;
+ portConfig.portId = portId;
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
+ module->setAudioPortConfig(portConfig, &suggestedConfig, &applied))
+ << "port ID " << portId;
+ EXPECT_FALSE(suggestedConfig.format.has_value());
+ EXPECT_FALSE(suggestedConfig.channelMask.has_value());
+ EXPECT_FALSE(suggestedConfig.sampleRate.has_value());
+ }
+}
+
+TEST_P(AudioCoreModule, SetAudioPortConfigInvalidPortConfigId) {
+ std::set<int32_t> portConfigIds;
+ ASSERT_NO_FATAL_FAILURE(GetAllPortConfigIds(&portConfigIds));
+ for (const auto portConfigId : GetNonExistentIds(portConfigIds)) {
+ AudioPortConfig portConfig, suggestedConfig;
+ bool applied;
+ portConfig.id = portConfigId;
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
+ module->setAudioPortConfig(portConfig, &suggestedConfig, &applied))
+ << "port config ID " << portConfigId;
+ EXPECT_FALSE(suggestedConfig.format.has_value());
+ EXPECT_FALSE(suggestedConfig.channelMask.has_value());
+ EXPECT_FALSE(suggestedConfig.sampleRate.has_value());
+ }
+}
+
+TEST_P(AudioCoreModule, TryConnectMissingDevice) {
+ ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+ std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
+ if (ports.empty()) {
+ GTEST_SKIP() << "No external devices in the module.";
+ }
+ AudioPort ignored;
+ WithDebugFlags doNotSimulateConnections = WithDebugFlags::createNested(debug);
+ doNotSimulateConnections.flags().simulateDeviceConnections = false;
+ ASSERT_NO_FATAL_FAILURE(doNotSimulateConnections.SetUp(module.get()));
+ for (const auto& port : ports) {
+ AudioPort portWithData = port;
+ portWithData.ext.get<AudioPortExt::Tag::device>().device.address =
+ GenerateUniqueDeviceAddress();
+ EXPECT_STATUS(EX_ILLEGAL_STATE, module->connectExternalDevice(portWithData, &ignored))
+ << "static port " << portWithData.toString();
+ }
+}
+
+TEST_P(AudioCoreModule, TryChangingConnectionSimulationMidway) {
+ ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+ std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
+ if (ports.empty()) {
+ GTEST_SKIP() << "No external devices in the module.";
+ }
+ WithDevicePortConnectedState portConnected(*ports.begin(), GenerateUniqueDeviceAddress());
+ ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
+ ModuleDebug midwayDebugChange = debug.flags();
+ midwayDebugChange.simulateDeviceConnections = false;
+ EXPECT_STATUS(EX_ILLEGAL_STATE, module->setModuleDebug(midwayDebugChange))
+ << "when trying to disable connections simulation while having a connected device";
+}
+
+TEST_P(AudioCoreModule, ConnectDisconnectExternalDeviceInvalidPorts) {
+ AudioPort ignored;
+ std::set<int32_t> portIds;
+ ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
+ for (const auto portId : GetNonExistentIds(portIds)) {
+ AudioPort invalidPort;
+ invalidPort.id = portId;
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->connectExternalDevice(invalidPort, &ignored))
+ << "port ID " << portId << ", when setting CONNECTED state";
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->disconnectExternalDevice(portId))
+ << "port ID " << portId << ", when setting DISCONNECTED state";
+ }
+
+ std::vector<AudioPort> ports;
+ ASSERT_IS_OK(module->getAudioPorts(&ports));
+ for (const auto& port : ports) {
+ if (port.ext.getTag() != AudioPortExt::Tag::device) {
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->connectExternalDevice(port, &ignored))
+ << "non-device port ID " << port.id << " when setting CONNECTED state";
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->disconnectExternalDevice(port.id))
+ << "non-device port ID " << port.id << " when setting DISCONNECTED state";
+ } else {
+ const auto& devicePort = port.ext.get<AudioPortExt::Tag::device>();
+ if (devicePort.device.type.connection.empty()) {
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->connectExternalDevice(port, &ignored))
+ << "for a permanently attached device port ID " << port.id
+ << " when setting CONNECTED state";
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->disconnectExternalDevice(port.id))
+ << "for a permanently attached device port ID " << port.id
+ << " when setting DISCONNECTED state";
+ }
+ }
+ }
+}
+
+// Note: This test relies on simulation of external device connections by the HAL module.
+TEST_P(AudioCoreModule, ConnectDisconnectExternalDeviceTwice) {
+ ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+ AudioPort ignored;
+ std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
+ if (ports.empty()) {
+ GTEST_SKIP() << "No external devices in the module.";
+ }
+ for (const auto& port : ports) {
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->disconnectExternalDevice(port.id))
+ << "when disconnecting already disconnected device port ID " << port.id;
+ AudioPort portWithData = port;
+ portWithData.ext.get<AudioPortExt::Tag::device>().device.address =
+ GenerateUniqueDeviceAddress();
+ WithDevicePortConnectedState portConnected(portWithData);
+ ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
+ module->connectExternalDevice(portConnected.get(), &ignored))
+ << "when trying to connect a connected device port "
+ << portConnected.get().toString();
+ EXPECT_STATUS(EX_ILLEGAL_STATE, module->connectExternalDevice(portWithData, &ignored))
+ << "when connecting again the external device "
+ << portWithData.ext.get<AudioPortExt::Tag::device>().device.toString()
+ << "; Returned connected port " << ignored.toString() << " for template "
+ << portWithData.toString();
+ }
+}
+
+// Note: This test relies on simulation of external device connections by the HAL module.
+TEST_P(AudioCoreModule, DisconnectExternalDeviceNonResetPortConfig) {
+ ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+ std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
+ if (ports.empty()) {
+ GTEST_SKIP() << "No external devices in the module.";
+ }
+ for (const auto& port : ports) {
+ WithDevicePortConnectedState portConnected(port, GenerateUniqueDeviceAddress());
+ ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
+ const auto portConfig = moduleConfig->getSingleConfigForDevicePort(portConnected.get());
+ {
+ WithAudioPortConfig config(portConfig);
+ // Note: if SetUp fails, check the status of 'GetAudioPortWithExternalDevices' test.
+ // Our test assumes that 'getAudioPort' returns at least one profile, and it
+ // is not a dynamic profile.
+ ASSERT_NO_FATAL_FAILURE(config.SetUp(module.get()));
+ EXPECT_STATUS(EX_ILLEGAL_STATE, module->disconnectExternalDevice(portConnected.getId()))
+ << "when trying to disconnect device port ID " << port.id
+ << " with active configuration " << config.getId();
+ }
+ }
+}
+
+TEST_P(AudioCoreModule, ExternalDevicePortRoutes) {
+ ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+ std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
+ if (ports.empty()) {
+ GTEST_SKIP() << "No external devices in the module.";
+ }
+ for (const auto& port : ports) {
+ std::vector<AudioRoute> routesBefore;
+ ASSERT_IS_OK(module->getAudioRoutes(&routesBefore));
+
+ int32_t connectedPortId;
+ {
+ WithDevicePortConnectedState portConnected(port, GenerateUniqueDeviceAddress());
+ ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
+ connectedPortId = portConnected.getId();
+ std::vector<AudioRoute> connectedPortRoutes;
+ ASSERT_IS_OK(module->getAudioRoutesForAudioPort(connectedPortId, &connectedPortRoutes))
+ << "when retrieving routes for connected port id " << connectedPortId;
+ // There must be routes for the port to be useful.
+ if (connectedPortRoutes.empty()) {
+ std::vector<AudioRoute> allRoutes;
+ ASSERT_IS_OK(module->getAudioRoutes(&allRoutes));
+ ADD_FAILURE() << " no routes returned for the connected port "
+ << portConnected.get().toString()
+ << "; all routes: " << android::internal::ToString(allRoutes);
+ }
+ }
+ std::vector<AudioRoute> ignored;
+ ASSERT_STATUS(EX_ILLEGAL_ARGUMENT,
+ module->getAudioRoutesForAudioPort(connectedPortId, &ignored))
+ << "when retrieving routes for released connected port id " << connectedPortId;
+
+ std::vector<AudioRoute> routesAfter;
+ ASSERT_IS_OK(module->getAudioRoutes(&routesAfter));
+ ASSERT_EQ(routesBefore.size(), routesAfter.size())
+ << "Sizes of audio route arrays do not match after creating and "
+ << "releasing a connected port";
+ std::sort(routesBefore.begin(), routesBefore.end());
+ std::sort(routesAfter.begin(), routesAfter.end());
+ EXPECT_EQ(routesBefore, routesAfter);
+ }
+}
+
+TEST_P(AudioCoreModule, MasterMute) {
+ bool isSupported = false;
+ EXPECT_NO_FATAL_FAILURE(TestAccessors<bool>(module.get(), &IModule::getMasterMute,
+ &IModule::setMasterMute, {false, true}, {},
+ &isSupported));
+ if (!isSupported) {
+ GTEST_SKIP() << "Master mute is not supported";
+ }
+ // TODO: Test that master mute actually mutes output.
+}
+
+TEST_P(AudioCoreModule, MasterVolume) {
+ bool isSupported = false;
+ EXPECT_NO_FATAL_FAILURE(TestAccessors<float>(
+ module.get(), &IModule::getMasterVolume, &IModule::setMasterVolume, {0.0f, 0.5f, 1.0f},
+ {-0.1, 1.1, NAN, INFINITY, -INFINITY, 1 + std::numeric_limits<float>::epsilon()},
+ &isSupported));
+ if (!isSupported) {
+ GTEST_SKIP() << "Master volume is not supported";
+ }
+ // TODO: Test that master volume actually attenuates output.
+}
+
+TEST_P(AudioCoreModule, MicMute) {
+ bool isSupported = false;
+ EXPECT_NO_FATAL_FAILURE(TestAccessors<bool>(module.get(), &IModule::getMicMute,
+ &IModule::setMicMute, {false, true}, {},
+ &isSupported));
+ if (!isSupported) {
+ GTEST_SKIP() << "Mic mute is not supported";
+ }
+ // TODO: Test that mic mute actually mutes input.
+}
+
+TEST_P(AudioCoreModule, UpdateAudioMode) {
+ for (const auto mode : ::ndk::enum_range<AudioMode>()) {
+ EXPECT_IS_OK(module->updateAudioMode(mode)) << toString(mode);
+ }
+ EXPECT_IS_OK(module->updateAudioMode(AudioMode::NORMAL));
+}
+
+TEST_P(AudioCoreModule, UpdateScreenRotation) {
+ for (const auto rotation : ::ndk::enum_range<IModule::ScreenRotation>()) {
+ EXPECT_IS_OK(module->updateScreenRotation(rotation)) << toString(rotation);
+ }
+ EXPECT_IS_OK(module->updateScreenRotation(IModule::ScreenRotation::DEG_0));
+}
+
+TEST_P(AudioCoreModule, UpdateScreenState) {
+ EXPECT_IS_OK(module->updateScreenState(false));
+ EXPECT_IS_OK(module->updateScreenState(true));
+}
+
+class AudioCoreTelephony : public AudioCoreModuleBase, public testing::TestWithParam<std::string> {
+ public:
+ void SetUp() override {
+ ASSERT_NO_FATAL_FAILURE(SetUpImpl(GetParam()));
+ ASSERT_IS_OK(module->getTelephony(&telephony));
+ }
+
+ void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownImpl()); }
+
+ std::shared_ptr<ITelephony> telephony;
+};
+
+TEST_P(AudioCoreTelephony, GetSupportedAudioModes) {
+ if (telephony == nullptr) {
+ GTEST_SKIP() << "Telephony is not supported";
+ }
+ std::vector<AudioMode> modes1;
+ ASSERT_IS_OK(telephony->getSupportedAudioModes(&modes1));
+ const std::vector<AudioMode> kMandatoryModes = {AudioMode::NORMAL, AudioMode::RINGTONE,
+ AudioMode::IN_CALL,
+ AudioMode::IN_COMMUNICATION};
+ for (const auto mode : kMandatoryModes) {
+ EXPECT_NE(modes1.end(), std::find(modes1.begin(), modes1.end(), mode))
+ << "Mandatory mode not supported: " << toString(mode);
+ }
+ std::vector<AudioMode> modes2;
+ ASSERT_IS_OK(telephony->getSupportedAudioModes(&modes2));
+ ASSERT_EQ(modes1.size(), modes2.size())
+ << "Sizes of audio mode arrays do not match across consequent calls to "
+ << "getSupportedAudioModes";
+ std::sort(modes1.begin(), modes1.end());
+ std::sort(modes2.begin(), modes2.end());
+ EXPECT_EQ(modes1, modes2);
+};
+
+TEST_P(AudioCoreTelephony, SwitchAudioMode) {
+ if (telephony == nullptr) {
+ GTEST_SKIP() << "Telephony is not supported";
+ }
+ std::vector<AudioMode> supportedModes;
+ ASSERT_IS_OK(telephony->getSupportedAudioModes(&supportedModes));
+ std::set<AudioMode> unsupportedModes = {
+ // Start with all, remove supported ones
+ ::ndk::enum_range<AudioMode>().begin(), ::ndk::enum_range<AudioMode>().end()};
+ for (const auto mode : supportedModes) {
+ EXPECT_IS_OK(telephony->switchAudioMode(mode)) << toString(mode);
+ unsupportedModes.erase(mode);
+ }
+ for (const auto mode : unsupportedModes) {
+ EXPECT_STATUS(EX_UNSUPPORTED_OPERATION, telephony->switchAudioMode(mode)) << toString(mode);
+ }
+}
+
+using CommandSequence = std::vector<StreamDescriptor::Command>;
+class StreamLogicDriverInvalidCommand : public StreamLogicDriver {
+ public:
+ StreamLogicDriverInvalidCommand(const CommandSequence& commands) : mCommands(commands) {}
+
+ std::string getUnexpectedStatuses() {
+ // This method is intended to be called after the worker thread has joined,
+ // thus no extra synchronization is needed.
+ std::string s;
+ if (!mStatuses.empty()) {
+ s = std::string("Pairs of (command, actual status): ")
+ .append((android::internal::ToString(mStatuses)));
+ }
+ return s;
+ }
+
+ bool done() override { return mNextCommand >= mCommands.size(); }
+ TransitionTrigger getNextTrigger(int, int* actualSize) override {
+ if (actualSize != nullptr) *actualSize = 0;
+ return mCommands[mNextCommand++];
+ }
+ bool interceptRawReply(const StreamDescriptor::Reply& reply) override {
+ const size_t currentCommand = mNextCommand - 1; // increased by getNextTrigger
+ const bool isLastCommand = currentCommand == mCommands.size() - 1;
+ // All but the last command should run correctly. The last command must return 'BAD_VALUE'
+ // status.
+ if ((!isLastCommand && reply.status != STATUS_OK) ||
+ (isLastCommand && reply.status != STATUS_BAD_VALUE)) {
+ std::string s = mCommands[currentCommand].toString();
+ s.append(", ").append(statusToString(reply.status));
+ mStatuses.push_back(std::move(s));
+ // Process the reply, since the worker exits in case of an error.
+ return false;
+ }
+ return isLastCommand;
+ }
+ bool processValidReply(const StreamDescriptor::Reply&) override { return true; }
+
+ private:
+ const CommandSequence mCommands;
+ size_t mNextCommand = 0;
+ std::vector<std::string> mStatuses;
+};
+
+template <typename Stream>
+class AudioStream : public AudioCoreModule {
+ public:
+ void SetUp() override {
+ ASSERT_NO_FATAL_FAILURE(AudioCoreModule::SetUp());
+ ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+ }
+
+ void CloseTwice() {
+ const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
+ if (!portConfig.has_value()) {
+ GTEST_SKIP() << "No mix port for attached devices";
+ }
+ std::shared_ptr<Stream> heldStream;
+ {
+ WithStream<Stream> stream(portConfig.value());
+ ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+ heldStream = stream.getSharedPointer();
+ }
+ EXPECT_STATUS(EX_ILLEGAL_STATE, heldStream->close()) << "when closing the stream twice";
+ }
+
+ void OpenAllConfigs() {
+ const auto allPortConfigs =
+ moduleConfig->getPortConfigsForMixPorts(IOTraits<Stream>::is_input);
+ for (const auto& portConfig : allPortConfigs) {
+ WithStream<Stream> stream(portConfig);
+ ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+ }
+ }
+
+ void OpenInvalidBufferSize() {
+ const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
+ if (!portConfig.has_value()) {
+ GTEST_SKIP() << "No mix port for attached devices";
+ }
+ WithStream<Stream> stream(portConfig.value());
+ ASSERT_NO_FATAL_FAILURE(stream.SetUpPortConfig(module.get()));
+ // The buffer size of 1 frame should be impractically small, and thus
+ // less than any minimum buffer size suggested by any HAL.
+ for (long bufferSize : std::array<long, 4>{-1, 0, 1, std::numeric_limits<long>::max()}) {
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, stream.SetUpNoChecks(module.get(), bufferSize))
+ << "for the buffer size " << bufferSize;
+ EXPECT_EQ(nullptr, stream.get());
+ }
+ }
+
+ void OpenInvalidDirection() {
+ // Important! The direction of the port config must be reversed.
+ const auto portConfig =
+ moduleConfig->getSingleConfigForMixPort(!IOTraits<Stream>::is_input);
+ if (!portConfig.has_value()) {
+ GTEST_SKIP() << "No mix port for attached devices";
+ }
+ WithStream<Stream> stream(portConfig.value());
+ ASSERT_NO_FATAL_FAILURE(stream.SetUpPortConfig(module.get()));
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
+ stream.SetUpNoChecks(module.get(), kDefaultBufferSizeFrames))
+ << "port config ID " << stream.getPortId();
+ EXPECT_EQ(nullptr, stream.get());
+ }
+
+ void OpenOverMaxCount() {
+ constexpr bool isInput = IOTraits<Stream>::is_input;
+ auto ports = moduleConfig->getMixPorts(isInput);
+ bool hasSingleRun = false;
+ for (const auto& port : ports) {
+ const size_t maxStreamCount = port.ext.get<AudioPortExt::Tag::mix>().maxOpenStreamCount;
+ if (maxStreamCount == 0 ||
+ moduleConfig->getAttachedDevicesPortsForMixPort(isInput, port).empty()) {
+ // No restrictions or no permanently attached devices.
+ continue;
+ }
+ auto portConfigs = moduleConfig->getPortConfigsForMixPorts(isInput, port);
+ if (portConfigs.size() < maxStreamCount + 1) {
+ // Not able to open a sufficient number of streams for this port.
+ continue;
+ }
+ hasSingleRun = true;
+ std::optional<WithStream<Stream>> streamWraps[maxStreamCount + 1];
+ for (size_t i = 0; i <= maxStreamCount; ++i) {
+ streamWraps[i].emplace(portConfigs[i]);
+ WithStream<Stream>& stream = streamWraps[i].value();
+ if (i < maxStreamCount) {
+ ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+ } else {
+ ASSERT_NO_FATAL_FAILURE(stream.SetUpPortConfig(module.get()));
+ EXPECT_STATUS(EX_ILLEGAL_STATE,
+ stream.SetUpNoChecks(module.get(), kDefaultBufferSizeFrames))
+ << "port config ID " << stream.getPortId() << ", maxOpenStreamCount is "
+ << maxStreamCount;
+ }
+ }
+ }
+ if (!hasSingleRun) {
+ GTEST_SKIP() << "Not enough ports to test max open stream count";
+ }
+ }
+
+ void OpenTwiceSamePortConfig() {
+ const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
+ if (!portConfig.has_value()) {
+ GTEST_SKIP() << "No mix port for attached devices";
+ }
+ EXPECT_NO_FATAL_FAILURE(OpenTwiceSamePortConfigImpl(portConfig.value()));
+ }
+
+ void ResetPortConfigWithOpenStream() {
+ const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
+ if (!portConfig.has_value()) {
+ GTEST_SKIP() << "No mix port for attached devices";
+ }
+ WithStream<Stream> stream(portConfig.value());
+ ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+ EXPECT_STATUS(EX_ILLEGAL_STATE, module->resetAudioPortConfig(stream.getPortId()))
+ << "port config ID " << stream.getPortId();
+ }
+
+ void SendInvalidCommand() {
+ const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
+ if (!portConfig.has_value()) {
+ GTEST_SKIP() << "No mix port for attached devices";
+ }
+ EXPECT_NO_FATAL_FAILURE(SendInvalidCommandImpl(portConfig.value()));
+ }
+
+ void OpenTwiceSamePortConfigImpl(const AudioPortConfig& portConfig) {
+ WithStream<Stream> stream1(portConfig);
+ ASSERT_NO_FATAL_FAILURE(stream1.SetUp(module.get(), kDefaultBufferSizeFrames));
+ WithStream<Stream> stream2;
+ EXPECT_STATUS(EX_ILLEGAL_STATE, stream2.SetUpNoChecks(module.get(), stream1.getPortConfig(),
+ kDefaultBufferSizeFrames))
+ << "when opening a stream twice for the same port config ID "
+ << stream1.getPortId();
+ }
+
+ void SendInvalidCommandImpl(const AudioPortConfig& portConfig) {
+ using TestSequence = std::pair<std::string, CommandSequence>;
+ // The last command in 'CommandSequence' is the one that must trigger
+ // an error status. All preceding commands are to put the state machine
+ // into a state which accepts the last command.
+ std::vector<TestSequence> sequences{
+ std::make_pair(std::string("HalReservedExit"),
+ std::vector{StreamDescriptor::Command::make<
+ StreamDescriptor::Command::Tag::halReservedExit>(0)}),
+ std::make_pair(std::string("BurstNeg"),
+ std::vector{kStartCommand,
+ StreamDescriptor::Command::make<
+ StreamDescriptor::Command::Tag::burst>(-1)}),
+ std::make_pair(
+ std::string("BurstMinInt"),
+ std::vector{kStartCommand, StreamDescriptor::Command::make<
+ StreamDescriptor::Command::Tag::burst>(
+ std::numeric_limits<int32_t>::min())})};
+ if (IOTraits<Stream>::is_input) {
+ sequences.emplace_back("DrainAll",
+ std::vector{kStartCommand, kBurstCommand, kDrainOutAllCommand});
+ sequences.emplace_back(
+ "DrainEarly", std::vector{kStartCommand, kBurstCommand, kDrainOutEarlyCommand});
+ } else {
+ sequences.emplace_back("DrainUnspecified",
+ std::vector{kStartCommand, kBurstCommand, kDrainInCommand});
+ }
+ for (const auto& seq : sequences) {
+ SCOPED_TRACE(std::string("Sequence ").append(seq.first));
+ LOG(DEBUG) << __func__ << ": Sequence " << seq.first;
+ WithStream<Stream> stream(portConfig);
+ ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+ StreamLogicDriverInvalidCommand driver(seq.second);
+ typename IOTraits<Stream>::Worker worker(*stream.getContext(), &driver,
+ stream.getEventReceiver());
+ LOG(DEBUG) << __func__ << ": starting worker...";
+ ASSERT_TRUE(worker.start());
+ LOG(DEBUG) << __func__ << ": joining worker...";
+ worker.join();
+ EXPECT_EQ("", driver.getUnexpectedStatuses());
+ }
+ }
+};
+using AudioStreamIn = AudioStream<IStreamIn>;
+using AudioStreamOut = AudioStream<IStreamOut>;
+
+#define TEST_IN_AND_OUT_STREAM(method_name) \
+ TEST_P(AudioStreamIn, method_name) { ASSERT_NO_FATAL_FAILURE(method_name()); } \
+ TEST_P(AudioStreamOut, method_name) { ASSERT_NO_FATAL_FAILURE(method_name()); }
+
+TEST_IN_AND_OUT_STREAM(CloseTwice);
+TEST_IN_AND_OUT_STREAM(OpenAllConfigs);
+TEST_IN_AND_OUT_STREAM(OpenInvalidBufferSize);
+TEST_IN_AND_OUT_STREAM(OpenInvalidDirection);
+TEST_IN_AND_OUT_STREAM(OpenOverMaxCount);
+TEST_IN_AND_OUT_STREAM(OpenTwiceSamePortConfig);
+TEST_IN_AND_OUT_STREAM(ResetPortConfigWithOpenStream);
+TEST_IN_AND_OUT_STREAM(SendInvalidCommand);
+
+TEST_P(AudioStreamOut, OpenTwicePrimary) {
+ const auto mixPorts = moduleConfig->getMixPorts(false);
+ auto primaryPortIt = std::find_if(mixPorts.begin(), mixPorts.end(), [](const AudioPort& port) {
+ return port.flags.getTag() == AudioIoFlags::Tag::output &&
+ isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::output>(),
+ AudioOutputFlags::PRIMARY);
+ });
+ if (primaryPortIt == mixPorts.end()) {
+ GTEST_SKIP() << "No primary mix port";
+ }
+ if (moduleConfig->getAttachedSinkDevicesPortsForMixPort(*primaryPortIt).empty()) {
+ GTEST_SKIP() << "Primary mix port can not be routed to any of attached devices";
+ }
+ const auto portConfig = moduleConfig->getSingleConfigForMixPort(false, *primaryPortIt);
+ ASSERT_TRUE(portConfig.has_value()) << "No profiles specified for the primary mix port";
+ EXPECT_NO_FATAL_FAILURE(OpenTwiceSamePortConfigImpl(portConfig.value()));
+}
+
+TEST_P(AudioStreamOut, RequireOffloadInfo) {
+ const auto offloadMixPorts =
+ moduleConfig->getOffloadMixPorts(true /*attachedOnly*/, true /*singlePort*/);
+ if (offloadMixPorts.empty()) {
+ GTEST_SKIP()
+ << "No mix port for compressed offload that could be routed to attached devices";
+ }
+ const auto config = moduleConfig->getSingleConfigForMixPort(false, *offloadMixPorts.begin());
+ ASSERT_TRUE(config.has_value()) << "No profiles specified for the compressed offload mix port";
+ WithAudioPortConfig portConfig(config.value());
+ ASSERT_NO_FATAL_FAILURE(portConfig.SetUp(module.get()));
+ StreamDescriptor descriptor;
+ std::shared_ptr<IStreamOut> ignored;
+ aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
+ args.portConfigId = portConfig.getId();
+ args.sourceMetadata = GenerateSourceMetadata(portConfig.get());
+ args.bufferSizeFrames = kDefaultBufferSizeFrames;
+ aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->openOutputStream(args, &ret))
+ << "when no offload info is provided for a compressed offload mix port";
+}
+
+TEST_P(AudioStreamOut, RequireAsyncCallback) {
+ const auto nonBlockingMixPorts =
+ moduleConfig->getNonBlockingMixPorts(true /*attachedOnly*/, true /*singlePort*/);
+ if (nonBlockingMixPorts.empty()) {
+ GTEST_SKIP()
+ << "No mix port for non-blocking output that could be routed to attached devices";
+ }
+ const auto config =
+ moduleConfig->getSingleConfigForMixPort(false, *nonBlockingMixPorts.begin());
+ ASSERT_TRUE(config.has_value()) << "No profiles specified for the non-blocking mix port";
+ WithAudioPortConfig portConfig(config.value());
+ ASSERT_NO_FATAL_FAILURE(portConfig.SetUp(module.get()));
+ StreamDescriptor descriptor;
+ std::shared_ptr<IStreamOut> ignored;
+ aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
+ args.portConfigId = portConfig.getId();
+ args.sourceMetadata = GenerateSourceMetadata(portConfig.get());
+ args.offloadInfo = ModuleConfig::generateOffloadInfoIfNeeded(portConfig.get());
+ args.bufferSizeFrames = kDefaultBufferSizeFrames;
+ aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->openOutputStream(args, &ret))
+ << "when no async callback is provided for a non-blocking mix port";
+}
+
+class StreamLogicDefaultDriver : public StreamLogicDriver {
+ public:
+ explicit StreamLogicDefaultDriver(std::shared_ptr<StateSequence> commands)
+ : mCommands(commands) {
+ mCommands->rewind();
+ }
+
+ // The three methods below is intended to be called after the worker
+ // thread has joined, thus no extra synchronization is needed.
+ bool hasObservablePositionIncrease() const { return mObservablePositionIncrease; }
+ bool hasRetrogradeObservablePosition() const { return mRetrogradeObservablePosition; }
+ std::string getUnexpectedStateTransition() const { return mUnexpectedTransition; }
+
+ bool done() override { return mCommands->done(); }
+ TransitionTrigger getNextTrigger(int maxDataSize, int* actualSize) override {
+ auto trigger = mCommands->getTrigger();
+ if (StreamDescriptor::Command* command = std::get_if<StreamDescriptor::Command>(&trigger);
+ command != nullptr) {
+ if (command->getTag() == StreamDescriptor::Command::Tag::burst) {
+ if (actualSize != nullptr) {
+ // In the output scenario, reduce slightly the fmqByteCount to verify
+ // that the HAL module always consumes all data from the MQ.
+ if (maxDataSize > 1) maxDataSize--;
+ *actualSize = maxDataSize;
+ }
+ command->set<StreamDescriptor::Command::Tag::burst>(maxDataSize);
+ } else {
+ if (actualSize != nullptr) *actualSize = 0;
+ }
+ }
+ return trigger;
+ }
+ bool interceptRawReply(const StreamDescriptor::Reply&) override { return false; }
+ bool processValidReply(const StreamDescriptor::Reply& reply) override {
+ if (reply.observable.frames != StreamDescriptor::Position::UNKNOWN) {
+ if (mPreviousFrames.has_value()) {
+ if (reply.observable.frames > mPreviousFrames.value()) {
+ mObservablePositionIncrease = true;
+ } else if (reply.observable.frames < mPreviousFrames.value()) {
+ mRetrogradeObservablePosition = true;
+ }
+ }
+ mPreviousFrames = reply.observable.frames;
+ }
+
+ auto expected = mCommands->getExpectedStates();
+ if (expected.count(reply.state) == 0) {
+ std::string s =
+ std::string("Unexpected transition from the state ")
+ .append(mPreviousState.has_value() ? toString(mPreviousState.value())
+ : "<initial state>")
+ .append(" to ")
+ .append(toString(reply.state))
+ .append(" (expected one of ")
+ .append(::android::internal::ToString(expected))
+ .append(") caused by the ")
+ .append(toString(mCommands->getTrigger()));
+ LOG(ERROR) << __func__ << ": " << s;
+ mUnexpectedTransition = std::move(s);
+ return false;
+ }
+ mCommands->advance(reply.state);
+ mPreviousState = reply.state;
+ return true;
+ }
+
+ protected:
+ std::shared_ptr<StateSequence> mCommands;
+ std::optional<StreamDescriptor::State> mPreviousState;
+ std::optional<int64_t> mPreviousFrames;
+ bool mObservablePositionIncrease = false;
+ bool mRetrogradeObservablePosition = false;
+ std::string mUnexpectedTransition;
+};
+
+enum { NAMED_CMD_NAME, NAMED_CMD_DELAY_MS, NAMED_CMD_STREAM_TYPE, NAMED_CMD_CMDS };
+enum class StreamTypeFilter { ANY, SYNC, ASYNC };
+using NamedCommandSequence =
+ std::tuple<std::string, int, StreamTypeFilter, std::shared_ptr<StateSequence>>;
+enum { PARAM_MODULE_NAME, PARAM_CMD_SEQ, PARAM_SETUP_SEQ };
+using StreamIoTestParameters =
+ std::tuple<std::string /*moduleName*/, NamedCommandSequence, bool /*useSetupSequence2*/>;
+template <typename Stream>
+class AudioStreamIo : public AudioCoreModuleBase,
+ public testing::TestWithParam<StreamIoTestParameters> {
+ public:
+ void SetUp() override {
+ ASSERT_NO_FATAL_FAILURE(SetUpImpl(std::get<PARAM_MODULE_NAME>(GetParam())));
+ ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+ }
+
+ void Run() {
+ const auto allPortConfigs =
+ moduleConfig->getPortConfigsForMixPorts(IOTraits<Stream>::is_input);
+ if (allPortConfigs.empty()) {
+ GTEST_SKIP() << "No mix ports have attached devices";
+ }
+ for (const auto& portConfig : allPortConfigs) {
+ SCOPED_TRACE(portConfig.toString());
+ const bool isNonBlocking =
+ IOTraits<Stream>::is_input
+ ? false
+ :
+ // TODO: Uncomment when support for asynchronous input is implemented.
+ /*isBitPositionFlagSet(
+ portConfig.flags.value().template get<AudioIoFlags::Tag::input>(),
+ AudioInputFlags::NON_BLOCKING) :*/
+ isBitPositionFlagSet(portConfig.flags.value()
+ .template get<AudioIoFlags::Tag::output>(),
+ AudioOutputFlags::NON_BLOCKING);
+ if (auto streamType =
+ std::get<NAMED_CMD_STREAM_TYPE>(std::get<PARAM_CMD_SEQ>(GetParam()));
+ (isNonBlocking && streamType == StreamTypeFilter::SYNC) ||
+ (!isNonBlocking && streamType == StreamTypeFilter::ASYNC)) {
+ continue;
+ }
+ WithDebugFlags delayTransientStates = WithDebugFlags::createNested(debug);
+ delayTransientStates.flags().streamTransientStateDelayMs =
+ std::get<NAMED_CMD_DELAY_MS>(std::get<PARAM_CMD_SEQ>(GetParam()));
+ ASSERT_NO_FATAL_FAILURE(delayTransientStates.SetUp(module.get()));
+ const auto& commandsAndStates =
+ std::get<NAMED_CMD_CMDS>(std::get<PARAM_CMD_SEQ>(GetParam()));
+ if (!std::get<PARAM_SETUP_SEQ>(GetParam())) {
+ ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq1(portConfig, commandsAndStates));
+ } else {
+ ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq2(portConfig, commandsAndStates));
+ }
+ }
+ }
+
+ bool ValidateObservablePosition(const AudioPortConfig& /*portConfig*/) {
+ // May return false based on the portConfig, e.g. for telephony ports.
+ return true;
+ }
+
+ // Set up a patch first, then open a stream.
+ void RunStreamIoCommandsImplSeq1(const AudioPortConfig& portConfig,
+ std::shared_ptr<StateSequence> commandsAndStates) {
+ auto devicePorts = moduleConfig->getAttachedDevicesPortsForMixPort(
+ IOTraits<Stream>::is_input, portConfig);
+ ASSERT_FALSE(devicePorts.empty());
+ auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(devicePorts[0]);
+ WithAudioPatch patch(IOTraits<Stream>::is_input, portConfig, devicePortConfig);
+ ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
+
+ WithStream<Stream> stream(patch.getPortConfig(IOTraits<Stream>::is_input));
+ ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+ StreamLogicDefaultDriver driver(commandsAndStates);
+ typename IOTraits<Stream>::Worker worker(*stream.getContext(), &driver,
+ stream.getEventReceiver());
+
+ LOG(DEBUG) << __func__ << ": starting worker...";
+ ASSERT_TRUE(worker.start());
+ LOG(DEBUG) << __func__ << ": joining worker...";
+ worker.join();
+ EXPECT_FALSE(worker.hasError()) << worker.getError();
+ EXPECT_EQ("", driver.getUnexpectedStateTransition());
+ if (ValidateObservablePosition(portConfig)) {
+ EXPECT_TRUE(driver.hasObservablePositionIncrease());
+ EXPECT_FALSE(driver.hasRetrogradeObservablePosition());
+ }
+ }
+
+ // Open a stream, then set up a patch for it.
+ void RunStreamIoCommandsImplSeq2(const AudioPortConfig& portConfig,
+ std::shared_ptr<StateSequence> commandsAndStates) {
+ WithStream<Stream> stream(portConfig);
+ ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+ StreamLogicDefaultDriver driver(commandsAndStates);
+ typename IOTraits<Stream>::Worker worker(*stream.getContext(), &driver,
+ stream.getEventReceiver());
+
+ auto devicePorts = moduleConfig->getAttachedDevicesPortsForMixPort(
+ IOTraits<Stream>::is_input, portConfig);
+ ASSERT_FALSE(devicePorts.empty());
+ auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(devicePorts[0]);
+ WithAudioPatch patch(IOTraits<Stream>::is_input, stream.getPortConfig(), devicePortConfig);
+ ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
+
+ LOG(DEBUG) << __func__ << ": starting worker...";
+ ASSERT_TRUE(worker.start());
+ LOG(DEBUG) << __func__ << ": joining worker...";
+ worker.join();
+ EXPECT_FALSE(worker.hasError()) << worker.getError();
+ EXPECT_EQ("", driver.getUnexpectedStateTransition());
+ if (ValidateObservablePosition(portConfig)) {
+ EXPECT_TRUE(driver.hasObservablePositionIncrease());
+ EXPECT_FALSE(driver.hasRetrogradeObservablePosition());
+ }
+ }
+};
+using AudioStreamIoIn = AudioStreamIo<IStreamIn>;
+using AudioStreamIoOut = AudioStreamIo<IStreamOut>;
+
+#define TEST_IN_AND_OUT_STREAM_IO(method_name) \
+ TEST_P(AudioStreamIoIn, method_name) { ASSERT_NO_FATAL_FAILURE(method_name()); } \
+ TEST_P(AudioStreamIoOut, method_name) { ASSERT_NO_FATAL_FAILURE(method_name()); }
+
+TEST_IN_AND_OUT_STREAM_IO(Run);
+
+// Tests specific to audio patches. The fixure class is named 'AudioModulePatch'
+// to avoid clashing with 'AudioPatch' class.
+class AudioModulePatch : public AudioCoreModule {
+ public:
+ static std::string direction(bool isInput, bool capitalize) {
+ return isInput ? (capitalize ? "Input" : "input") : (capitalize ? "Output" : "output");
+ }
+
+ void SetUp() override {
+ ASSERT_NO_FATAL_FAILURE(AudioCoreModule::SetUp());
+ ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+ }
+
+ void SetInvalidPatchHelper(int32_t expectedException, const std::vector<int32_t>& sources,
+ const std::vector<int32_t>& sinks) {
+ AudioPatch patch;
+ patch.sourcePortConfigIds = sources;
+ patch.sinkPortConfigIds = sinks;
+ ASSERT_STATUS(expectedException, module->setAudioPatch(patch, &patch))
+ << "patch source ids: " << android::internal::ToString(sources)
+ << "; sink ids: " << android::internal::ToString(sinks);
+ }
+
+ void ResetPortConfigUsedByPatch(bool isInput) {
+ auto srcSinkGroups = moduleConfig->getRoutableSrcSinkGroups(isInput);
+ if (srcSinkGroups.empty()) {
+ GTEST_SKIP() << "No routes to any attached " << direction(isInput, false) << " devices";
+ }
+ auto srcSinkGroup = *srcSinkGroups.begin();
+ auto srcSink = *srcSinkGroup.second.begin();
+ WithAudioPatch patch(srcSink.first, srcSink.second);
+ ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
+ std::vector<int32_t> sourceAndSinkPortConfigIds(patch.get().sourcePortConfigIds);
+ sourceAndSinkPortConfigIds.insert(sourceAndSinkPortConfigIds.end(),
+ patch.get().sinkPortConfigIds.begin(),
+ patch.get().sinkPortConfigIds.end());
+ for (const auto portConfigId : sourceAndSinkPortConfigIds) {
+ EXPECT_STATUS(EX_ILLEGAL_STATE, module->resetAudioPortConfig(portConfigId))
+ << "port config ID " << portConfigId;
+ }
+ }
+
+ void SetInvalidPatch(bool isInput) {
+ auto srcSinkPair = moduleConfig->getRoutableSrcSinkPair(isInput);
+ if (!srcSinkPair.has_value()) {
+ GTEST_SKIP() << "No routes to any attached " << direction(isInput, false) << " devices";
+ }
+ WithAudioPortConfig srcPortConfig(srcSinkPair.value().first);
+ ASSERT_NO_FATAL_FAILURE(srcPortConfig.SetUp(module.get()));
+ WithAudioPortConfig sinkPortConfig(srcSinkPair.value().second);
+ ASSERT_NO_FATAL_FAILURE(sinkPortConfig.SetUp(module.get()));
+ { // Check that the pair can actually be used for setting up a patch.
+ WithAudioPatch patch(srcPortConfig.get(), sinkPortConfig.get());
+ ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
+ }
+ EXPECT_NO_FATAL_FAILURE(
+ SetInvalidPatchHelper(EX_ILLEGAL_ARGUMENT, {}, {sinkPortConfig.getId()}));
+ EXPECT_NO_FATAL_FAILURE(SetInvalidPatchHelper(
+ EX_ILLEGAL_ARGUMENT, {srcPortConfig.getId(), srcPortConfig.getId()},
+ {sinkPortConfig.getId()}));
+ EXPECT_NO_FATAL_FAILURE(
+ SetInvalidPatchHelper(EX_ILLEGAL_ARGUMENT, {srcPortConfig.getId()}, {}));
+ EXPECT_NO_FATAL_FAILURE(
+ SetInvalidPatchHelper(EX_ILLEGAL_ARGUMENT, {srcPortConfig.getId()},
+ {sinkPortConfig.getId(), sinkPortConfig.getId()}));
+
+ std::set<int32_t> portConfigIds;
+ ASSERT_NO_FATAL_FAILURE(GetAllPortConfigIds(&portConfigIds));
+ for (const auto portConfigId : GetNonExistentIds(portConfigIds)) {
+ EXPECT_NO_FATAL_FAILURE(SetInvalidPatchHelper(EX_ILLEGAL_ARGUMENT, {portConfigId},
+ {sinkPortConfig.getId()}));
+ EXPECT_NO_FATAL_FAILURE(SetInvalidPatchHelper(EX_ILLEGAL_ARGUMENT,
+ {srcPortConfig.getId()}, {portConfigId}));
+ }
+ }
+
+ void SetNonRoutablePatch(bool isInput) {
+ auto srcSinkPair = moduleConfig->getNonRoutableSrcSinkPair(isInput);
+ if (!srcSinkPair.has_value()) {
+ GTEST_SKIP() << "All possible source/sink pairs are routable";
+ }
+ WithAudioPatch patch(srcSinkPair.value().first, srcSinkPair.value().second);
+ ASSERT_NO_FATAL_FAILURE(patch.SetUpPortConfigs(module.get()));
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, patch.SetUpNoChecks(module.get()))
+ << "when setting up a patch from " << srcSinkPair.value().first.toString() << " to "
+ << srcSinkPair.value().second.toString() << " that does not have a route";
+ }
+
+ void SetPatch(bool isInput) {
+ auto srcSinkGroups = moduleConfig->getRoutableSrcSinkGroups(isInput);
+ if (srcSinkGroups.empty()) {
+ GTEST_SKIP() << "No routes to any attached " << direction(isInput, false) << " devices";
+ }
+ for (const auto& srcSinkGroup : srcSinkGroups) {
+ const auto& route = srcSinkGroup.first;
+ std::vector<std::unique_ptr<WithAudioPatch>> patches;
+ for (const auto& srcSink : srcSinkGroup.second) {
+ if (!route.isExclusive) {
+ patches.push_back(
+ std::make_unique<WithAudioPatch>(srcSink.first, srcSink.second));
+ EXPECT_NO_FATAL_FAILURE(patches[patches.size() - 1]->SetUp(module.get()));
+ } else {
+ WithAudioPatch patch(srcSink.first, srcSink.second);
+ EXPECT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
+ }
+ }
+ }
+ }
+
+ void UpdatePatch(bool isInput) {
+ auto srcSinkGroups = moduleConfig->getRoutableSrcSinkGroups(isInput);
+ if (srcSinkGroups.empty()) {
+ GTEST_SKIP() << "No routes to any attached " << direction(isInput, false) << " devices";
+ }
+ for (const auto& srcSinkGroup : srcSinkGroups) {
+ for (const auto& srcSink : srcSinkGroup.second) {
+ WithAudioPatch patch(srcSink.first, srcSink.second);
+ ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
+ AudioPatch ignored;
+ EXPECT_NO_FATAL_FAILURE(module->setAudioPatch(patch.get(), &ignored));
+ }
+ }
+ }
+
+ void UpdateInvalidPatchId(bool isInput) {
+ auto srcSinkGroups = moduleConfig->getRoutableSrcSinkGroups(isInput);
+ if (srcSinkGroups.empty()) {
+ GTEST_SKIP() << "No routes to any attached " << direction(isInput, false) << " devices";
+ }
+ // First, set up a patch to ensure that its settings are accepted.
+ auto srcSinkGroup = *srcSinkGroups.begin();
+ auto srcSink = *srcSinkGroup.second.begin();
+ WithAudioPatch patch(srcSink.first, srcSink.second);
+ ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
+ // Then use the same patch setting, except for having an invalid ID.
+ std::set<int32_t> patchIds;
+ ASSERT_NO_FATAL_FAILURE(GetAllPatchIds(&patchIds));
+ for (const auto patchId : GetNonExistentIds(patchIds)) {
+ AudioPatch patchWithNonExistendId = patch.get();
+ patchWithNonExistendId.id = patchId;
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
+ module->setAudioPatch(patchWithNonExistendId, &patchWithNonExistendId))
+ << "patch ID " << patchId;
+ }
+ }
+};
+
+// Not all tests require both directions, so parametrization would require
+// more abstractions.
+#define TEST_PATCH_BOTH_DIRECTIONS(method_name) \
+ TEST_P(AudioModulePatch, method_name##Input) { ASSERT_NO_FATAL_FAILURE(method_name(true)); } \
+ TEST_P(AudioModulePatch, method_name##Output) { ASSERT_NO_FATAL_FAILURE(method_name(false)); }
+
+TEST_PATCH_BOTH_DIRECTIONS(ResetPortConfigUsedByPatch);
+TEST_PATCH_BOTH_DIRECTIONS(SetInvalidPatch);
+TEST_PATCH_BOTH_DIRECTIONS(SetNonRoutablePatch);
+TEST_PATCH_BOTH_DIRECTIONS(SetPatch);
+TEST_PATCH_BOTH_DIRECTIONS(UpdateInvalidPatchId);
+TEST_PATCH_BOTH_DIRECTIONS(UpdatePatch);
+
+TEST_P(AudioModulePatch, ResetInvalidPatchId) {
+ std::set<int32_t> patchIds;
+ ASSERT_NO_FATAL_FAILURE(GetAllPatchIds(&patchIds));
+ for (const auto patchId : GetNonExistentIds(patchIds)) {
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->resetAudioPatch(patchId))
+ << "patch ID " << patchId;
+ }
+}
+
+INSTANTIATE_TEST_SUITE_P(AudioCoreModuleTest, AudioCoreModule,
+ testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
+ android::PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioCoreModule);
+INSTANTIATE_TEST_SUITE_P(AudioCoreTelephonyTest, AudioCoreTelephony,
+ testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
+ android::PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioCoreTelephony);
+INSTANTIATE_TEST_SUITE_P(AudioStreamInTest, AudioStreamIn,
+ testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
+ android::PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioStreamIn);
+INSTANTIATE_TEST_SUITE_P(AudioStreamOutTest, AudioStreamOut,
+ testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
+ android::PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioStreamOut);
+
+// This is the value used in test sequences for which the test needs to ensure
+// that the HAL stays in a transient state long enough to receive the next command.
+static const int kStreamTransientStateTransitionDelayMs = 3000;
+
+// TODO: Add async test cases for input once it is implemented.
+
+std::shared_ptr<StateSequence> makeBurstCommands(bool isSync, size_t burstCount) {
+ const auto burst =
+ isSync ? std::vector<StateTransition>{std::make_pair(kBurstCommand,
+ StreamDescriptor::State::ACTIVE)}
+ : std::vector<StateTransition>{
+ std::make_pair(kBurstCommand, StreamDescriptor::State::TRANSFERRING),
+ std::make_pair(kTransferReadyEvent, StreamDescriptor::State::ACTIVE)};
+ std::vector<StateTransition> result{
+ std::make_pair(kStartCommand, StreamDescriptor::State::IDLE)};
+ for (size_t i = 0; i < burstCount; ++i) {
+ result.insert(result.end(), burst.begin(), burst.end());
+ }
+ return std::make_shared<SmartStateSequence>(result);
+}
+static const NamedCommandSequence kReadSeq =
+ std::make_tuple(std::string("Read"), 0, StreamTypeFilter::ANY, makeBurstCommands(true, 3));
+static const NamedCommandSequence kWriteSyncSeq = std::make_tuple(
+ std::string("Write"), 0, StreamTypeFilter::SYNC, makeBurstCommands(true, 3));
+static const NamedCommandSequence kWriteAsyncSeq = std::make_tuple(
+ std::string("Write"), 0, StreamTypeFilter::ASYNC, makeBurstCommands(false, 3));
+
+std::shared_ptr<StateSequence> makeAsyncDrainCommands(bool isInput) {
+ return std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
+ std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+ std::make_pair(kBurstCommand, isInput ? StreamDescriptor::State::ACTIVE
+ : StreamDescriptor::State::TRANSFERRING),
+ std::make_pair(isInput ? kDrainInCommand : kDrainOutAllCommand,
+ StreamDescriptor::State::DRAINING),
+ isInput ? std::make_pair(kStartCommand, StreamDescriptor::State::ACTIVE)
+ : std::make_pair(kBurstCommand, StreamDescriptor::State::TRANSFERRING),
+ std::make_pair(isInput ? kDrainInCommand : kDrainOutAllCommand,
+ StreamDescriptor::State::DRAINING)});
+}
+static const NamedCommandSequence kWriteDrainAsyncSeq =
+ std::make_tuple(std::string("WriteDrain"), kStreamTransientStateTransitionDelayMs,
+ StreamTypeFilter::ASYNC, makeAsyncDrainCommands(false));
+static const NamedCommandSequence kDrainInSeq = std::make_tuple(
+ std::string("Drain"), 0, StreamTypeFilter::ANY, makeAsyncDrainCommands(true));
+
+std::shared_ptr<StateSequence> makeDrainOutCommands(bool isSync) {
+ return std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
+ std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+ std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
+ std::make_pair(kDrainOutAllCommand, StreamDescriptor::State::DRAINING),
+ std::make_pair(isSync ? TransitionTrigger(kGetStatusCommand)
+ : TransitionTrigger(kDrainReadyEvent),
+ StreamDescriptor::State::IDLE)});
+}
+static const NamedCommandSequence kDrainOutSyncSeq = std::make_tuple(
+ std::string("Drain"), 0, StreamTypeFilter::SYNC, makeDrainOutCommands(true));
+static const NamedCommandSequence kDrainOutAsyncSeq = std::make_tuple(
+ std::string("Drain"), 0, StreamTypeFilter::ASYNC, makeDrainOutCommands(false));
+
+std::shared_ptr<StateSequence> makeDrainOutPauseCommands(bool isSync) {
+ return std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
+ std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+ std::make_pair(kBurstCommand, isSync ? StreamDescriptor::State::ACTIVE
+ : StreamDescriptor::State::TRANSFERRING),
+ std::make_pair(kDrainOutAllCommand, StreamDescriptor::State::DRAINING),
+ std::make_pair(kPauseCommand, StreamDescriptor::State::DRAIN_PAUSED),
+ std::make_pair(kStartCommand, StreamDescriptor::State::DRAINING),
+ std::make_pair(kPauseCommand, StreamDescriptor::State::DRAIN_PAUSED),
+ std::make_pair(kBurstCommand, isSync ? StreamDescriptor::State::PAUSED
+ : StreamDescriptor::State::TRANSFER_PAUSED)});
+}
+static const NamedCommandSequence kDrainPauseOutSyncSeq =
+ std::make_tuple(std::string("DrainPause"), kStreamTransientStateTransitionDelayMs,
+ StreamTypeFilter::SYNC, makeDrainOutPauseCommands(true));
+static const NamedCommandSequence kDrainPauseOutAsyncSeq =
+ std::make_tuple(std::string("DrainPause"), kStreamTransientStateTransitionDelayMs,
+ StreamTypeFilter::ASYNC, makeDrainOutPauseCommands(false));
+
+// This sequence also verifies that the capture / presentation position is not reset on standby.
+std::shared_ptr<StateSequence> makeStandbyCommands(bool isInput, bool isSync) {
+ return std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
+ std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+ std::make_pair(kStandbyCommand, StreamDescriptor::State::STANDBY),
+ std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+ std::make_pair(kBurstCommand, isInput || isSync
+ ? StreamDescriptor::State::ACTIVE
+ : StreamDescriptor::State::TRANSFERRING),
+ std::make_pair(kPauseCommand, isInput || isSync
+ ? StreamDescriptor::State::PAUSED
+ : StreamDescriptor::State::TRANSFER_PAUSED),
+ std::make_pair(kFlushCommand, isInput ? StreamDescriptor::State::STANDBY
+ : StreamDescriptor::State::IDLE),
+ std::make_pair(isInput ? kGetStatusCommand : kStandbyCommand, // no-op for input
+ StreamDescriptor::State::STANDBY),
+ std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+ std::make_pair(kBurstCommand, isInput || isSync
+ ? StreamDescriptor::State::ACTIVE
+ : StreamDescriptor::State::TRANSFERRING)});
+}
+static const NamedCommandSequence kStandbyInSeq = std::make_tuple(
+ std::string("Standby"), 0, StreamTypeFilter::ANY, makeStandbyCommands(true, false));
+static const NamedCommandSequence kStandbyOutSyncSeq = std::make_tuple(
+ std::string("Standby"), 0, StreamTypeFilter::SYNC, makeStandbyCommands(false, true));
+static const NamedCommandSequence kStandbyOutAsyncSeq =
+ std::make_tuple(std::string("Standby"), kStreamTransientStateTransitionDelayMs,
+ StreamTypeFilter::ASYNC, makeStandbyCommands(false, false));
+
+static const NamedCommandSequence kPauseInSeq =
+ std::make_tuple(std::string("Pause"), 0, StreamTypeFilter::ANY,
+ std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
+ std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+ std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
+ std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
+ std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
+ std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
+ std::make_pair(kFlushCommand, StreamDescriptor::State::STANDBY)}));
+static const NamedCommandSequence kPauseOutSyncSeq =
+ std::make_tuple(std::string("Pause"), 0, StreamTypeFilter::SYNC,
+ std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
+ std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+ std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
+ std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
+ std::make_pair(kStartCommand, StreamDescriptor::State::ACTIVE),
+ std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
+ std::make_pair(kBurstCommand, StreamDescriptor::State::PAUSED),
+ std::make_pair(kStartCommand, StreamDescriptor::State::ACTIVE),
+ std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED)}));
+/* TODO: Figure out a better way for testing sync/async bursts
+static const NamedCommandSequence kPauseOutAsyncSeq = std::make_tuple(
+ std::string("Pause"), kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC,
+ std::make_shared<StaticStateSequence>(std::vector<StateTransition>{
+ std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+ std::make_pair(kBurstCommand, StreamDescriptor::State::TRANSFERRING),
+ std::make_pair(kPauseCommand, StreamDescriptor::State::TRANSFER_PAUSED),
+ std::make_pair(kStartCommand, StreamDescriptor::State::TRANSFERRING),
+ std::make_pair(kPauseCommand, StreamDescriptor::State::TRANSFER_PAUSED),
+ std::make_pair(kDrainOutAllCommand, StreamDescriptor::State::DRAIN_PAUSED),
+ std::make_pair(kBurstCommand, StreamDescriptor::State::TRANSFER_PAUSED)}));
+*/
+
+std::shared_ptr<StateSequence> makeFlushCommands(bool isInput, bool isSync) {
+ return std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
+ std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+ std::make_pair(kBurstCommand, isInput || isSync
+ ? StreamDescriptor::State::ACTIVE
+ : StreamDescriptor::State::TRANSFERRING),
+ std::make_pair(kPauseCommand, isInput || isSync
+ ? StreamDescriptor::State::PAUSED
+ : StreamDescriptor::State::TRANSFER_PAUSED),
+ std::make_pair(kFlushCommand, isInput ? StreamDescriptor::State::STANDBY
+ : StreamDescriptor::State::IDLE)});
+}
+static const NamedCommandSequence kFlushInSeq = std::make_tuple(
+ std::string("Flush"), 0, StreamTypeFilter::ANY, makeFlushCommands(true, false));
+static const NamedCommandSequence kFlushOutSyncSeq = std::make_tuple(
+ std::string("Flush"), 0, StreamTypeFilter::SYNC, makeFlushCommands(false, true));
+static const NamedCommandSequence kFlushOutAsyncSeq =
+ std::make_tuple(std::string("Flush"), kStreamTransientStateTransitionDelayMs,
+ StreamTypeFilter::ASYNC, makeFlushCommands(false, false));
+
+std::shared_ptr<StateSequence> makeDrainPauseFlushOutCommands(bool isSync) {
+ return std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
+ std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+ std::make_pair(kBurstCommand, isSync ? StreamDescriptor::State::ACTIVE
+ : StreamDescriptor::State::TRANSFERRING),
+ std::make_pair(kDrainOutAllCommand, StreamDescriptor::State::DRAINING),
+ std::make_pair(kPauseCommand, StreamDescriptor::State::DRAIN_PAUSED),
+ std::make_pair(kFlushCommand, StreamDescriptor::State::IDLE)});
+}
+static const NamedCommandSequence kDrainPauseFlushOutSyncSeq =
+ std::make_tuple(std::string("DrainPauseFlush"), kStreamTransientStateTransitionDelayMs,
+ StreamTypeFilter::SYNC, makeDrainPauseFlushOutCommands(true));
+static const NamedCommandSequence kDrainPauseFlushOutAsyncSeq =
+ std::make_tuple(std::string("DrainPauseFlush"), kStreamTransientStateTransitionDelayMs,
+ StreamTypeFilter::ASYNC, makeDrainPauseFlushOutCommands(false));
+
+// Note, this isn't the "official" enum printer, it is only used to make the test name suffix.
+std::string PrintStreamFilterToString(StreamTypeFilter filter) {
+ switch (filter) {
+ case StreamTypeFilter::ANY:
+ return "";
+ case StreamTypeFilter::SYNC:
+ return "Sync";
+ case StreamTypeFilter::ASYNC:
+ return "Async";
+ }
+ return std::string("Unknown").append(std::to_string(static_cast<int32_t>(filter)));
+}
+std::string GetStreamIoTestName(const testing::TestParamInfo<StreamIoTestParameters>& info) {
+ return android::PrintInstanceNameToString(
+ testing::TestParamInfo<std::string>{std::get<PARAM_MODULE_NAME>(info.param),
+ info.index})
+ .append("_")
+ .append(std::get<NAMED_CMD_NAME>(std::get<PARAM_CMD_SEQ>(info.param)))
+ .append(PrintStreamFilterToString(
+ std::get<NAMED_CMD_STREAM_TYPE>(std::get<PARAM_CMD_SEQ>(info.param))))
+ .append("_SetupSeq")
+ .append(std::get<PARAM_SETUP_SEQ>(info.param) ? "2" : "1");
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ AudioStreamIoInTest, AudioStreamIoIn,
+ testing::Combine(testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
+ testing::Values(kReadSeq, kDrainInSeq, kStandbyInSeq, kPauseInSeq,
+ kFlushInSeq),
+ testing::Values(false, true)),
+ GetStreamIoTestName);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioStreamIoIn);
+INSTANTIATE_TEST_SUITE_P(
+ AudioStreamIoOutTest, AudioStreamIoOut,
+ testing::Combine(testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
+ testing::Values(kWriteSyncSeq, kWriteAsyncSeq, kWriteDrainAsyncSeq,
+ kDrainOutSyncSeq, kDrainPauseOutSyncSeq,
+ kDrainPauseOutAsyncSeq, kStandbyOutSyncSeq,
+ kStandbyOutAsyncSeq,
+ kPauseOutSyncSeq, // kPauseOutAsyncSeq,
+ kFlushOutSyncSeq, kFlushOutAsyncSeq,
+ kDrainPauseFlushOutSyncSeq, kDrainPauseFlushOutAsyncSeq),
+ testing::Values(false, true)),
+ GetStreamIoTestName);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioStreamIoOut);
+
+INSTANTIATE_TEST_SUITE_P(AudioPatchTest, AudioModulePatch,
+ testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
+ android::PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioModulePatch);
+
+class TestExecutionTracer : public ::testing::EmptyTestEventListener {
+ public:
+ void OnTestStart(const ::testing::TestInfo& test_info) override {
+ TraceTestState("Started", test_info);
+ }
+ void OnTestEnd(const ::testing::TestInfo& test_info) override {
+ TraceTestState("Completed", test_info);
+ }
+
+ private:
+ static void TraceTestState(const std::string& state, const ::testing::TestInfo& test_info) {
+ LOG(INFO) << state << " " << test_info.test_suite_name() << "::" << test_info.name();
+ }
+};
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
+ android::base::SetMinimumLogSeverity(::android::base::DEBUG);
+ ABinderProcess_setThreadPoolMaxThreadCount(1);
+ ABinderProcess_startThreadPool();
+ return RUN_ALL_TESTS();
+}
diff --git a/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp b/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp
new file mode 100644
index 0000000..8ae963e
--- /dev/null
+++ b/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <memory>
+#include <set>
+#include <string>
+#include <vector>
+
+#define LOG_TAG "VtsHalAudioEffectFactory"
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android/binder_interface_utils.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+#include <aidl/android/hardware/audio/effect/IFactory.h>
+
+#include "AudioHalBinderServiceUtil.h"
+#include "EffectFactoryHelper.h"
+#include "TestUtils.h"
+
+using namespace android;
+
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::kEffectNullUuid;
+using aidl::android::hardware::audio::effect::kEffectZeroUuid;
+using aidl::android::hardware::audio::effect::Processing;
+using aidl::android::media::audio::common::AudioSource;
+using aidl::android::media::audio::common::AudioStreamType;
+using aidl::android::media::audio::common::AudioUuid;
+
+/// Effect factory testing.
+class EffectFactoryTest : public testing::TestWithParam<std::string> {
+ public:
+ void SetUp() override {
+ mFactoryHelper = std::make_unique<EffectFactoryHelper>(GetParam());
+ connectAndGetFactory();
+ }
+
+ void TearDown() override {
+ for (auto& effect : mEffects) {
+ const auto status = mEffectFactory->destroyEffect(effect);
+ EXPECT_STATUS(EX_NONE, status);
+ }
+ }
+
+ std::unique_ptr<EffectFactoryHelper> mFactoryHelper;
+ std::shared_ptr<IFactory> mEffectFactory;
+ std::vector<std::shared_ptr<IEffect>> mEffects;
+ const Descriptor::Identity kNullDesc = {.uuid = kEffectNullUuid};
+ const Descriptor::Identity kZeroDesc = {.uuid = kEffectZeroUuid};
+
+ template <typename Functor>
+ void ForEachId(const std::vector<Descriptor::Identity> ids, Functor functor) {
+ for (const auto& id : ids) {
+ SCOPED_TRACE(id.toString());
+ functor(id);
+ }
+ }
+ template <typename Functor>
+ void ForEachEffect(std::vector<std::shared_ptr<IEffect>> effects, Functor functor) {
+ for (auto& effect : effects) {
+ functor(effect);
+ }
+ }
+
+ std::vector<std::shared_ptr<IEffect>> createWithIds(
+ const std::vector<Descriptor::Identity> ids,
+ const binder_status_t expectStatus = EX_NONE) {
+ std::vector<std::shared_ptr<IEffect>> effects;
+ for (const auto& id : ids) {
+ std::shared_ptr<IEffect> effect;
+ EXPECT_STATUS(expectStatus, mEffectFactory->createEffect(id.uuid, &effect));
+ if (expectStatus == EX_NONE) {
+ EXPECT_NE(effect, nullptr) << " null effect with uuid: " << id.uuid.toString();
+ effects.push_back(std::move(effect));
+ }
+ }
+ return effects;
+ }
+ void destroyEffects(std::vector<std::shared_ptr<IEffect>> effects,
+ const binder_status_t expectStatus = EX_NONE) {
+ for (const auto& effect : effects) {
+ EXPECT_STATUS(expectStatus, mEffectFactory->destroyEffect(effect));
+ }
+ }
+ void creatAndDestroyIds(const std::vector<Descriptor::Identity> ids) {
+ for (const auto& id : ids) {
+ auto effects = createWithIds({id});
+ ASSERT_NO_FATAL_FAILURE(destroyEffects(effects));
+ }
+ }
+ void connectAndGetFactory() {
+ ASSERT_NO_FATAL_FAILURE(mFactoryHelper->ConnectToFactoryService());
+ mEffectFactory = mFactoryHelper->GetFactory();
+ ASSERT_NE(mEffectFactory, nullptr);
+ }
+};
+
+TEST_P(EffectFactoryTest, SetupAndTearDown) {
+ // Intentionally empty test body.
+}
+
+TEST_P(EffectFactoryTest, CanBeRestarted) {
+ ASSERT_NO_FATAL_FAILURE(mFactoryHelper->RestartFactoryService());
+}
+
+/**
+ * @brief Check at least support list of effect must be supported by aosp:
+ * https://developer.android.com/reference/android/media/audiofx/AudioEffect
+ */
+TEST_P(EffectFactoryTest, ExpectAllAospEffectTypes) {
+ std::vector<Descriptor::Identity> ids;
+ std::set<AudioUuid> typeUuidSet(
+ {aidl::android::hardware::audio::effect::kBassBoostTypeUUID,
+ aidl::android::hardware::audio::effect::kEqualizerTypeUUID,
+ aidl::android::hardware::audio::effect::kEnvReverbTypeUUID,
+ aidl::android::hardware::audio::effect::kPresetReverbTypeUUID,
+ aidl::android::hardware::audio::effect::kDynamicsProcessingTypeUUID,
+ aidl::android::hardware::audio::effect::kHapticGeneratorTypeUUID,
+ aidl::android::hardware::audio::effect::kVirtualizerTypeUUID});
+
+ EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids));
+ EXPECT_TRUE(ids.size() >= typeUuidSet.size());
+ for (const auto& id : ids) {
+ typeUuidSet.erase(id.type);
+ }
+ std::string msg = " missing type UUID:\n";
+ for (const auto& uuid : typeUuidSet) {
+ msg += (uuid.toString() + "\n");
+ }
+ SCOPED_TRACE(msg);
+ EXPECT_EQ(0UL, typeUuidSet.size());
+}
+
+TEST_P(EffectFactoryTest, QueryNullTypeUuid) {
+ std::vector<Descriptor::Identity> ids;
+ EXPECT_IS_OK(mEffectFactory->queryEffects(kEffectNullUuid, std::nullopt, std::nullopt, &ids));
+ EXPECT_EQ(ids.size(), 0UL);
+}
+
+TEST_P(EffectFactoryTest, QueriedNullImplUuid) {
+ std::vector<Descriptor::Identity> ids;
+ EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, kEffectNullUuid, std::nullopt, &ids));
+ EXPECT_EQ(ids.size(), 0UL);
+}
+
+TEST_P(EffectFactoryTest, QueriedNullProxyUuid) {
+ std::vector<Descriptor::Identity> ids;
+ EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, kEffectNullUuid, &ids));
+ EXPECT_EQ(ids.size(), 0UL);
+}
+
+// create all effects, and then destroy them all together
+TEST_P(EffectFactoryTest, CreateAndDestroyEffects) {
+ std::vector<Descriptor::Identity> ids;
+ EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids));
+ EXPECT_NE(ids.size(), 0UL);
+
+ std::vector<std::shared_ptr<IEffect>> effects;
+ effects = createWithIds(ids);
+ EXPECT_EQ(ids.size(), effects.size());
+ destroyEffects(effects);
+}
+
+TEST_P(EffectFactoryTest, CreateMultipleInstanceOfSameEffect) {
+ std::vector<Descriptor::Identity> ids;
+ EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids));
+ EXPECT_NE(ids.size(), 0UL);
+
+ std::vector<std::shared_ptr<IEffect>> effects = createWithIds(ids);
+ EXPECT_EQ(ids.size(), effects.size());
+ std::vector<std::shared_ptr<IEffect>> effects2 = createWithIds(ids);
+ EXPECT_EQ(ids.size(), effects2.size());
+ std::vector<std::shared_ptr<IEffect>> effects3 = createWithIds(ids);
+ EXPECT_EQ(ids.size(), effects3.size());
+
+ destroyEffects(effects);
+ destroyEffects(effects2);
+ destroyEffects(effects3);
+}
+
+// create and destroy each effect one by one
+TEST_P(EffectFactoryTest, CreateAndDestroyEffectsOneByOne) {
+ std::vector<Descriptor::Identity> ids;
+ EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids));
+ EXPECT_NE(ids.size(), 0UL);
+
+ creatAndDestroyIds(ids);
+}
+
+// for each effect: repeat 3 times create and destroy
+TEST_P(EffectFactoryTest, CreateAndDestroyRepeat) {
+ std::vector<Descriptor::Identity> ids;
+ EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids));
+ EXPECT_NE(ids.size(), 0UL);
+
+ creatAndDestroyIds(ids);
+ creatAndDestroyIds(ids);
+ creatAndDestroyIds(ids);
+}
+
+// Expect EX_ILLEGAL_ARGUMENT when create with invalid UUID.
+TEST_P(EffectFactoryTest, CreateWithInvalidUuid) {
+ std::vector<Descriptor::Identity> ids = {kNullDesc, kZeroDesc};
+ auto effects = createWithIds(ids, EX_ILLEGAL_ARGUMENT);
+ EXPECT_EQ(effects.size(), 0UL);
+}
+
+// Expect EX_ILLEGAL_ARGUMENT when destroy null interface.
+TEST_P(EffectFactoryTest, DestroyWithInvalidInterface) {
+ std::shared_ptr<IEffect> spDummyEffect(nullptr);
+ destroyEffects({spDummyEffect}, EX_ILLEGAL_ARGUMENT);
+}
+
+// Same descriptor ID should work after service restart.
+TEST_P(EffectFactoryTest, CreateDestroyWithRestart) {
+ std::vector<Descriptor::Identity> ids;
+ EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids));
+ EXPECT_NE(ids.size(), 0UL);
+ creatAndDestroyIds(ids);
+
+ mFactoryHelper->RestartFactoryService();
+
+ connectAndGetFactory();
+ creatAndDestroyIds(ids);
+}
+
+// Effect handle invalid after restart.
+TEST_P(EffectFactoryTest, EffectInvalidAfterRestart) {
+ std::vector<Descriptor::Identity> ids;
+ EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids));
+ EXPECT_NE(ids.size(), 0UL);
+ std::vector<std::shared_ptr<IEffect>> effects = createWithIds(ids);
+
+ ASSERT_NO_FATAL_FAILURE(mFactoryHelper->RestartFactoryService());
+
+ connectAndGetFactory();
+ destroyEffects(effects, EX_ILLEGAL_ARGUMENT);
+}
+
+// expect no error with the queryProcessing interface, but don't check number of processing
+TEST_P(EffectFactoryTest, QueryProcess) {
+ std::vector<Processing> processing;
+ EXPECT_IS_OK(mEffectFactory->queryProcessing(std::nullopt, &processing));
+
+ Processing::Type streamType =
+ Processing::Type::make<Processing::Type::streamType>(AudioStreamType::SYSTEM);
+ std::vector<Processing> processingFilteredByStream;
+ EXPECT_IS_OK(mEffectFactory->queryProcessing(streamType, &processingFilteredByStream));
+
+ Processing::Type source =
+ Processing::Type::make<Processing::Type::source>(AudioSource::DEFAULT);
+ std::vector<Processing> processingFilteredBySource;
+ EXPECT_IS_OK(mEffectFactory->queryProcessing(source, &processingFilteredBySource));
+
+ EXPECT_TRUE(processing.size() >= processingFilteredByStream.size());
+ EXPECT_TRUE(processing.size() >= processingFilteredBySource.size());
+}
+
+INSTANTIATE_TEST_SUITE_P(EffectFactoryTest, EffectFactoryTest,
+ testing::ValuesIn(android::getAidlHalInstanceNames(IFactory::descriptor)),
+ android::PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EffectFactoryTest);
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ ABinderProcess_setThreadPoolMaxThreadCount(1);
+ ABinderProcess_startThreadPool();
+ return RUN_ALL_TESTS();
+}
\ No newline at end of file
diff --git a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
new file mode 100644
index 0000000..8212149
--- /dev/null
+++ b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
@@ -0,0 +1,776 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "VtsHalAudioEffectTargetTest"
+
+#include <chrono>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <Utils.h>
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/audio/effect/IEffect.h>
+#include <aidl/android/hardware/audio/effect/IFactory.h>
+#include <android-base/logging.h>
+#include <android/binder_interface_utils.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <fmq/AidlMessageQueue.h>
+
+#include "AudioHalBinderServiceUtil.h"
+#include "EffectFactoryHelper.h"
+#include "EffectHelper.h"
+#include "TestUtils.h"
+
+using namespace android;
+
+using ndk::ScopedAStatus;
+
+using aidl::android::hardware::audio::effect::CommandId;
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::Parameter;
+using aidl::android::hardware::audio::effect::State;
+
+enum ParamName { PARAM_INSTANCE_NAME };
+using EffectTestParam = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor::Identity>>;
+
+class AudioEffectTest : public testing::TestWithParam<EffectTestParam>, public EffectHelper {
+ public:
+ AudioEffectTest() { std::tie(mFactory, mIdentity) = std::get<PARAM_INSTANCE_NAME>(GetParam()); }
+
+ void SetUp() override {}
+ void TearDown() override {}
+
+ static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+ std::shared_ptr<IFactory> mFactory;
+ Descriptor::Identity mIdentity;
+};
+
+TEST_P(AudioEffectTest, SetupAndTearDown) {
+ // Intentionally empty test body.
+}
+
+TEST_P(AudioEffectTest, CreateAndDestroy) {
+ std::shared_ptr<IEffect> effect;
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+}
+
+TEST_P(AudioEffectTest, OpenAndClose) {
+ std::shared_ptr<IEffect> effect;
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+ ASSERT_NO_FATAL_FAILURE(open(effect));
+ ASSERT_NO_FATAL_FAILURE(close(effect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+}
+
+TEST_P(AudioEffectTest, CloseUnopenedEffect) {
+ std::shared_ptr<IEffect> effect;
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+ ASSERT_NO_FATAL_FAILURE(close(effect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+}
+
+TEST_P(AudioEffectTest, DoubleOpenAndClose) {
+ std::shared_ptr<IEffect> effect1, effect2;
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, effect1, mIdentity));
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, effect2, mIdentity));
+ ASSERT_NO_FATAL_FAILURE(open(effect1));
+ ASSERT_NO_FATAL_FAILURE(open(effect2, 1 /* session */));
+ ASSERT_NO_FATAL_FAILURE(close(effect1));
+ ASSERT_NO_FATAL_FAILURE(close(effect2));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect1));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect2));
+}
+
+TEST_P(AudioEffectTest, TripleOpenAndClose) {
+ std::shared_ptr<IEffect> effect1, effect2, effect3;
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, effect1, mIdentity));
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, effect2, mIdentity));
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, effect3, mIdentity));
+ ASSERT_NO_FATAL_FAILURE(open(effect1));
+ ASSERT_NO_FATAL_FAILURE(open(effect2, 1 /* session */));
+ ASSERT_NO_FATAL_FAILURE(open(effect3, 2 /* session */));
+ ASSERT_NO_FATAL_FAILURE(close(effect1));
+ ASSERT_NO_FATAL_FAILURE(close(effect2));
+ ASSERT_NO_FATAL_FAILURE(close(effect3));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect1));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect2));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect3));
+}
+
+TEST_P(AudioEffectTest, GetDescritorBeforeOpen) {
+ std::shared_ptr<IEffect> effect;
+ Descriptor desc;
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+ ASSERT_NO_FATAL_FAILURE(getDescriptor(effect, desc));
+ EXPECT_EQ(mIdentity.toString(), desc.common.id.toString());
+ EXPECT_NE("", desc.common.name);
+ EXPECT_NE("", desc.common.implementor);
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+}
+
+TEST_P(AudioEffectTest, GetDescritorAfterOpen) {
+ std::shared_ptr<IEffect> effect;
+ Descriptor beforeOpen, afterOpen, afterClose;
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+ ASSERT_NO_FATAL_FAILURE(getDescriptor(effect, beforeOpen));
+ ASSERT_NO_FATAL_FAILURE(open(effect));
+ ASSERT_NO_FATAL_FAILURE(getDescriptor(effect, afterOpen));
+ EXPECT_EQ(beforeOpen.toString(), afterOpen.toString()) << "\n"
+ << beforeOpen.toString() << "\n"
+ << afterOpen.toString();
+ ASSERT_NO_FATAL_FAILURE(close(effect));
+ ASSERT_NO_FATAL_FAILURE(getDescriptor(effect, afterClose));
+ EXPECT_EQ(beforeOpen.toString(), afterClose.toString()) << "\n"
+ << beforeOpen.toString() << "\n"
+ << afterClose.toString();
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+}
+
+TEST_P(AudioEffectTest, DescriptorExistAndUnique) {
+ std::shared_ptr<IEffect> effect;
+ Descriptor desc;
+
+ auto descList = EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor);
+ std::set<Descriptor::Identity> idSet;
+ for (const auto& it : descList) {
+ auto& id = it.second;
+ EXPECT_EQ(0ul, idSet.count(id));
+ idSet.insert(id);
+ }
+
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+ ASSERT_NO_FATAL_FAILURE(getDescriptor(effect, desc));
+ EXPECT_EQ(1ul, idSet.count(desc.common.id));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+}
+
+/// State testing.
+// An effect instance is in INIT state by default after it was created.
+TEST_P(AudioEffectTest, InitStateAfterCreation) {
+ std::shared_ptr<IEffect> effect;
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::INIT));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+}
+
+// An effect instance transfer to IDLE state after IEffect.ASSERT_NO_FATAL_FAILURE(open().
+TEST_P(AudioEffectTest, IdleStateAfterOpen) {
+ std::shared_ptr<IEffect> effect;
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+ ASSERT_NO_FATAL_FAILURE(open(effect));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(close(effect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+}
+
+// An effect instance is in PROCESSING state after it receive an START command.
+TEST_P(AudioEffectTest, ProcessingStateAfterStart) {
+ std::shared_ptr<IEffect> effect;
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::INIT));
+ ASSERT_NO_FATAL_FAILURE(open(effect));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
+ ASSERT_NO_FATAL_FAILURE(close(effect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+}
+
+// An effect instance transfer to IDLE state after Command.Id.STOP in PROCESSING state.
+TEST_P(AudioEffectTest, IdleStateAfterStop) {
+ std::shared_ptr<IEffect> effect;
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+ ASSERT_NO_FATAL_FAILURE(open(effect));
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(close(effect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+}
+
+// An effect instance transfer to IDLE state after Command.Id.RESET in PROCESSING state.
+TEST_P(AudioEffectTest, IdleStateAfterReset) {
+ std::shared_ptr<IEffect> effect;
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+ ASSERT_NO_FATAL_FAILURE(open(effect));
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(close(effect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+}
+
+// An effect instance transfer to INIT after IEffect.ASSERT_NO_FATAL_FAILURE(close().
+TEST_P(AudioEffectTest, InitStateAfterClose) {
+ std::shared_ptr<IEffect> effect;
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+ ASSERT_NO_FATAL_FAILURE(open(effect));
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
+ ASSERT_NO_FATAL_FAILURE(close(effect));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::INIT));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+}
+
+// An effect instance shouldn't accept any command before open.
+TEST_P(AudioEffectTest, NoCommandAcceptedBeforeOpen) {
+ std::shared_ptr<IEffect> effect;
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START, EX_ILLEGAL_STATE));
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP, EX_ILLEGAL_STATE));
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET, EX_ILLEGAL_STATE));
+ ASSERT_NO_FATAL_FAILURE(open(effect));
+ ASSERT_NO_FATAL_FAILURE(close(effect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+}
+
+// No-op when receive STOP command in IDLE state.
+TEST_P(AudioEffectTest, StopCommandInIdleStateNoOp) {
+ std::shared_ptr<IEffect> effect;
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+ ASSERT_NO_FATAL_FAILURE(open(effect));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(close(effect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+}
+
+// No-op when receive RESET command in IDLE state.
+TEST_P(AudioEffectTest, ResetCommandInIdleStateNoOp) {
+ std::shared_ptr<IEffect> effect;
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+ ASSERT_NO_FATAL_FAILURE(open(effect));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(close(effect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+}
+
+// Repeat START and STOP command.
+TEST_P(AudioEffectTest, RepeatStartAndStop) {
+ std::shared_ptr<IEffect> effect;
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+ ASSERT_NO_FATAL_FAILURE(open(effect));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(close(effect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+}
+
+// Repeat START and RESET command.
+TEST_P(AudioEffectTest, RepeatStartAndReset) {
+ std::shared_ptr<IEffect> effect;
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+ ASSERT_NO_FATAL_FAILURE(open(effect));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(close(effect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+}
+
+// Try to close an effect instance at PROCESSING state.
+TEST_P(AudioEffectTest, CloseProcessingStateEffects) {
+ std::shared_ptr<IEffect> effect;
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+ ASSERT_NO_FATAL_FAILURE(open(effect));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+
+ ASSERT_NO_FATAL_FAILURE(close(effect, EX_ILLEGAL_STATE));
+
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(close(effect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+}
+
+// Expect EX_ILLEGAL_STATE if the effect instance is not in a proper state to be destroyed.
+TEST_P(AudioEffectTest, DestroyOpenEffects) {
+ std::shared_ptr<IEffect> effect;
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+ ASSERT_NO_FATAL_FAILURE(open(effect));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect, EX_ILLEGAL_STATE));
+}
+
+// Expect EX_ILLEGAL_STATE if the effect instance is not in a proper state to be destroyed.
+TEST_P(AudioEffectTest, DestroyProcessingEffects) {
+ std::shared_ptr<IEffect> effect;
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+ ASSERT_NO_FATAL_FAILURE(open(effect));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect, EX_ILLEGAL_STATE));
+}
+
+TEST_P(AudioEffectTest, NormalSequenceStates) {
+ std::shared_ptr<IEffect> effect;
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::INIT));
+ ASSERT_NO_FATAL_FAILURE(open(effect));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(close(effect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+}
+
+/// Parameter testing.
+// Verify parameters pass in open can be successfully get.
+TEST_P(AudioEffectTest, VerifyCommonParametersAfterOpen) {
+ std::shared_ptr<IEffect> effect;
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+
+ Parameter::Common common = EffectHelper::createParamCommon();
+ IEffect::OpenEffectReturn ret;
+ ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, EX_NONE));
+
+ Parameter get = Parameter(), expect = Parameter();
+ expect.set<Parameter::common>(common);
+ Parameter::Id id;
+ id.set<Parameter::Id::commonTag>(Parameter::common);
+ EXPECT_IS_OK(effect->getParameter(id, &get));
+ EXPECT_EQ(expect, get) << expect.toString() << " vs " << get.toString();
+
+ ASSERT_NO_FATAL_FAILURE(close(effect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+}
+
+// Verify parameters pass in set can be successfully get.
+TEST_P(AudioEffectTest, SetAndGetCommonParameter) {
+ std::shared_ptr<IEffect> effect;
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+ ASSERT_NO_FATAL_FAILURE(open(effect));
+
+ Parameter::Common common = EffectHelper::createParamCommon(
+ 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */);
+ Parameter get = Parameter(), set = Parameter();
+ set.set<Parameter::common>(common);
+ EXPECT_IS_OK(effect->setParameter(set));
+
+ Parameter::Id id;
+ id.set<Parameter::Id::commonTag>(Parameter::common);
+ EXPECT_IS_OK(effect->getParameter(id, &get));
+ EXPECT_EQ(set, get) << set.toString() << " vs " << get.toString();
+
+ ASSERT_NO_FATAL_FAILURE(close(effect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+}
+
+// Verify parameters set and get in PROCESSING state.
+TEST_P(AudioEffectTest, SetAndGetParameterInProcessing) {
+ std::shared_ptr<IEffect> effect;
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+ ASSERT_NO_FATAL_FAILURE(open(effect));
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+
+ Parameter::Common common = EffectHelper::createParamCommon(
+ 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */);
+ Parameter get = Parameter(), set = Parameter();
+ set.set<Parameter::common>(common);
+ EXPECT_IS_OK(effect->setParameter(set));
+
+ Parameter::Id id;
+ id.set<Parameter::Id::commonTag>(Parameter::common);
+ EXPECT_IS_OK(effect->getParameter(id, &get));
+ EXPECT_EQ(set, get) << set.toString() << " vs " << get.toString();
+
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
+ ASSERT_NO_FATAL_FAILURE(close(effect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+}
+
+// Verify parameters set and get in IDLE state.
+TEST_P(AudioEffectTest, SetAndGetParameterInIdle) {
+ std::shared_ptr<IEffect> effect;
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+ ASSERT_NO_FATAL_FAILURE(open(effect));
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+
+ Parameter::Common common = EffectHelper::createParamCommon(
+ 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */);
+ Parameter get = Parameter(), set = Parameter();
+ set.set<Parameter::common>(common);
+ EXPECT_IS_OK(effect->setParameter(set));
+
+ Parameter::Id id;
+ id.set<Parameter::Id::commonTag>(Parameter::common);
+ EXPECT_IS_OK(effect->getParameter(id, &get));
+ EXPECT_EQ(set, get) << set.toString() << " vs " << get.toString();
+
+ ASSERT_NO_FATAL_FAILURE(close(effect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+}
+
+// Verify Parameters kept after stop.
+TEST_P(AudioEffectTest, SetAndGetParameterAfterStop) {
+ std::shared_ptr<IEffect> effect;
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+ ASSERT_NO_FATAL_FAILURE(open(effect));
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+
+ Parameter::Common common = EffectHelper::createParamCommon(
+ 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */);
+ Parameter get = Parameter(), set = Parameter();
+ set.set<Parameter::common>(common);
+ EXPECT_IS_OK(effect->setParameter(set));
+
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+
+ Parameter::Id id;
+ id.set<Parameter::Id::commonTag>(Parameter::common);
+ EXPECT_IS_OK(effect->getParameter(id, &get));
+ EXPECT_EQ(set, get) << set.toString() << " vs " << get.toString();
+
+ ASSERT_NO_FATAL_FAILURE(close(effect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+}
+
+// Verify Parameters kept after reset.
+TEST_P(AudioEffectTest, SetAndGetParameterAfterReset) {
+ std::shared_ptr<IEffect> effect;
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+ ASSERT_NO_FATAL_FAILURE(open(effect));
+
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+
+ Parameter::Common common = EffectHelper::createParamCommon(
+ 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */);
+ Parameter get = Parameter(), set = Parameter();
+ set.set<Parameter::common>(common);
+ EXPECT_IS_OK(effect->setParameter(set));
+
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+
+ Parameter::Id id;
+ id.set<Parameter::Id::commonTag>(Parameter::common);
+ EXPECT_IS_OK(effect->getParameter(id, &get));
+ EXPECT_EQ(set, get) << set.toString() << " vs " << get.toString();
+
+ ASSERT_NO_FATAL_FAILURE(close(effect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+}
+
+/// Data processing test
+// Send data to effects and expect it to be consumed by checking statusMQ.
+TEST_P(AudioEffectTest, ConsumeDataInProcessingState) {
+ std::shared_ptr<IEffect> effect;
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+
+ Parameter::Common common = EffectHelper::createParamCommon(
+ 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
+ kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
+ IEffect::OpenEffectReturn ret;
+ ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, EX_NONE));
+ auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
+ auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
+ auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
+
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+
+ std::vector<float> buffer;
+ EffectHelper::allocateInputData(common, inputMQ, buffer);
+ EffectHelper::writeToFmq(inputMQ, buffer);
+ EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer);
+
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+
+ ASSERT_NO_FATAL_FAILURE(close(effect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+}
+
+// Send data to effects and expect it to be consumed after effect restart.
+TEST_P(AudioEffectTest, ConsumeDataAfterRestart) {
+ std::shared_ptr<IEffect> effect;
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+
+ Parameter::Common common = EffectHelper::createParamCommon(
+ 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
+ kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
+ IEffect::OpenEffectReturn ret;
+ ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, EX_NONE));
+ auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
+ auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
+ auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
+
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+
+ std::vector<float> buffer;
+ EffectHelper::allocateInputData(common, inputMQ, buffer);
+ EffectHelper::writeToFmq(inputMQ, buffer);
+ EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer);
+
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+
+ ASSERT_NO_FATAL_FAILURE(close(effect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+}
+
+// Send data to IDLE effects and expect it to be consumed after effect start.
+TEST_P(AudioEffectTest, SendDataAtIdleAndConsumeDataInProcessing) {
+ std::shared_ptr<IEffect> effect;
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+
+ Parameter::Common common = EffectHelper::createParamCommon(
+ 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
+ kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
+ IEffect::OpenEffectReturn ret;
+ ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, EX_NONE));
+ auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
+ auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
+ auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
+
+ std::vector<float> buffer;
+ EffectHelper::allocateInputData(common, inputMQ, buffer);
+ EffectHelper::writeToFmq(inputMQ, buffer);
+ EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer);
+
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+
+ EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer);
+
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+
+ ASSERT_NO_FATAL_FAILURE(close(effect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+}
+
+// Send data multiple times.
+TEST_P(AudioEffectTest, ProcessDataMultipleTimes) {
+ std::shared_ptr<IEffect> effect;
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+
+ Parameter::Common common = EffectHelper::createParamCommon(
+ 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
+ kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
+ IEffect::OpenEffectReturn ret;
+ ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, EX_NONE));
+ auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
+ auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
+ auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
+
+ std::vector<float> buffer;
+ EffectHelper::allocateInputData(common, inputMQ, buffer);
+ EffectHelper::writeToFmq(inputMQ, buffer);
+ EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer);
+
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+
+ EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer);
+ // expect no status and data after consume
+ EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer);
+
+ EffectHelper::writeToFmq(inputMQ, buffer);
+ EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer);
+ // expect no status and data after consume
+ EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer);
+
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+
+ ASSERT_NO_FATAL_FAILURE(close(effect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+}
+
+// Send data to IDLE state effects and expect it not be consumed.
+TEST_P(AudioEffectTest, NotConsumeDataInIdleState) {
+ std::shared_ptr<IEffect> effect;
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+
+ Parameter::Common common = EffectHelper::createParamCommon(
+ 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
+ kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
+ IEffect::OpenEffectReturn ret;
+ ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, EX_NONE));
+ auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
+ auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
+ auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
+
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+
+ std::vector<float> buffer;
+ EffectHelper::allocateInputData(common, inputMQ, buffer);
+ EffectHelper::writeToFmq(inputMQ, buffer);
+ EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer);
+
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+ EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer);
+
+ ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+
+ ASSERT_NO_FATAL_FAILURE(close(effect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+}
+
+// Send data to closed effects and expect it not be consumed.
+TEST_P(AudioEffectTest, NotConsumeDataByClosedEffect) {
+ std::shared_ptr<IEffect> effect;
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+
+ Parameter::Common common = EffectHelper::createParamCommon(
+ 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
+ kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
+ IEffect::OpenEffectReturn ret;
+ ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, EX_NONE));
+ ASSERT_NO_FATAL_FAILURE(close(effect));
+
+ auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
+ auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
+ auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
+
+ std::vector<float> buffer;
+ EffectHelper::allocateInputData(common, inputMQ, buffer);
+ EffectHelper::writeToFmq(inputMQ, buffer);
+ EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer);
+
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+}
+
+// Send data to multiple effects.
+TEST_P(AudioEffectTest, ConsumeDataMultipleEffects) {
+ std::shared_ptr<IEffect> effect1, effect2;
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, effect1, mIdentity));
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, effect2, mIdentity));
+
+ Parameter::Common common1 = EffectHelper::createParamCommon(
+ 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
+ kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
+ Parameter::Common common2 = EffectHelper::createParamCommon(
+ 1 /* session */, 1 /* ioHandle */, 48000 /* iSampleRate */, 48000 /* oSampleRate */,
+ 2 * kInputFrameCount /* iFrameCount */, 2 * kOutputFrameCount /* oFrameCount */);
+ IEffect::OpenEffectReturn ret1, ret2;
+ ASSERT_NO_FATAL_FAILURE(open(effect1, common1, std::nullopt /* specific */, &ret1, EX_NONE));
+ ASSERT_NO_FATAL_FAILURE(open(effect2, common2, std::nullopt /* specific */, &ret2, EX_NONE));
+ ASSERT_NO_FATAL_FAILURE(command(effect1, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect1, State::PROCESSING));
+ ASSERT_NO_FATAL_FAILURE(command(effect2, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect2, State::PROCESSING));
+
+ auto statusMQ1 = std::make_unique<EffectHelper::StatusMQ>(ret1.statusMQ);
+ auto inputMQ1 = std::make_unique<EffectHelper::DataMQ>(ret1.inputDataMQ);
+ auto outputMQ1 = std::make_unique<EffectHelper::DataMQ>(ret1.outputDataMQ);
+
+ std::vector<float> buffer1, buffer2;
+ EffectHelper::allocateInputData(common1, inputMQ1, buffer1);
+ EffectHelper::writeToFmq(inputMQ1, buffer1);
+ EffectHelper::readFromFmq(statusMQ1, 1, outputMQ1, buffer1.size(), buffer1);
+
+ auto statusMQ2 = std::make_unique<EffectHelper::StatusMQ>(ret2.statusMQ);
+ auto inputMQ2 = std::make_unique<EffectHelper::DataMQ>(ret2.inputDataMQ);
+ auto outputMQ2 = std::make_unique<EffectHelper::DataMQ>(ret2.outputDataMQ);
+ EffectHelper::allocateInputData(common2, inputMQ2, buffer2);
+ EffectHelper::writeToFmq(inputMQ2, buffer2);
+ EffectHelper::readFromFmq(statusMQ2, 1, outputMQ2, buffer2.size(), buffer2);
+
+ ASSERT_NO_FATAL_FAILURE(command(effect1, CommandId::STOP));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect1, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(close(effect1));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect1));
+
+ ASSERT_NO_FATAL_FAILURE(command(effect2, CommandId::STOP));
+ ASSERT_NO_FATAL_FAILURE(expectState(effect2, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(close(effect2));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect2));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ SingleEffectInstanceTest, AudioEffectTest,
+ ::testing::Combine(testing::ValuesIn(
+ EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor))),
+ [](const testing::TestParamInfo<AudioEffectTest::ParamType>& info) {
+ auto msSinceEpoch = std::chrono::duration_cast<std::chrono::nanoseconds>(
+ std::chrono::system_clock::now().time_since_epoch())
+ .count();
+ auto instance = std::get<PARAM_INSTANCE_NAME>(info.param);
+ std::ostringstream address;
+ address << msSinceEpoch << "_factory_" << instance.first.get();
+ std::string name = address.str() + "_UUID_timeLow_" +
+ ::android::internal::ToString(instance.second.uuid.timeLow) +
+ "_timeMid_" +
+ ::android::internal::ToString(instance.second.uuid.timeMid);
+ std::replace_if(
+ name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+ return name;
+ });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioEffectTest);
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ ABinderProcess_setThreadPoolMaxThreadCount(1);
+ ABinderProcess_startThreadPool();
+ return RUN_ALL_TESTS();
+}
diff --git a/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp b/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp
new file mode 100644
index 0000000..f19dff6
--- /dev/null
+++ b/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <algorithm>
+#include <limits>
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#define LOG_TAG "VtsHalEqualizerTest"
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android/binder_interface_utils.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <gtest/gtest.h>
+
+#include <Utils.h>
+#include <aidl/android/hardware/audio/effect/IEffect.h>
+#include <aidl/android/hardware/audio/effect/IFactory.h>
+
+#include "AudioHalBinderServiceUtil.h"
+#include "EffectHelper.h"
+#include "TestUtils.h"
+#include "effect-impl/EffectUUID.h"
+
+using namespace android;
+
+using aidl::android::hardware::audio::effect::Capability;
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::Equalizer;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::kEqualizerTypeUUID;
+using aidl::android::hardware::audio::effect::Parameter;
+
+/**
+ * Here we focus on specific effect (equalizer) parameter checking, general IEffect interfaces
+ * testing performed in VtsAudioEfectTargetTest.
+ */
+
+enum ParamName { PARAM_INSTANCE_NAME, PARAM_BAND_LEVEL };
+using EqualizerParamTestParam =
+ std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor::Identity>, int>;
+
+/*
+Testing parameter range, assuming the parameter supported by effect is in this range.
+This range is verified with IEffect.getDescriptor(), for any index supported vts expect EX_NONE
+from IEffect.setParameter(), otherwise expect EX_ILLEGAL_ARGUMENT.
+*/
+const std::vector<int> kBandLevels = {0, -10, 10}; // needs update with implementation
+
+class EqualizerTest : public ::testing::TestWithParam<EqualizerParamTestParam>,
+ public EffectHelper {
+ public:
+ EqualizerTest() : mBandLevel(std::get<PARAM_BAND_LEVEL>(GetParam())) {
+ std::tie(mFactory, mIdentity) = std::get<PARAM_INSTANCE_NAME>(GetParam());
+ }
+
+ void SetUp() override {
+ ASSERT_NE(nullptr, mFactory);
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mIdentity));
+
+ Parameter::Specific specific = getDefaultParamSpecific();
+ Parameter::Common common = EffectHelper::createParamCommon(
+ 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
+ kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
+ IEffect::OpenEffectReturn ret;
+ ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &ret, EX_NONE));
+ ASSERT_NE(nullptr, mEffect);
+ ASSERT_NO_FATAL_FAILURE(setTagRange());
+ }
+ void TearDown() override {
+ ASSERT_NO_FATAL_FAILURE(close(mEffect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+ }
+
+ std::pair<int, int> setPresetIndexRange(const Equalizer::Capability& cap) const {
+ const auto [min, max] =
+ std::minmax_element(cap.presets.begin(), cap.presets.end(),
+ [](const auto& a, const auto& b) { return a.index < b.index; });
+ return {min->index, max->index};
+ }
+ std::pair<int, int> setBandIndexRange(const Equalizer::Capability& cap) const {
+ const auto [min, max] =
+ std::minmax_element(cap.bandFrequencies.begin(), cap.bandFrequencies.end(),
+ [](const auto& a, const auto& b) { return a.index < b.index; });
+ return {min->index, max->index};
+ }
+ void setTagRange() {
+ Descriptor desc;
+ ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
+ Equalizer::Capability& eqCap = desc.capability.get<Capability::equalizer>();
+ mPresetIndex = setPresetIndexRange(eqCap);
+ mBandIndex = setBandIndexRange(eqCap);
+ }
+
+ static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+ std::shared_ptr<IFactory> mFactory;
+ std::shared_ptr<IEffect> mEffect;
+ Descriptor::Identity mIdentity;
+ std::pair<int, int> mPresetIndex;
+ std::pair<int, int> mBandIndex;
+ const int mBandLevel;
+ Descriptor mDesc;
+
+ void SetAndGetEqualizerParameters() {
+ ASSERT_NE(nullptr, mEffect);
+ for (auto& it : mTags) {
+ auto& tag = it.first;
+ auto& eq = it.second;
+
+ // validate parameter
+ const bool valid = isTagInRange(it.first, it.second);
+ const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
+
+ // set
+ Parameter expectParam;
+ Parameter::Specific specific;
+ specific.set<Parameter::Specific::equalizer>(eq);
+ expectParam.set<Parameter::specific>(specific);
+ EXPECT_STATUS(expected, mEffect->setParameter(expectParam))
+ << expectParam.toString() << "\n"
+ << mDesc.toString();
+
+ // only get if parameter in range and set success
+ if (expected == EX_NONE) {
+ Parameter getParam;
+ Parameter::Id id;
+ Equalizer::Id eqId;
+ eqId.set<Equalizer::Id::commonTag>(tag);
+ id.set<Parameter::Id::equalizerTag>(eqId);
+ // if set success, then get should match
+ EXPECT_STATUS(expected, mEffect->getParameter(id, &getParam));
+ EXPECT_TRUE(isEqParameterExpected(expectParam, getParam))
+ << "\nexpect:" << expectParam.toString()
+ << "\ngetParam:" << getParam.toString();
+ }
+ }
+ }
+
+ bool isEqParameterExpected(const Parameter& expect, const Parameter& target) {
+ // if parameter same, then for sure they are matched
+ if (expect == target) return true;
+
+ // if not, see if target include the expect parameter, and others all default (0).
+ /*
+ * This is to verify the case of client setParameter to a single bandLevel ({3, -1} for
+ * example), and return of getParameter must be [{0, 0}, {1, 0}, {2, 0}, {3, -1}, {4, 0}]
+ */
+ EXPECT_EQ(expect.getTag(), Parameter::specific);
+ EXPECT_EQ(target.getTag(), Parameter::specific);
+
+ Parameter::Specific expectSpec = expect.get<Parameter::specific>(),
+ targetSpec = target.get<Parameter::specific>();
+ EXPECT_EQ(expectSpec.getTag(), Parameter::Specific::equalizer);
+ EXPECT_EQ(targetSpec.getTag(), Parameter::Specific::equalizer);
+
+ Equalizer expectEq = expectSpec.get<Parameter::Specific::equalizer>(),
+ targetEq = targetSpec.get<Parameter::Specific::equalizer>();
+ EXPECT_EQ(expectEq.getTag(), targetEq.getTag());
+
+ auto eqTag = targetEq.getTag();
+ switch (eqTag) {
+ case Equalizer::bandLevels: {
+ auto expectBl = expectEq.get<Equalizer::bandLevels>();
+ std::sort(expectBl.begin(), expectBl.end(),
+ [](const auto& a, const auto& b) { return a.index < b.index; });
+ expectBl.erase(std::unique(expectBl.begin(), expectBl.end()), expectBl.end());
+ auto targetBl = targetEq.get<Equalizer::bandLevels>();
+ return std::includes(targetBl.begin(), targetBl.end(), expectBl.begin(),
+ expectBl.end());
+ }
+ case Equalizer::preset: {
+ return expectEq.get<Equalizer::preset>() == targetEq.get<Equalizer::preset>();
+ }
+ default:
+ return false;
+ }
+ return false;
+ }
+
+ void addPresetParam(int preset) {
+ Equalizer eq;
+ eq.set<Equalizer::preset>(preset);
+ mTags.push_back({Equalizer::preset, eq});
+ }
+
+ void addBandLevelsParam(std::vector<Equalizer::BandLevel>& bandLevels) {
+ Equalizer eq;
+ eq.set<Equalizer::bandLevels>(bandLevels);
+ mTags.push_back({Equalizer::bandLevels, eq});
+ }
+
+ bool isTagInRange(const Equalizer::Tag& tag, const Equalizer& eq) const {
+ switch (tag) {
+ case Equalizer::preset: {
+ int index = eq.get<Equalizer::preset>();
+ return index >= mPresetIndex.first && index <= mPresetIndex.second;
+ }
+ case Equalizer::bandLevels: {
+ auto& bandLevel = eq.get<Equalizer::bandLevels>();
+ return isBandInRange(bandLevel);
+ }
+ default:
+ return false;
+ }
+ return false;
+ }
+
+ bool isBandInRange(const std::vector<Equalizer::BandLevel>& bandLevel) const {
+ for (auto& it : bandLevel) {
+ if (it.index < mBandIndex.first || it.index > mBandIndex.second) return false;
+ }
+ return true;
+ }
+
+ Parameter::Specific getDefaultParamSpecific() {
+ Equalizer eq = Equalizer::make<Equalizer::preset>(0);
+ Parameter::Specific specific =
+ Parameter::Specific::make<Parameter::Specific::equalizer>(eq);
+ return specific;
+ }
+
+ private:
+ std::vector<std::pair<Equalizer::Tag, Equalizer>> mTags;
+
+ bool validCapabilityTag(Capability& cap) { return cap.getTag() == Capability::equalizer; }
+
+ void CleanUp() { mTags.clear(); }
+};
+
+TEST_P(EqualizerTest, SetAndGetPresetOutOfLowerBound) {
+ addPresetParam(mPresetIndex.second - 1);
+ ASSERT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
+}
+
+TEST_P(EqualizerTest, SetAndGetPresetOutOfUpperBound) {
+ addPresetParam(mPresetIndex.second + 1);
+ EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
+}
+
+TEST_P(EqualizerTest, SetAndGetPresetAtLowerBound) {
+ addPresetParam(mPresetIndex.first);
+ EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
+}
+
+TEST_P(EqualizerTest, SetAndGetPresetAtHigherBound) {
+ addPresetParam(mPresetIndex.second);
+ EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
+}
+
+TEST_P(EqualizerTest, SetAndGetPresetInBound) {
+ addPresetParam((mPresetIndex.first + mPresetIndex.second) >> 1);
+ EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
+}
+
+TEST_P(EqualizerTest, SetAndGetBandOutOfLowerBound) {
+ std::vector<Equalizer::BandLevel> bandLevels{{mBandIndex.first - 1, mBandLevel}};
+ addBandLevelsParam(bandLevels);
+ EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
+}
+
+TEST_P(EqualizerTest, SetAndGetBandOutOfUpperBound) {
+ std::vector<Equalizer::BandLevel> bandLevels{{mBandIndex.second + 1, mBandLevel}};
+ addBandLevelsParam(bandLevels);
+ EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
+}
+
+TEST_P(EqualizerTest, SetAndGetBandAtLowerBound) {
+ std::vector<Equalizer::BandLevel> bandLevels{{mBandIndex.first, mBandLevel}};
+ addBandLevelsParam(bandLevels);
+ EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
+}
+
+TEST_P(EqualizerTest, SetAndGetBandAtHigherBound) {
+ std::vector<Equalizer::BandLevel> bandLevels{{mBandIndex.second, mBandLevel}};
+ addBandLevelsParam(bandLevels);
+ EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
+}
+
+TEST_P(EqualizerTest, SetAndGetBandInBound) {
+ std::vector<Equalizer::BandLevel> bandLevels{
+ {(mBandIndex.first + mBandIndex.second) >> 1, mBandLevel}};
+ addBandLevelsParam(bandLevels);
+ EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
+}
+
+TEST_P(EqualizerTest, SetAndGetMultiBands) {
+ addPresetParam(mPresetIndex.first);
+ std::vector<Equalizer::BandLevel> bandLevels{
+ {mBandIndex.first, mBandLevel},
+ {mBandIndex.second, mBandLevel},
+ {(mBandIndex.first + mBandIndex.second) >> 1, mBandLevel}};
+ addBandLevelsParam(bandLevels);
+ EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
+}
+
+TEST_P(EqualizerTest, SetAndGetMultipleParams) {
+ std::vector<Equalizer::BandLevel> bandLevels{
+ {(mBandIndex.first + mBandIndex.second) >> 1, mBandLevel}};
+ addBandLevelsParam(bandLevels);
+ addPresetParam((mPresetIndex.first + mPresetIndex.second) >> 1);
+ EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ EqualizerTest, EqualizerTest,
+ ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+ IFactory::descriptor, kEqualizerTypeUUID)),
+ testing::ValuesIn(kBandLevels)),
+ [](const testing::TestParamInfo<EqualizerTest::ParamType>& info) {
+ auto msSinceEpoch = std::chrono::duration_cast<std::chrono::nanoseconds>(
+ std::chrono::system_clock::now().time_since_epoch())
+ .count();
+ auto instance = std::get<PARAM_INSTANCE_NAME>(info.param);
+ std::string bandLevel = std::to_string(std::get<PARAM_BAND_LEVEL>(info.param));
+ std::ostringstream address;
+ address << msSinceEpoch << "_factory_" << instance.first.get();
+ std::string name = address.str() + "_UUID_timeLow_" +
+ ::android::internal::ToString(instance.second.uuid.timeLow) +
+ "_timeMid_" +
+ ::android::internal::ToString(instance.second.uuid.timeMid) +
+ "_bandLevel_" + bandLevel;
+ std::replace_if(
+ name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+ return name;
+ });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EqualizerTest);
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ ABinderProcess_setThreadPoolMaxThreadCount(1);
+ ABinderProcess_startThreadPool();
+ return RUN_ALL_TESTS();
+}
diff --git a/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp b/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp
new file mode 100644
index 0000000..1485657
--- /dev/null
+++ b/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/Vintf.h>
+
+#define LOG_TAG "VtsHalLoudnessEnhancerTest"
+
+#include <Utils.h>
+#include "EffectHelper.h"
+
+using namespace android;
+
+using aidl::android::hardware::audio::effect::Capability;
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::kLoudnessEnhancerTypeUUID;
+using aidl::android::hardware::audio::effect::LoudnessEnhancer;
+using aidl::android::hardware::audio::effect::Parameter;
+
+/**
+ * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
+ * VtsAudioEffectTargetTest.
+ */
+enum ParamName { PARAM_INSTANCE_NAME, PARAM_GAIN_MB };
+using LoudnessEnhancerParamTestParam =
+ std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor::Identity>, int>;
+
+// Every int 32 bit value is a valid gain, so testing the corner cases and one regular value.
+// TODO : Update the test values once range/capability is updated by implementation.
+const std::vector<int> kGainMbValues = {std::numeric_limits<int>::min(), 100,
+ std::numeric_limits<int>::max()};
+
+class LoudnessEnhancerParamTest : public ::testing::TestWithParam<LoudnessEnhancerParamTestParam>,
+ public EffectHelper {
+ public:
+ LoudnessEnhancerParamTest() : mParamGainMb(std::get<PARAM_GAIN_MB>(GetParam())) {
+ std::tie(mFactory, mIdentity) = std::get<PARAM_INSTANCE_NAME>(GetParam());
+ }
+
+ void SetUp() override {
+ ASSERT_NE(nullptr, mFactory);
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mIdentity));
+
+ Parameter::Specific specific = getDefaultParamSpecific();
+ Parameter::Common common = EffectHelper::createParamCommon(
+ 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
+ kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
+ IEffect::OpenEffectReturn ret;
+ ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &ret, EX_NONE));
+ ASSERT_NE(nullptr, mEffect);
+ }
+ void TearDown() override {
+ ASSERT_NO_FATAL_FAILURE(close(mEffect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+ }
+
+ Parameter::Specific getDefaultParamSpecific() {
+ LoudnessEnhancer le = LoudnessEnhancer::make<LoudnessEnhancer::gainMb>(0);
+ Parameter::Specific specific =
+ Parameter::Specific::make<Parameter::Specific::loudnessEnhancer>(le);
+ return specific;
+ }
+
+ static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+ std::shared_ptr<IFactory> mFactory;
+ std::shared_ptr<IEffect> mEffect;
+ Descriptor::Identity mIdentity;
+ int mParamGainMb = 0;
+
+ void SetAndGetParameters() {
+ for (auto& it : mTags) {
+ auto& tag = it.first;
+ auto& le = it.second;
+
+ // set parameter
+ Parameter expectParam;
+ Parameter::Specific specific;
+ specific.set<Parameter::Specific::loudnessEnhancer>(le);
+ expectParam.set<Parameter::specific>(specific);
+ // All values are valid, set parameter should succeed
+ EXPECT_STATUS(EX_NONE, mEffect->setParameter(expectParam)) << expectParam.toString();
+
+ // get parameter
+ Parameter getParam;
+ Parameter::Id id;
+ LoudnessEnhancer::Id leId;
+ leId.set<LoudnessEnhancer::Id::commonTag>(tag);
+ id.set<Parameter::Id::loudnessEnhancerTag>(leId);
+ EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &getParam));
+
+ EXPECT_EQ(expectParam, getParam) << "\nexpect:" << expectParam.toString()
+ << "\ngetParam:" << getParam.toString();
+ }
+ }
+
+ void addGainMbParam(int gainMb) {
+ LoudnessEnhancer le;
+ le.set<LoudnessEnhancer::gainMb>(gainMb);
+ mTags.push_back({LoudnessEnhancer::gainMb, le});
+ }
+
+ private:
+ std::vector<std::pair<LoudnessEnhancer::Tag, LoudnessEnhancer>> mTags;
+ void CleanUp() { mTags.clear(); }
+};
+
+TEST_P(LoudnessEnhancerParamTest, SetAndGetGainMb) {
+ EXPECT_NO_FATAL_FAILURE(addGainMbParam(mParamGainMb));
+ SetAndGetParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ LoudnessEnhancerTest, LoudnessEnhancerParamTest,
+ ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+ IFactory::descriptor, kLoudnessEnhancerTypeUUID)),
+ testing::ValuesIn(kGainMbValues)),
+ [](const testing::TestParamInfo<LoudnessEnhancerParamTest::ParamType>& info) {
+ auto msSinceEpoch = std::chrono::duration_cast<std::chrono::nanoseconds>(
+ std::chrono::system_clock::now().time_since_epoch())
+ .count();
+ auto instance = std::get<PARAM_INSTANCE_NAME>(info.param);
+ std::string gainMb = std::to_string(std::get<PARAM_GAIN_MB>(info.param));
+
+ std::ostringstream address;
+ address << msSinceEpoch << "_factory_" << instance.first.get();
+ std::string name = address.str() + "_UUID_timeLow_" +
+ ::android::internal::ToString(instance.second.uuid.timeLow) +
+ "_timeMid_" +
+ ::android::internal::ToString(instance.second.uuid.timeMid) +
+ "_gainMb" + gainMb;
+ std::replace_if(
+ name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+ return name;
+ });
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(LoudnessEnhancerParamTest);
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ ABinderProcess_setThreadPoolMaxThreadCount(1);
+ ABinderProcess_startThreadPool();
+ return RUN_ALL_TESTS();
+}
diff --git a/audio/common/5.0/Android.bp b/audio/common/5.0/Android.bp
index fd8e85f..a6bb331 100644
--- a/audio/common/5.0/Android.bp
+++ b/audio/common/5.0/Android.bp
@@ -22,6 +22,6 @@
gen_java_constants: true,
apex_available: [
"//apex_available:platform",
- "com.android.bluetooth",
+ "com.android.btservices",
],
}
diff --git a/audio/common/all-versions/default/tests/hidlutils_tests.cpp b/audio/common/all-versions/default/tests/hidlutils_tests.cpp
index e6e2280..93688fc 100644
--- a/audio/common/all-versions/default/tests/hidlutils_tests.cpp
+++ b/audio/common/all-versions/default/tests/hidlutils_tests.cpp
@@ -1127,8 +1127,12 @@
TypeParam emptyTags;
EXPECT_EQ(emptyTags, HidlUtils::filterOutNonVendorTags(emptyTags));
- TypeParam allVendorTags = {{"VX_GOOGLE_VR_42", "VX_GOOGLE_1E100"}};
- EXPECT_EQ(allVendorTags, HidlUtils::filterOutNonVendorTags(allVendorTags));
+ // b/248421569, allocate two vendor tags at a time can run out of memory
+ // TypeParam allVendorTags = {{"VX_GOOGLE_VR_42", "VX_GOOGLE_1E100"}};
+ TypeParam allVendorTags1 = {{"VX_GOOGLE_VR_42"}};
+ EXPECT_EQ(allVendorTags1, HidlUtils::filterOutNonVendorTags(allVendorTags1));
+ TypeParam allVendorTags2 = {{"VX_GOOGLE_1E100"}};
+ EXPECT_EQ(allVendorTags2, HidlUtils::filterOutNonVendorTags(allVendorTags2));
TypeParam oneVendorTag = {{"", "VX_GOOGLE_VR", "random_string"}};
TypeParam oneVendorTagOnly = HidlUtils::filterOutNonVendorTags(oneVendorTag);
diff --git a/audio/common/all-versions/test/utility/src/ValidateXml.cpp b/audio/common/all-versions/test/utility/src/ValidateXml.cpp
index f111c01..4d6f003 100644
--- a/audio/common/all-versions/test/utility/src/ValidateXml.cpp
+++ b/audio/common/all-versions/test/utility/src/ValidateXml.cpp
@@ -63,11 +63,8 @@
xmlSetGenericErrorFunc(this, errorCb);
}
~Libxml2Global() {
- // TODO: check if all those cleanup are needed
xmlSetGenericErrorFunc(nullptr, nullptr);
- xmlSchemaCleanupTypes();
xmlCleanupParser();
- xmlCleanupThreads();
}
const std::string& getErrors() { return errors; }
diff --git a/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
index 505c54c..55d4e1d 100644
--- a/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
@@ -957,10 +957,16 @@
ASSERT_NO_FATAL_FAILURE(createPatchIfNeeded());
const int presentationeEndPrecisionMs = 1000;
const int sampleRate = 44100;
+ // The duration of sine882hz3s.mp3 is: 3 seconds + (576 + 756) samples.
+ // This is a mono file, thus 1 frame = 1 sample for it.
+ const int fullTrackDurationMs = 3000 + (576 + 756) * 1000 / sampleRate;
const int significantSampleNumber = (presentationeEndPrecisionMs * sampleRate) / 1000;
+ // 'delay' is the amount of frames ignored at the beginning, 'padding' is the amount of frames
+ // ignored at the end of the track. Extra 1000 samples are requested for trimming to reduce the
+ // test running time.
const int delay = 576 + 1000;
const int padding = 756 + 1000;
- const int durationMs = 3000 - 44;
+ const int durationMs = fullTrackDurationMs - (delay + padding) * 1000 / sampleRate;
auto start = std::chrono::steady_clock::now();
auto callbacks = sp<OffloadCallbacks>::make();
std::mutex presentationEndLock;
diff --git a/audio/core/all-versions/vts/functional/Android.bp b/audio/core/all-versions/vts/functional/Android.bp
index daed7a8..f51a8d0 100644
--- a/audio/core/all-versions/vts/functional/Android.bp
+++ b/audio/core/all-versions/vts/functional/Android.bp
@@ -49,7 +49,10 @@
cc_test {
name: "VtsHalAudioV2_0TargetTest",
- defaults: ["VtsHalAudioTargetTest_defaults"],
+ defaults: [
+ "VtsHalAudioTargetTest_defaults",
+ "latest_android_media_audio_common_types_cpp_static",
+ ],
tidy_timeout_srcs: [
"2.0/AudioPrimaryHidlHalTest.cpp",
],
@@ -62,7 +65,6 @@
"libmedia_helper",
"android.hardware.audio@2.0",
"android.hardware.audio.common@2.0",
- "android.media.audio.common.types-V1-cpp",
],
cflags: [
"-DMAJOR_VERSION=2",
@@ -79,7 +81,10 @@
cc_test {
name: "VtsHalAudioV4_0TargetTest",
- defaults: ["VtsHalAudioTargetTest_defaults"],
+ defaults: [
+ "VtsHalAudioTargetTest_defaults",
+ "latest_android_media_audio_common_types_cpp_static",
+ ],
tidy_timeout_srcs: [
"4.0/AudioPrimaryHidlHalTest.cpp",
],
@@ -92,7 +97,6 @@
"libmedia_helper",
"android.hardware.audio@4.0",
"android.hardware.audio.common@4.0",
- "android.media.audio.common.types-V1-cpp",
],
cflags: [
"-DMAJOR_VERSION=4",
@@ -109,7 +113,10 @@
cc_test {
name: "VtsHalAudioV5_0TargetTest",
- defaults: ["VtsHalAudioTargetTest_defaults"],
+ defaults: [
+ "VtsHalAudioTargetTest_defaults",
+ "latest_android_media_audio_common_types_cpp_static",
+ ],
srcs: [
"5.0/AudioPrimaryHidlHalTest.cpp",
],
@@ -119,7 +126,6 @@
"libmedia_helper",
"android.hardware.audio@5.0",
"android.hardware.audio.common@5.0",
- "android.media.audio.common.types-V1-cpp",
],
cflags: [
"-DMAJOR_VERSION=5",
@@ -136,7 +142,10 @@
cc_test {
name: "VtsHalAudioV6_0TargetTest",
- defaults: ["VtsHalAudioTargetTest_defaults"],
+ defaults: [
+ "VtsHalAudioTargetTest_defaults",
+ "latest_android_media_audio_common_types_cpp_static",
+ ],
tidy_timeout_srcs: [
"6.0/AudioPrimaryHidlHalTest.cpp",
],
@@ -150,7 +159,6 @@
"libmedia_helper",
"android.hardware.audio@6.0",
"android.hardware.audio.common@6.0",
- "android.media.audio.common.types-V1-cpp",
],
cflags: [
"-DMAJOR_VERSION=6",
@@ -244,7 +252,10 @@
cc_test {
name: "HalAudioV6_0GeneratorTest",
- defaults: ["VtsHalAudioTargetTest_defaults"],
+ defaults: [
+ "VtsHalAudioTargetTest_defaults",
+ "latest_android_media_audio_common_types_cpp_static",
+ ],
srcs: [
"6.0/Generators.cpp",
"tests/generators_tests.cpp",
@@ -252,7 +263,6 @@
static_libs: [
"android.hardware.audio@6.0",
"android.hardware.audio.common@6.0",
- "android.media.audio.common.types-V1-cpp",
"libaudiofoundation",
"libaudiopolicycomponents",
"libmedia_helper",
diff --git a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
index e46e5b4..98e49a2 100644
--- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
+++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
@@ -1014,9 +1014,8 @@
if (mDataPosition == 0) mOnDataStart();
const size_t dataSize = std::min(mData.size() - mDataPosition, mDataMQ->availableToWrite());
bool success = mDataMQ->write(mData.data() + mDataPosition, dataSize);
+ bool wrapped = false;
ALOGE_IF(!success, "data message queue write failed");
- mDataPosition += dataSize;
- if (mDataPosition >= mData.size()) mDataPosition = 0;
mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
uint32_t efState = 0;
@@ -1034,6 +1033,11 @@
ALOGE("bad write status: %d", writeStatus.retval);
success = false;
}
+ mDataPosition += writeStatus.reply.written;
+ if (mDataPosition >= mData.size()) {
+ mDataPosition = 0;
+ wrapped = true;
+ }
}
if (ret == -EAGAIN || ret == -EINTR) {
// Spurious wakeup. This normally retries no more than once.
@@ -1042,7 +1046,7 @@
ALOGE("bad wait status: %d", ret);
success = false;
}
- if (success && mDataPosition == 0) {
+ if (wrapped) {
success = mOnDataWrap();
}
return success;
@@ -1270,6 +1274,8 @@
if (!xsd::isTelephonyDevice(address.deviceType)) {
metadata.source = toString(xsd::AudioSource::AUDIO_SOURCE_UNPROCESSED);
metadata.channelMask = getConfig().base.channelMask;
+ } else {
+ address.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_IN_DEFAULT);
}
#if MAJOR_VERSION == 7 && MINOR_VERSION >= 1
auto flagsIt = std::find(flags.begin(), flags.end(),
diff --git a/audio/policy/1.0/xml/api/current.txt b/audio/policy/1.0/xml/api/current.txt
index 0b77d45..84a2b71 100644
--- a/audio/policy/1.0/xml/api/current.txt
+++ b/audio/policy/1.0/xml/api/current.txt
@@ -217,6 +217,10 @@
enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_GAME;
enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_MEDIA;
enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_NOTIFICATION;
+ enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED;
+ enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT;
+ enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST;
+ enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_NOTIFICATION_EVENT;
enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE;
enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_UNKNOWN;
enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_VIRTUAL_SOURCE;
diff --git a/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd b/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd
index 3ce12e7..b58a6c8 100644
--- a/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd
+++ b/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd
@@ -347,6 +347,11 @@
<xs:enumeration value="AUDIO_USAGE_ALARM"/>
<xs:enumeration value="AUDIO_USAGE_NOTIFICATION"/>
<xs:enumeration value="AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE"/>
+ <!-- Note: the following 3 values were deprecated in Android T (13) SDK -->
+ <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST"/>
+ <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT"/>
+ <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED"/>
+ <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_EVENT"/>
<xs:enumeration value="AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY"/>
<xs:enumeration value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE"/>
<xs:enumeration value="AUDIO_USAGE_ASSISTANCE_SONIFICATION"/>
diff --git a/authsecret/aidl/Android.bp b/authsecret/aidl/Android.bp
index 432c1b9..90e128d 100644
--- a/authsecret/aidl/Android.bp
+++ b/authsecret/aidl/Android.bp
@@ -16,11 +16,6 @@
java: {
platform_apis: true,
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
versions: ["1"],
}
diff --git a/automotive/OWNERS b/automotive/OWNERS
index 43c5f3e..09e257c 100644
--- a/automotive/OWNERS
+++ b/automotive/OWNERS
@@ -1,6 +1 @@
-pirozzoj@google.com
-twasilczyk@google.com
-krachuri@google.com
-gurunagarajan@google.com
-keunyoung@google.com
-felipeal@google.com
+include platform/packages/services/Car:/OWNERS
diff --git a/automotive/audiocontrol/OWNERS b/automotive/audiocontrol/OWNERS
new file mode 100644
index 0000000..f55eff3
--- /dev/null
+++ b/automotive/audiocontrol/OWNERS
@@ -0,0 +1 @@
+oscarazu@google.com
diff --git a/automotive/audiocontrol/aidl/Android.bp b/automotive/audiocontrol/aidl/Android.bp
index e5f7a4f..03dab08 100644
--- a/automotive/audiocontrol/aidl/Android.bp
+++ b/automotive/audiocontrol/aidl/Android.bp
@@ -15,7 +15,7 @@
srcs: ["android/hardware/automotive/audiocontrol/*.aidl"],
imports: [
"android.hardware.audio.common-V1",
- "android.media.audio.common.types-V1",
+ "android.media.audio.common.types-V2",
],
stability: "vintf",
backend: {
@@ -33,14 +33,14 @@
version: "1",
imports: [
"android.hardware.audio.common-V1",
- "android.media.audio.common.types-V1",
+ "android.media.audio.common.types-V2",
],
},
{
version: "2",
imports: [
"android.hardware.audio.common-V1",
- "android.media.audio.common.types-V1",
+ "android.media.audio.common.types-V2",
],
},
diff --git a/automotive/audiocontrol/aidl/vts/Android.bp b/automotive/audiocontrol/aidl/vts/Android.bp
index 3d4be48..edac160 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_media_audio_common_types_cpp_static",
+ "latest_android_hardware_audio_common_cpp_static",
"VtsHalTargetTestDefaults",
"use_libaidlvintf_gtest_helper_static",
],
@@ -38,8 +40,6 @@
],
static_libs: [
"android.hardware.automotive.audiocontrol-V2-cpp",
- "android.hardware.audio.common-V1-cpp",
- "android.media.audio.common.types-V1-cpp",
"libgmock",
],
test_suites: [
diff --git a/automotive/can/OWNERS b/automotive/can/OWNERS
new file mode 100644
index 0000000..ffa4828
--- /dev/null
+++ b/automotive/can/OWNERS
@@ -0,0 +1,3 @@
+kevinme@google.com
+chrisweir@google.com
+twasilczyk@google.com
diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
index 623438f..18a3329 100644
--- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
+++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
@@ -250,8 +250,7 @@
// Stream configurations are found in metadata
RawStreamConfig *ptr = reinterpret_cast<RawStreamConfig *>(streamCfgs.data.i32);
for (unsigned offset = 0; offset < streamCfgs.count; offset += kStreamCfgSz) {
- if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
- ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) {
+ if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT) {
targetCfg.width = ptr->width;
targetCfg.height = ptr->height;
targetCfg.format = static_cast<PixelFormat>(ptr->format);
@@ -2017,13 +2016,12 @@
// Stream configurations are found in metadata
RawStreamConfig *ptr = reinterpret_cast<RawStreamConfig *>(streamCfgs.data.i32);
for (unsigned offset = 0; offset < streamCfgs.count; offset += kStreamCfgSz) {
- if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
- ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) {
-
+ if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT) {
if (ptr->width * ptr->height > maxArea &&
ptr->framerate >= minReqFps) {
targetCfg.width = ptr->width;
targetCfg.height = ptr->height;
+ targetCfg.format = static_cast<PixelFormat>(ptr->format);
maxArea = ptr->width * ptr->height;
foundCfg = true;
@@ -2032,8 +2030,6 @@
++ptr;
}
}
- targetCfg.format =
- static_cast<PixelFormat>(HAL_PIXEL_FORMAT_RGBA_8888);
if (!foundCfg) {
// Current EVS camera does not provide stream configurations in the
@@ -2120,13 +2116,12 @@
// Stream configurations are found in metadata
RawStreamConfig *ptr = reinterpret_cast<RawStreamConfig *>(streamCfgs.data.i32);
for (unsigned offset = 0; offset < streamCfgs.count; offset += kStreamCfgSz) {
- if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
- ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) {
-
+ if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT) {
if (ptr->width * ptr->height > maxArea &&
ptr->framerate >= minReqFps) {
targetCfg.width = ptr->width;
targetCfg.height = ptr->height;
+ targetCfg.format = static_cast<PixelFormat>(ptr->format);
maxArea = ptr->width * ptr->height;
foundCfg = true;
@@ -2135,8 +2130,6 @@
++ptr;
}
}
- targetCfg.format =
- static_cast<PixelFormat>(HAL_PIXEL_FORMAT_RGBA_8888);
if (!foundCfg) {
LOG(INFO) << "Device " << cam.v1.cameraId
diff --git a/automotive/evs/aidl/vts/VtsHalEvsTargetTest.cpp b/automotive/evs/aidl/vts/VtsHalEvsTargetTest.cpp
index 9c6c573..3ea1eaa 100644
--- a/automotive/evs/aidl/vts/VtsHalEvsTargetTest.cpp
+++ b/automotive/evs/aidl/vts/VtsHalEvsTargetTest.cpp
@@ -231,8 +231,7 @@
// Stream configurations are found in metadata
RawStreamConfig* ptr = reinterpret_cast<RawStreamConfig*>(streamCfgs.data.i32);
for (unsigned offset = 0; offset < streamCfgs.count; offset += kStreamCfgSz) {
- if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
- ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) {
+ if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT) {
targetCfg.width = ptr->width;
targetCfg.height = ptr->height;
targetCfg.format = static_cast<PixelFormat>(ptr->format);
@@ -1732,11 +1731,11 @@
// Stream configurations are found in metadata
RawStreamConfig* ptr = reinterpret_cast<RawStreamConfig*>(streamCfgs.data.i32);
for (unsigned offset = 0; offset < streamCfgs.count; offset += kStreamCfgSz) {
- if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
- ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) {
+ if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT) {
if (ptr->width * ptr->height > maxArea && ptr->framerate >= minReqFps) {
targetCfg.width = ptr->width;
targetCfg.height = ptr->height;
+ targetCfg.format = static_cast<PixelFormat>(ptr->format);
maxArea = ptr->width * ptr->height;
foundCfg = true;
@@ -1745,7 +1744,6 @@
++ptr;
}
}
- targetCfg.format = static_cast<PixelFormat>(HAL_PIXEL_FORMAT_RGBA_8888);
if (!foundCfg) {
// Current EVS camera does not provide stream configurations in the
@@ -1829,11 +1827,11 @@
// Stream configurations are found in metadata
RawStreamConfig* ptr = reinterpret_cast<RawStreamConfig*>(streamCfgs.data.i32);
for (unsigned offset = 0; offset < streamCfgs.count; offset += kStreamCfgSz) {
- if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
- ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) {
+ if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT) {
if (ptr->width * ptr->height > maxArea && ptr->framerate >= minReqFps) {
targetCfg.width = ptr->width;
targetCfg.height = ptr->height;
+ targetCfg.format = static_cast<PixelFormat>(ptr->format);
maxArea = ptr->width * ptr->height;
foundCfg = true;
@@ -1842,7 +1840,6 @@
++ptr;
}
}
- targetCfg.format = static_cast<PixelFormat>(HAL_PIXEL_FORMAT_RGBA_8888);
if (!foundCfg) {
LOG(INFO) << "Device " << cam.id
diff --git a/automotive/occupant_awareness/aidl/Android.bp b/automotive/occupant_awareness/aidl/Android.bp
index 6ddc127..1a8124c 100644
--- a/automotive/occupant_awareness/aidl/Android.bp
+++ b/automotive/occupant_awareness/aidl/Android.bp
@@ -23,11 +23,6 @@
"com.android.car.framework",
],
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
versions: ["1"],
}
diff --git a/automotive/remoteaccess/Android.bp b/automotive/remoteaccess/Android.bp
new file mode 100644
index 0000000..ac04354
--- /dev/null
+++ b/automotive/remoteaccess/Android.bp
@@ -0,0 +1,39 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+aidl_interface {
+ name: "android.hardware.automotive.remoteaccess",
+ vendor_available: true,
+ srcs: [
+ "android/hardware/automotive/remoteaccess/**/*.aidl",
+ ],
+ stability: "vintf",
+ backend: {
+ cpp: {
+ enabled: false,
+ },
+ java: {
+ sdk_version: "module_current",
+ min_sdk_version: "31",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.car.framework",
+ ],
+ },
+ },
+}
diff --git a/automotive/remoteaccess/OWNERS b/automotive/remoteaccess/OWNERS
new file mode 100644
index 0000000..d6969e5
--- /dev/null
+++ b/automotive/remoteaccess/OWNERS
@@ -0,0 +1,2 @@
+ericjeong@google.com
+shanyu@google.com
diff --git a/automotive/remoteaccess/aidl_api/android.hardware.automotive.remoteaccess/current/android/hardware/automotive/remoteaccess/ApState.aidl b/automotive/remoteaccess/aidl_api/android.hardware.automotive.remoteaccess/current/android/hardware/automotive/remoteaccess/ApState.aidl
new file mode 100644
index 0000000..da4f1d4
--- /dev/null
+++ b/automotive/remoteaccess/aidl_api/android.hardware.automotive.remoteaccess/current/android/hardware/automotive/remoteaccess/ApState.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.automotive.remoteaccess;
+@VintfStability
+parcelable ApState {
+ boolean isReadyForRemoteTask;
+ boolean isWakeupRequired;
+}
diff --git a/automotive/remoteaccess/aidl_api/android.hardware.automotive.remoteaccess/current/android/hardware/automotive/remoteaccess/IRemoteAccess.aidl b/automotive/remoteaccess/aidl_api/android.hardware.automotive.remoteaccess/current/android/hardware/automotive/remoteaccess/IRemoteAccess.aidl
new file mode 100644
index 0000000..9b6eb2f
--- /dev/null
+++ b/automotive/remoteaccess/aidl_api/android.hardware.automotive.remoteaccess/current/android/hardware/automotive/remoteaccess/IRemoteAccess.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.remoteaccess;
+@VintfStability
+interface IRemoteAccess {
+ String getDeviceId();
+ String getWakeupServiceName();
+ void setRemoteTaskCallback(android.hardware.automotive.remoteaccess.IRemoteTaskCallback callback);
+ void clearRemoteTaskCallback();
+ void notifyApStateChange(in android.hardware.automotive.remoteaccess.ApState state);
+}
diff --git a/automotive/remoteaccess/aidl_api/android.hardware.automotive.remoteaccess/current/android/hardware/automotive/remoteaccess/IRemoteTaskCallback.aidl b/automotive/remoteaccess/aidl_api/android.hardware.automotive.remoteaccess/current/android/hardware/automotive/remoteaccess/IRemoteTaskCallback.aidl
new file mode 100644
index 0000000..295100e
--- /dev/null
+++ b/automotive/remoteaccess/aidl_api/android.hardware.automotive.remoteaccess/current/android/hardware/automotive/remoteaccess/IRemoteTaskCallback.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.remoteaccess;
+@VintfStability
+interface IRemoteTaskCallback {
+ oneway void onRemoteTaskRequested(String clientId, in byte[] data);
+}
diff --git a/automotive/remoteaccess/android/hardware/automotive/remoteaccess/ApState.aidl b/automotive/remoteaccess/android/hardware/automotive/remoteaccess/ApState.aidl
new file mode 100644
index 0000000..c8eb3ef
--- /dev/null
+++ b/automotive/remoteaccess/android/hardware/automotive/remoteaccess/ApState.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.remoteaccess;
+
+@VintfStability
+parcelable ApState {
+ /**
+ * Whether AP (application processor) is ready to receive remote tasks.
+ *
+ * If this is true. AP is powered on and the car service is ready to handle
+ * remote tasks.
+ */
+ boolean isReadyForRemoteTask;
+ /**
+ * Whether AP (application processor) needs to be woken up.
+ *
+ * While the AP is shutting down, this will be set to false to prevent the
+ * wakeup signal to interrupt the shutdown process. At the last step of the
+ * shutdown process, this will be set to true so that AP will be waken
+ * up when task arrives. After AP starts up, this will be set to false
+ * to prevent unnecessary wakeup signal.
+ */
+ boolean isWakeupRequired;
+}
diff --git a/automotive/remoteaccess/android/hardware/automotive/remoteaccess/IRemoteAccess.aidl b/automotive/remoteaccess/android/hardware/automotive/remoteaccess/IRemoteAccess.aidl
new file mode 100644
index 0000000..a198b03
--- /dev/null
+++ b/automotive/remoteaccess/android/hardware/automotive/remoteaccess/IRemoteAccess.aidl
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.remoteaccess;
+
+import android.hardware.automotive.remoteaccess.ApState;
+import android.hardware.automotive.remoteaccess.IRemoteTaskCallback;
+
+/**
+ * Interface representing a remote wakeup client.
+ *
+ * A wakeup client is a binary outside Android framework that communicates with
+ * a wakeup server and receives wake up command.
+ */
+@VintfStability
+interface IRemoteAccess {
+ /**
+ * Gets a unique device ID that could be recognized by wake up server.
+ *
+ * This device ID is provisioned during car production and is registered
+ * with the wake up server.
+ *
+ * @return a unique device ID.
+ */
+ String getDeviceId();
+
+ /**
+ * Gets the name for the remote wakeup server.
+ *
+ * This name will be provided to remote task server during registration
+ * and used by remote task server to find the remote wakeup server to
+ * use for waking up the device. This name must be pre-negotiated between
+ * the remote wakeup server/client and the remote task server/client and
+ * must be unique. We recommend the format to be a human readable string
+ * with reverse domain name notation (reverse-DNS), e.g.
+ * "com.google.vehicle.wakeup".
+ */
+ String getWakeupServiceName();
+
+ /**
+ * Sets a callback to be called when a remote task is requested.
+ *
+ * @param callback A callback to be called when a remote task is requested.
+ */
+ void setRemoteTaskCallback(IRemoteTaskCallback callback);
+
+ /**
+ * Clears a previously set remote task callback.
+ *
+ * If no callback was set, this operation is no-op.
+ */
+ void clearRemoteTaskCallback();
+
+ /**
+ * Notifies whether AP is ready to receive remote tasks.
+ *
+ * <p>Wakeup client should store and use this state until a new call with a
+ * different state arrives.
+ *
+ * <p>If {@code isReadyForRemoteTask} is true, the wakeup client may send
+ * the task received from the server to AP immediately.
+ *
+ * <p>If {@code isReadyForRemoteTask} is false, it must store the received
+ * remote tasks and wait until AP is ready to receive tasks. If it takes too
+ * long for AP to become ready, the task must be reported to remote task
+ * server as failed. Implementation must make sure no duplicate tasks are
+ * delivered to AP.
+ *
+ * <p>If {@code isWakeupRequired} is true, it must try to wake up AP when a
+ * remote task arrives or when there are pending requests.
+ *
+ * <p>If {@code isWakeupRequired} is false, it must not try to wake up AP.
+ */
+ void notifyApStateChange(in ApState state);
+}
diff --git a/automotive/remoteaccess/android/hardware/automotive/remoteaccess/IRemoteTaskCallback.aidl b/automotive/remoteaccess/android/hardware/automotive/remoteaccess/IRemoteTaskCallback.aidl
new file mode 100644
index 0000000..7a1616f
--- /dev/null
+++ b/automotive/remoteaccess/android/hardware/automotive/remoteaccess/IRemoteTaskCallback.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.remoteaccess;
+
+/**
+ * The callback interface for car service to receive tasks from wakup client.
+ */
+@VintfStability
+interface IRemoteTaskCallback {
+ /**
+ * A callback that is called when a remote task is requested.
+ *
+ * @param clientId An ID to uniquely identify a remote task client.
+ * @param data Opaque task data passed to the remote task client.
+ */
+ oneway void onRemoteTaskRequested(String clientId, in byte[] data);
+}
diff --git a/automotive/remoteaccess/hal/default/Android.bp b/automotive/remoteaccess/hal/default/Android.bp
new file mode 100644
index 0000000..a2bf86c
--- /dev/null
+++ b/automotive/remoteaccess/hal/default/Android.bp
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_binary {
+ name: "android.hardware.automotive.remoteaccess@V1-default-service",
+ vendor: true,
+ vintf_fragments: ["remoteaccess-default-service.xml"],
+ init_rc: ["remoteaccess-default-service.rc"],
+ relative_install_path: "hw",
+ srcs: ["src/RemoteAccessImpl.cpp"],
+ whole_static_libs: [
+ "RemoteAccessService",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "liblog",
+ "libutils",
+ "libgrpc++",
+ "libprotobuf-cpp-full",
+ ],
+ defaults: [
+ "vhalclient_defaults",
+ ],
+ cflags: [
+ "-Wno-unused-parameter",
+ "-DGRPC_SERVICE_ADDRESS=\"localhost:50051\"",
+ ],
+}
+
+cc_library {
+ name: "RemoteAccessService",
+ vendor_available: true,
+ local_include_dirs: ["include"],
+ export_include_dirs: ["include"],
+ srcs: [
+ "src/RemoteAccessService.cpp",
+ ],
+ whole_static_libs: [
+ "android.hardware.automotive.remoteaccess-V1-ndk",
+ "wakeup_client_protos",
+ "libvhalclient",
+ ],
+ defaults: [
+ "vhalclient_defaults",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "libcutils",
+ "liblog",
+ "libutils",
+ "libgrpc++",
+ "libprotobuf-cpp-full",
+ ],
+ cflags: [
+ "-Wno-unused-parameter",
+ ],
+}
+
+cc_fuzz {
+ name: "android.hardware.automotive.remoteaccess@V1-default-service.aidl_fuzzer",
+ srcs: ["fuzzer/fuzzer.cpp"],
+ whole_static_libs: [
+ "RemoteAccessService",
+ ],
+ static_libs: [
+ "libgtest",
+ "libgmock",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "liblog",
+ "libutils",
+ "libgrpc++",
+ "libprotobuf-cpp-full",
+ ],
+ defaults: [
+ "vhalclient_defaults",
+ "service_fuzzer_defaults",
+ ],
+ cflags: [
+ "-Wno-unused-parameter",
+ "-DGRPC_SERVICE_ADDRESS=\"localhost:50051\"",
+ ],
+ fuzz_config: {
+ cc: [
+ "shanyu@google.com",
+ ],
+ },
+}
diff --git a/automotive/remoteaccess/hal/default/fuzzer/fuzzer.cpp b/automotive/remoteaccess/hal/default/fuzzer/fuzzer.cpp
new file mode 100644
index 0000000..292c80e
--- /dev/null
+++ b/automotive/remoteaccess/hal/default/fuzzer/fuzzer.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <RemoteAccessService.h>
+#include <fuzzbinder/libbinder_ndk_driver.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <gmock/gmock.h>
+#include <grpcpp/test/mock_stream.h>
+#include <wakeup_client.grpc.pb.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace remoteaccess {
+
+using ::grpc::ClientAsyncReaderInterface;
+using ::grpc::ClientAsyncResponseReaderInterface;
+using ::grpc::ClientContext;
+using ::grpc::ClientReader;
+using ::grpc::ClientReaderInterface;
+using ::grpc::CompletionQueue;
+using ::grpc::Status;
+using ::grpc::testing::MockClientReader;
+using ::testing::_;
+using ::testing::Return;
+
+class MockGrpcClientStub : public WakeupClient::StubInterface {
+ public:
+ ClientReaderInterface<GetRemoteTasksResponse>* GetRemoteTasksRaw(
+ [[maybe_unused]] ClientContext* context,
+ [[maybe_unused]] const GetRemoteTasksRequest& request) override {
+ MockClientReader<GetRemoteTasksResponse>* mockClientReader =
+ new MockClientReader<GetRemoteTasksResponse>();
+ ON_CALL(*mockClientReader, Finish()).WillByDefault(Return(Status::OK));
+ ON_CALL(*mockClientReader, Read(_)).WillByDefault(Return(false));
+ return mockClientReader;
+ }
+
+ Status NotifyWakeupRequired([[maybe_unused]] ClientContext* context,
+ [[maybe_unused]] const NotifyWakeupRequiredRequest& request,
+ [[maybe_unused]] NotifyWakeupRequiredResponse* response) {
+ return Status::OK;
+ }
+
+ // Async methods which we do not care.
+ ClientAsyncReaderInterface<GetRemoteTasksResponse>* AsyncGetRemoteTasksRaw(
+ [[maybe_unused]] ClientContext* context,
+ [[maybe_unused]] const GetRemoteTasksRequest& request,
+ [[maybe_unused]] CompletionQueue* cq, [[maybe_unused]] void* tag) {
+ return nullptr;
+ }
+
+ ClientAsyncReaderInterface<GetRemoteTasksResponse>* PrepareAsyncGetRemoteTasksRaw(
+ [[maybe_unused]] ClientContext* context,
+ [[maybe_unused]] const GetRemoteTasksRequest& request,
+ [[maybe_unused]] CompletionQueue* cq) {
+ return nullptr;
+ }
+
+ ClientAsyncResponseReaderInterface<NotifyWakeupRequiredResponse>* AsyncNotifyWakeupRequiredRaw(
+ [[maybe_unused]] ClientContext* context,
+ [[maybe_unused]] const NotifyWakeupRequiredRequest& request,
+ [[maybe_unused]] CompletionQueue* cq) {
+ return nullptr;
+ }
+
+ ClientAsyncResponseReaderInterface<NotifyWakeupRequiredResponse>*
+ PrepareAsyncNotifyWakeupRequiredRaw([[maybe_unused]] ClientContext* context,
+ [[maybe_unused]] const NotifyWakeupRequiredRequest& request,
+ [[maybe_unused]] CompletionQueue* c) {
+ return nullptr;
+ }
+};
+
+} // namespace remoteaccess
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ android::hardware::automotive::remoteaccess::MockGrpcClientStub stub;
+ std::shared_ptr<android::hardware::automotive::remoteaccess::RemoteAccessService> service =
+ ndk::SharedRefBase::make<
+ android::hardware::automotive::remoteaccess::RemoteAccessService>(&stub);
+ android::fuzzService(service->asBinder().get(), FuzzedDataProvider(data, size));
+
+ return 0;
+}
diff --git a/automotive/remoteaccess/hal/default/include/RemoteAccessService.h b/automotive/remoteaccess/hal/default/include/RemoteAccessService.h
new file mode 100644
index 0000000..74c2af4
--- /dev/null
+++ b/automotive/remoteaccess/hal/default/include/RemoteAccessService.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <IVhalClient.h>
+#include <aidl/android/hardware/automotive/remoteaccess/ApState.h>
+#include <aidl/android/hardware/automotive/remoteaccess/BnRemoteAccess.h>
+#include <aidl/android/hardware/automotive/remoteaccess/BnRemoteTaskCallback.h>
+#include <aidl/android/hardware/automotive/remoteaccess/IRemoteTaskCallback.h>
+#include <android-base/thread_annotations.h>
+#include <android/binder_auto_utils.h>
+#include <utils/SystemClock.h>
+#include <wakeup_client.grpc.pb.h>
+
+#include <string>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace remoteaccess {
+
+// A IRemoteTaskCallback implementation for debug purpose.
+class DebugRemoteTaskCallback final
+ : public aidl::android::hardware::automotive::remoteaccess::BnRemoteTaskCallback {
+ public:
+ DebugRemoteTaskCallback() { mStartTimeMillis = android::uptimeMillis(); };
+
+ ndk::ScopedAStatus onRemoteTaskRequested(const std::string& clientId,
+ const std::vector<uint8_t>& data) override;
+ std::string printTasks();
+
+ private:
+ struct TaskData {
+ std::string clientId;
+ std::vector<uint8_t> data;
+ };
+
+ std::mutex mLock;
+ int64_t mStartTimeMillis;
+ std::vector<TaskData> mTasks;
+};
+
+class RemoteAccessService
+ : public aidl::android::hardware::automotive::remoteaccess::BnRemoteAccess {
+ public:
+ explicit RemoteAccessService(WakeupClient::StubInterface* grpcStub);
+
+ ~RemoteAccessService();
+
+ ndk::ScopedAStatus getDeviceId(std::string* deviceId) override;
+
+ ndk::ScopedAStatus getWakeupServiceName(std::string* wakeupServiceName) override;
+
+ ndk::ScopedAStatus setRemoteTaskCallback(
+ const std::shared_ptr<
+ aidl::android::hardware::automotive::remoteaccess::IRemoteTaskCallback>&
+ callback) override;
+
+ ndk::ScopedAStatus clearRemoteTaskCallback() override;
+
+ ndk::ScopedAStatus notifyApStateChange(
+ const aidl::android::hardware::automotive::remoteaccess::ApState& newState) override;
+
+ binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
+
+ private:
+ // For testing.
+ friend class RemoteAccessServiceUnitTest;
+
+ static bool checkDumpPermission();
+
+ WakeupClient::StubInterface* mGrpcStub;
+ std::thread mThread;
+ std::mutex mLock;
+ std::condition_variable mCv;
+ std::shared_ptr<aidl::android::hardware::automotive::remoteaccess::IRemoteTaskCallback>
+ mRemoteTaskCallback GUARDED_BY(mLock);
+ std::unique_ptr<grpc::ClientContext> mGetRemoteTasksContext GUARDED_BY(mLock);
+ // Associated with mCv to notify the task loop to stop waiting and exit.
+ bool mTaskWaitStopped GUARDED_BY(mLock);
+ // A mutex to make sure startTaskLoop does not overlap with stopTaskLoop.
+ std::mutex mStartStopTaskLoopLock;
+ bool mTaskLoopRunning GUARDED_BY(mStartStopTaskLoopLock);
+ // Default wait time before retry connecting to remote access client is 10s.
+ size_t mRetryWaitInMs = 10'000;
+ std::shared_ptr<DebugRemoteTaskCallback> mDebugCallback;
+
+ void runTaskLoop();
+ void maybeStartTaskLoop();
+ void maybeStopTaskLoop();
+ ndk::ScopedAStatus getDeviceIdWithClient(
+ android::frameworks::automotive::vhal::IVhalClient& client, std::string* deviceId);
+
+ void setRetryWaitInMs(size_t retryWaitInMs) { mRetryWaitInMs = retryWaitInMs; }
+ void dumpHelp(int fd);
+};
+
+} // namespace remoteaccess
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/remoteaccess/hal/default/proto/Android.bp b/automotive/remoteaccess/hal/default/proto/Android.bp
new file mode 100644
index 0000000..3e0dba1
--- /dev/null
+++ b/automotive/remoteaccess/hal/default/proto/Android.bp
@@ -0,0 +1,79 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+genrule {
+ name: "wakeup_client_pb_h",
+ tools: [
+ "aprotoc",
+ "protoc-gen-grpc-cpp-plugin",
+ ],
+ cmd: "$(location aprotoc) -I$$(dirname $(in)) -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)",
+ srcs: [
+ "wakeup_client.proto",
+ ],
+ out: [
+ "wakeup_client.pb.h",
+ "wakeup_client.grpc.pb.h",
+ ],
+}
+
+genrule {
+ name: "wakeup_client_pb_cc",
+ tools: [
+ "aprotoc",
+ "protoc-gen-grpc-cpp-plugin",
+ ],
+ cmd: "$(location aprotoc) -I$$(dirname $(in)) -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)",
+ srcs: [
+ "wakeup_client.proto",
+ ],
+ out: [
+ "wakeup_client.pb.cc",
+ "wakeup_client.grpc.pb.cc",
+ ],
+}
+
+cc_library_static {
+ name: "wakeup_client_protos",
+ vendor_available: true,
+ host_supported: true,
+ include_dirs: [
+ "external/protobuf/src",
+ ],
+ generated_headers: [
+ "wakeup_client_pb_h",
+ ],
+ export_generated_headers: [
+ "wakeup_client_pb_h",
+ ],
+ generated_sources: [
+ "wakeup_client_pb_cc",
+ ],
+ shared_libs: [
+ "libgrpc++",
+ "libprotobuf-cpp-full",
+ ],
+ cflags: [
+ "-Wno-unused-parameter",
+ ],
+}
diff --git a/automotive/remoteaccess/hal/default/proto/wakeup_client.proto b/automotive/remoteaccess/hal/default/proto/wakeup_client.proto
new file mode 100644
index 0000000..4fe0d01
--- /dev/null
+++ b/automotive/remoteaccess/hal/default/proto/wakeup_client.proto
@@ -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.
+ */
+
+syntax = "proto3";
+
+package android.hardware.automotive.remoteaccess;
+
+/**
+ * Service provided by a wakeup client running on TCU.
+ */
+service WakeupClient {
+ /**
+ * Establish a long-live connection to receive remote tasks.
+ *
+ * <p>For the server, whenever a remote task arrives, if the connection is
+ * alive, it will use the return stream to return a task's information.
+ *
+ * <p>If the connection is not alive, the server must stores the remote task
+ * until a new connection is established (which means AP is ready to
+ * receive remote task again) and send the stored tasks.
+ *
+ * <p>If the server closes the connection, the client will try to
+ * reestablish the connection.
+ */
+ rpc GetRemoteTasks(GetRemoteTasksRequest) returns (stream GetRemoteTasksResponse) {}
+
+ /**
+ * Notifies whether AP is required to be waken up when remote task arrives.
+ *
+ * <p>Wakeup client should store and use this state until a new call with a
+ * different state arrives.
+ *
+ * <p>If {@code isWakeupRequired} in the request is true, it must wake up AP
+ * when a remote task arrives.
+ *
+ * <p>If {@code isWakeupRequired} in the request is false, it must not try
+ * to wake up AP.
+ */
+ rpc NotifyWakeupRequired(NotifyWakeupRequiredRequest) returns (NotifyWakeupRequiredResponse) {}
+}
+
+message GetRemoteTasksRequest {}
+
+message GetRemoteTasksResponse {
+ string clientId = 1;
+ bytes data = 2;
+}
+
+message NotifyWakeupRequiredRequest {
+ bool isWakeupRequired = 1;
+}
+
+message NotifyWakeupRequiredResponse {}
diff --git a/automotive/remoteaccess/hal/default/remoteaccess-default-service.rc b/automotive/remoteaccess/hal/default/remoteaccess-default-service.rc
new file mode 100644
index 0000000..b7a9cdc
--- /dev/null
+++ b/automotive/remoteaccess/hal/default/remoteaccess-default-service.rc
@@ -0,0 +1,4 @@
+service vendor.remoteaccess-default /vendor/bin/hw/android.hardware.automotive.remoteaccess@V1-default-service
+ class hal
+ user vehicle_network
+ group system inet
diff --git a/automotive/remoteaccess/hal/default/remoteaccess-default-service.xml b/automotive/remoteaccess/hal/default/remoteaccess-default-service.xml
new file mode 100644
index 0000000..d050a1b
--- /dev/null
+++ b/automotive/remoteaccess/hal/default/remoteaccess-default-service.xml
@@ -0,0 +1,7 @@
+<manifest version="1.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.automotive.remoteaccess</name>
+ <version>1</version>
+ <fqname>IRemoteAccess/default</fqname>
+ </hal>
+</manifest>
diff --git a/automotive/remoteaccess/hal/default/src/RemoteAccessImpl.cpp b/automotive/remoteaccess/hal/default/src/RemoteAccessImpl.cpp
new file mode 100644
index 0000000..8720c2f
--- /dev/null
+++ b/automotive/remoteaccess/hal/default/src/RemoteAccessImpl.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "RemoteAccessImpl"
+
+#include "RemoteAccessService.h"
+
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <grpcpp/create_channel.h>
+#include <stdlib.h>
+#include <utils/Log.h>
+
+constexpr char SERVICE_NAME[] = "android.hardware.automotive.remoteaccess.IRemoteAccess/default";
+
+int main(int /* argc */, char* /* argv */[]) {
+ ALOGI("Registering RemoteAccessService as service...");
+
+#ifndef GRPC_SERVICE_ADDRESS
+ ALOGE("GRPC_SERVICE_ADDRESS is not defined, exiting");
+ exit(1);
+#endif
+ auto channel = grpc::CreateChannel(GRPC_SERVICE_ADDRESS, grpc::InsecureChannelCredentials());
+ auto clientStub = android::hardware::automotive::remoteaccess::WakeupClient::NewStub(channel);
+ auto service = ndk::SharedRefBase::make<
+ android::hardware::automotive::remoteaccess::RemoteAccessService>(clientStub.get());
+
+ binder_exception_t err = AServiceManager_addService(service->asBinder().get(), SERVICE_NAME);
+ if (err != EX_NONE) {
+ ALOGE("failed to register android.hardware.automotive.remote.IRemoteAccess service, "
+ "exception: %d",
+ err);
+ exit(1);
+ }
+
+ if (!ABinderProcess_setThreadPoolMaxThreadCount(1)) {
+ ALOGE("%s", "failed to set thread pool max thread count");
+ exit(1);
+ }
+ ABinderProcess_startThreadPool();
+
+ ALOGI("RemoteAccess service Ready");
+
+ ABinderProcess_joinThreadPool();
+
+ ALOGW("Should not reach here");
+
+ return 0;
+}
diff --git a/automotive/remoteaccess/hal/default/src/RemoteAccessService.cpp b/automotive/remoteaccess/hal/default/src/RemoteAccessService.cpp
new file mode 100644
index 0000000..5cd58d3
--- /dev/null
+++ b/automotive/remoteaccess/hal/default/src/RemoteAccessService.cpp
@@ -0,0 +1,355 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "RemoteAccessService.h"
+
+#include <VehicleUtils.h>
+#include <aidl/android/hardware/automotive/vehicle/VehicleProperty.h>
+#include <android-base/stringprintf.h>
+#include <android/binder_status.h>
+#include <grpc++/grpc++.h>
+#include <private/android_filesystem_config.h>
+#include <utils/Log.h>
+#include <chrono>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace remoteaccess {
+
+namespace {
+
+using ::aidl::android::hardware::automotive::remoteaccess::ApState;
+using ::aidl::android::hardware::automotive::remoteaccess::IRemoteTaskCallback;
+using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
+using ::android::base::ScopedLockAssertion;
+using ::android::base::StringAppendF;
+using ::android::base::StringPrintf;
+using ::android::frameworks::automotive::vhal::IVhalClient;
+using ::android::hardware::automotive::vehicle::toInt;
+using ::grpc::ClientContext;
+using ::grpc::ClientReaderInterface;
+using ::grpc::Status;
+using ::grpc::StatusCode;
+using ::ndk::ScopedAStatus;
+
+const std::string WAKEUP_SERVICE_NAME = "com.google.vehicle.wakeup";
+constexpr char COMMAND_SET_AP_STATE[] = "--set-ap-state";
+constexpr char COMMAND_START_DEBUG_CALLBACK[] = "--start-debug-callback";
+constexpr char COMMAND_STOP_DEBUG_CALLBACK[] = "--stop-debug-callback";
+constexpr char COMMAND_SHOW_TASK[] = "--show-task";
+constexpr char COMMAND_GET_DEVICE_ID[] = "--get-device-id";
+
+std::vector<uint8_t> stringToBytes(const std::string& s) {
+ const char* data = s.data();
+ return std::vector<uint8_t>(data, data + s.size());
+}
+
+ScopedAStatus rpcStatusToScopedAStatus(const Status& status, const std::string& errorMsg) {
+ return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+ status.error_code(), (errorMsg + ", error: " + status.error_message()).c_str());
+}
+
+std::string printBytes(const std::vector<uint8_t>& bytes) {
+ std::string s;
+ for (size_t i = 0; i < bytes.size(); i++) {
+ StringAppendF(&s, "%02x", bytes[i]);
+ }
+ return s;
+}
+
+bool checkBoolFlag(const char* flag) {
+ return !strcmp(flag, "1") || !strcmp(flag, "0");
+}
+
+void dprintErrorStatus(int fd, const char* detail, const ScopedAStatus& status) {
+ dprintf(fd, "%s, code: %d, error: %s\n", detail, status.getStatus(), status.getMessage());
+}
+
+} // namespace
+
+RemoteAccessService::RemoteAccessService(WakeupClient::StubInterface* grpcStub)
+ : mGrpcStub(grpcStub){};
+
+RemoteAccessService::~RemoteAccessService() {
+ maybeStopTaskLoop();
+}
+
+void RemoteAccessService::maybeStartTaskLoop() {
+ std::lock_guard<std::mutex> lockGuard(mStartStopTaskLoopLock);
+ if (mTaskLoopRunning) {
+ return;
+ }
+
+ mThread = std::thread([this]() { runTaskLoop(); });
+
+ mTaskLoopRunning = true;
+}
+
+void RemoteAccessService::maybeStopTaskLoop() {
+ std::lock_guard<std::mutex> lockGuard(mStartStopTaskLoopLock);
+ if (!mTaskLoopRunning) {
+ return;
+ }
+
+ {
+ std::lock_guard<std::mutex> lockGuard(mLock);
+ // Try to stop the reading stream.
+ if (mGetRemoteTasksContext) {
+ mGetRemoteTasksContext->TryCancel();
+ mGetRemoteTasksContext.reset();
+ }
+ mTaskWaitStopped = true;
+ mCv.notify_all();
+ }
+ if (mThread.joinable()) {
+ mThread.join();
+ }
+
+ mTaskLoopRunning = false;
+}
+
+void RemoteAccessService::runTaskLoop() {
+ GetRemoteTasksRequest request = {};
+ std::unique_ptr<ClientReaderInterface<GetRemoteTasksResponse>> reader;
+ while (true) {
+ {
+ std::lock_guard<std::mutex> lockGuard(mLock);
+ mGetRemoteTasksContext.reset(new ClientContext());
+ reader = mGrpcStub->GetRemoteTasks(mGetRemoteTasksContext.get(), request);
+ }
+ GetRemoteTasksResponse response;
+ while (reader->Read(&response)) {
+ ALOGI("Receiving one task from remote task client");
+
+ std::shared_ptr<IRemoteTaskCallback> callback;
+ {
+ std::lock_guard<std::mutex> lockGuard(mLock);
+ callback = mRemoteTaskCallback;
+ }
+ if (callback == nullptr) {
+ ALOGD("No callback registered, task ignored");
+ continue;
+ }
+ ALOGD("Calling onRemoteTaskRequested callback for client ID: %s",
+ response.clientid().c_str());
+ ScopedAStatus callbackStatus = callback->onRemoteTaskRequested(
+ response.clientid(), stringToBytes(response.data()));
+ if (!callbackStatus.isOk()) {
+ ALOGE("Failed to call onRemoteTaskRequested callback, status: %d, message: %s",
+ callbackStatus.getStatus(), callbackStatus.getMessage());
+ }
+ }
+ Status status = reader->Finish();
+
+ ALOGE("GetRemoteTasks stream breaks, code: %d, message: %s, sleeping for 10s and retry",
+ status.error_code(), status.error_message().c_str());
+ // The long lasting connection should not return. But if the server returns, retry after
+ // 10s.
+ {
+ std::unique_lock lk(mLock);
+ if (mCv.wait_for(lk, std::chrono::milliseconds(mRetryWaitInMs), [this] {
+ ScopedLockAssertion lockAssertion(mLock);
+ return mTaskWaitStopped;
+ })) {
+ // If the stopped flag is set, we are quitting, exit the loop.
+ break;
+ }
+ }
+ }
+}
+
+ScopedAStatus RemoteAccessService::getDeviceId(std::string* deviceId) {
+#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ auto vhalClient = IVhalClient::tryCreate();
+ if (vhalClient == nullptr) {
+ ALOGE("Failed to connect to VHAL");
+ return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+ /*errorCode=*/0, "Failed to connect to VHAL to get device ID");
+ }
+ return getDeviceIdWithClient(*vhalClient.get(), deviceId);
+#else
+ // Don't use VHAL client in fuzzing since IPC is not allowed.
+ return ScopedAStatus::ok();
+#endif
+}
+
+ScopedAStatus RemoteAccessService::getDeviceIdWithClient(IVhalClient& vhalClient,
+ std::string* deviceId) {
+ auto result = vhalClient.getValueSync(
+ *vhalClient.createHalPropValue(toInt(VehicleProperty::INFO_VIN)));
+ if (!result.ok()) {
+ return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+ /*errorCode=*/0,
+ ("failed to get INFO_VIN from VHAL: " + result.error().message()).c_str());
+ }
+ *deviceId = (*result)->getStringValue();
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus RemoteAccessService::getWakeupServiceName(std::string* wakeupServiceName) {
+ *wakeupServiceName = WAKEUP_SERVICE_NAME;
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus RemoteAccessService::setRemoteTaskCallback(
+ const std::shared_ptr<IRemoteTaskCallback>& callback) {
+ std::lock_guard<std::mutex> lockGuard(mLock);
+ mRemoteTaskCallback = callback;
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus RemoteAccessService::clearRemoteTaskCallback() {
+ std::lock_guard<std::mutex> lockGuard(mLock);
+ mRemoteTaskCallback.reset();
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus RemoteAccessService::notifyApStateChange(const ApState& newState) {
+ ClientContext context;
+ NotifyWakeupRequiredRequest request = {};
+ request.set_iswakeuprequired(newState.isWakeupRequired);
+ NotifyWakeupRequiredResponse response = {};
+ Status status = mGrpcStub->NotifyWakeupRequired(&context, request, &response);
+ if (!status.ok()) {
+ return rpcStatusToScopedAStatus(status, "Failed to notify isWakeupRequired");
+ }
+
+ if (newState.isReadyForRemoteTask) {
+ maybeStartTaskLoop();
+ } else {
+ maybeStopTaskLoop();
+ }
+ return ScopedAStatus::ok();
+}
+
+bool RemoteAccessService::checkDumpPermission() {
+ uid_t uid = AIBinder_getCallingUid();
+ return uid == AID_ROOT || uid == AID_SHELL || uid == AID_SYSTEM;
+}
+
+void RemoteAccessService::dumpHelp(int fd) {
+ dprintf(fd, "%s",
+ (std::string("RemoteAccess HAL debug interface, Usage: \n") + COMMAND_SET_AP_STATE +
+ " [0/1](isReadyForRemoteTask) [0/1](isWakeupRequired) Set the new AP state\n" +
+ COMMAND_START_DEBUG_CALLBACK +
+ " Start a debug callback that will record the received tasks\n" +
+ COMMAND_STOP_DEBUG_CALLBACK + " Stop the debug callback\n" + COMMAND_SHOW_TASK +
+ " Show tasks received by debug callback\n" + COMMAND_GET_DEVICE_ID +
+ " Get device id\n")
+ .c_str());
+}
+
+binder_status_t RemoteAccessService::dump(int fd, const char** args, uint32_t numArgs) {
+ if (!checkDumpPermission()) {
+ dprintf(fd, "Caller must be root, system or shell\n");
+ return STATUS_PERMISSION_DENIED;
+ }
+
+ if (numArgs == 0) {
+ dumpHelp(fd);
+ return STATUS_OK;
+ }
+
+ if (!strcmp(args[0], COMMAND_SET_AP_STATE)) {
+ if (numArgs < 3) {
+ dumpHelp(fd);
+ return STATUS_OK;
+ }
+ ApState apState = {};
+ const char* remoteTaskFlag = args[1];
+ if (!strcmp(remoteTaskFlag, "1") && !strcmp(remoteTaskFlag, "0")) {
+ dumpHelp(fd);
+ return STATUS_OK;
+ }
+ if (!checkBoolFlag(args[1])) {
+ dumpHelp(fd);
+ return STATUS_OK;
+ }
+ if (!strcmp(args[1], "1")) {
+ apState.isReadyForRemoteTask = true;
+ }
+ if (!checkBoolFlag(args[2])) {
+ dumpHelp(fd);
+ return STATUS_OK;
+ }
+ if (!strcmp(args[2], "1")) {
+ apState.isWakeupRequired = true;
+ }
+ auto status = notifyApStateChange(apState);
+ if (!status.isOk()) {
+ dprintErrorStatus(fd, "Failed to set AP state", status);
+ } else {
+ dprintf(fd, "successfully set the new AP state\n");
+ }
+ } else if (!strcmp(args[0], COMMAND_START_DEBUG_CALLBACK)) {
+ mDebugCallback = ndk::SharedRefBase::make<DebugRemoteTaskCallback>();
+ setRemoteTaskCallback(mDebugCallback);
+ dprintf(fd, "Debug callback registered\n");
+ } else if (!strcmp(args[0], COMMAND_STOP_DEBUG_CALLBACK)) {
+ if (mDebugCallback) {
+ mDebugCallback.reset();
+ }
+ clearRemoteTaskCallback();
+ dprintf(fd, "Debug callback unregistered\n");
+ } else if (!strcmp(args[0], COMMAND_SHOW_TASK)) {
+ if (mDebugCallback) {
+ dprintf(fd, "%s", mDebugCallback->printTasks().c_str());
+ } else {
+ dprintf(fd, "Debug callback is not currently used, use \"%s\" first.\n",
+ COMMAND_START_DEBUG_CALLBACK);
+ }
+ } else if (!strcmp(args[0], COMMAND_GET_DEVICE_ID)) {
+ std::string deviceId;
+ auto status = getDeviceId(&deviceId);
+ if (!status.isOk()) {
+ dprintErrorStatus(fd, "Failed to get device ID", status);
+ } else {
+ dprintf(fd, "Device Id: %s\n", deviceId.c_str());
+ }
+ } else {
+ dumpHelp(fd);
+ }
+
+ return STATUS_OK;
+}
+
+ScopedAStatus DebugRemoteTaskCallback::onRemoteTaskRequested(const std::string& clientId,
+ const std::vector<uint8_t>& data) {
+ std::lock_guard<std::mutex> lockGuard(mLock);
+ mTasks.push_back({
+ .clientId = clientId,
+ .data = data,
+ });
+ return ScopedAStatus::ok();
+}
+
+std::string DebugRemoteTaskCallback::printTasks() {
+ std::lock_guard<std::mutex> lockGuard(mLock);
+ std::string s = StringPrintf("Received %zu tasks in %f seconds", mTasks.size(),
+ (android::uptimeMillis() - mStartTimeMillis) / 1000.);
+ for (size_t i = 0; i < mTasks.size(); i++) {
+ StringAppendF(&s, "Client Id: %s, Data: %s\n", mTasks[i].clientId.c_str(),
+ printBytes(mTasks[i].data).c_str());
+ }
+ return s;
+}
+
+} // namespace remoteaccess
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/remoteaccess/hal/default/test/Android.bp b/automotive/remoteaccess/hal/default/test/Android.bp
new file mode 100644
index 0000000..227175a
--- /dev/null
+++ b/automotive/remoteaccess/hal/default/test/Android.bp
@@ -0,0 +1,47 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_test {
+ name: "RemoteAccessServiceUnitTest",
+ vendor: true,
+ srcs: ["*.cpp"],
+ whole_static_libs: [
+ "RemoteAccessService",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "liblog",
+ "libutils",
+ "libgrpc++",
+ "libprotobuf-cpp-full",
+ ],
+ // libgrpc++.so is installed as root, require root to access it.
+ require_root: true,
+ static_libs: [
+ "libgtest",
+ "libgmock",
+ ],
+ defaults: [
+ "vhalclient_defaults",
+ ],
+ cflags: [
+ "-Wno-unused-parameter",
+ ],
+ test_suites: ["device-tests"],
+}
diff --git a/automotive/remoteaccess/hal/default/test/RemoteAccessServiceUnitTest.cpp b/automotive/remoteaccess/hal/default/test/RemoteAccessServiceUnitTest.cpp
new file mode 100644
index 0000000..a220aeb
--- /dev/null
+++ b/automotive/remoteaccess/hal/default/test/RemoteAccessServiceUnitTest.cpp
@@ -0,0 +1,375 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "RemoteAccessService.h"
+
+#include <AidlHalPropValue.h>
+#include <IVhalClient.h>
+#include <aidl/android/hardware/automotive/remoteaccess/ApState.h>
+#include <aidl/android/hardware/automotive/remoteaccess/BnRemoteTaskCallback.h>
+#include <aidl/android/hardware/automotive/vehicle/VehiclePropValue.h>
+#include <gmock/gmock.h>
+#include <grpcpp/test/mock_stream.h>
+#include <gtest/gtest.h>
+#include <wakeup_client.grpc.pb.h>
+#include <chrono>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace remoteaccess {
+
+namespace {
+
+using ::android::base::ScopedLockAssertion;
+using ::android::frameworks::automotive::vhal::AidlHalPropValue;
+using ::android::frameworks::automotive::vhal::IHalPropConfig;
+using ::android::frameworks::automotive::vhal::IHalPropValue;
+using ::android::frameworks::automotive::vhal::ISubscriptionCallback;
+using ::android::frameworks::automotive::vhal::ISubscriptionClient;
+using ::android::frameworks::automotive::vhal::IVhalClient;
+
+using ::aidl::android::hardware::automotive::remoteaccess::ApState;
+using ::aidl::android::hardware::automotive::remoteaccess::BnRemoteTaskCallback;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
+
+using ::grpc::ClientAsyncReaderInterface;
+using ::grpc::ClientAsyncResponseReaderInterface;
+using ::grpc::ClientContext;
+using ::grpc::ClientReader;
+using ::grpc::ClientReaderInterface;
+using ::grpc::CompletionQueue;
+using ::grpc::Status;
+using ::grpc::testing::MockClientReader;
+using ::ndk::ScopedAStatus;
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::Return;
+using ::testing::SetArgPointee;
+
+constexpr char kTestVin[] = "test_VIN";
+
+} // namespace
+
+class MockGrpcClientStub : public WakeupClient::StubInterface {
+ public:
+ MOCK_METHOD(ClientReaderInterface<GetRemoteTasksResponse>*, GetRemoteTasksRaw,
+ (ClientContext * context, const GetRemoteTasksRequest& request));
+ MOCK_METHOD(Status, NotifyWakeupRequired,
+ (ClientContext * context, const NotifyWakeupRequiredRequest& request,
+ NotifyWakeupRequiredResponse* response));
+ // Async methods which we do not care.
+ MOCK_METHOD(ClientAsyncReaderInterface<GetRemoteTasksResponse>*, AsyncGetRemoteTasksRaw,
+ (ClientContext * context, const GetRemoteTasksRequest& request, CompletionQueue* cq,
+ void* tag));
+ MOCK_METHOD(ClientAsyncReaderInterface<GetRemoteTasksResponse>*, PrepareAsyncGetRemoteTasksRaw,
+ (ClientContext * context, const GetRemoteTasksRequest& request,
+ CompletionQueue* cq));
+ MOCK_METHOD(ClientAsyncResponseReaderInterface<NotifyWakeupRequiredResponse>*,
+ AsyncNotifyWakeupRequiredRaw,
+ (ClientContext * context, const NotifyWakeupRequiredRequest& request,
+ CompletionQueue* cq));
+ MOCK_METHOD(ClientAsyncResponseReaderInterface<NotifyWakeupRequiredResponse>*,
+ PrepareAsyncNotifyWakeupRequiredRaw,
+ (ClientContext * context, const NotifyWakeupRequiredRequest& request,
+ CompletionQueue* cq));
+};
+
+class FakeVhalClient final : public android::frameworks::automotive::vhal::IVhalClient {
+ public:
+ template <class T>
+ using VhalClientResult = android::hardware::automotive::vehicle::VhalResult<T>;
+
+ inline bool isAidlVhal() { return true; }
+
+ VhalClientResult<std::unique_ptr<IHalPropValue>> getValueSync(
+ const IHalPropValue& requestValue) override {
+ auto propValue = std::make_unique<AidlHalPropValue>(requestValue.getPropId());
+ propValue->setStringValue(kTestVin);
+ return propValue;
+ }
+
+ std::unique_ptr<IHalPropValue> createHalPropValue(int32_t propId) override {
+ return std::make_unique<AidlHalPropValue>(propId);
+ }
+
+ // Functions we do not care.
+ std::unique_ptr<IHalPropValue> createHalPropValue([[maybe_unused]] int32_t propId,
+ [[maybe_unused]] int32_t areaId) override {
+ return nullptr;
+ }
+
+ void getValue([[maybe_unused]] const IHalPropValue& requestValue,
+ [[maybe_unused]] std::shared_ptr<GetValueCallbackFunc> callback) override {}
+
+ void setValue([[maybe_unused]] const IHalPropValue& requestValue,
+ [[maybe_unused]] std::shared_ptr<SetValueCallbackFunc> callback) override {}
+
+ VhalClientResult<void> setValueSync([[maybe_unused]] const IHalPropValue& requestValue) {
+ return {};
+ }
+
+ VhalClientResult<void> addOnBinderDiedCallback(
+ [[maybe_unused]] std::shared_ptr<OnBinderDiedCallbackFunc> callback) override {
+ return {};
+ }
+
+ VhalClientResult<void> removeOnBinderDiedCallback(
+ [[maybe_unused]] std::shared_ptr<OnBinderDiedCallbackFunc> callback) override {
+ return {};
+ }
+
+ VhalClientResult<std::vector<std::unique_ptr<IHalPropConfig>>> getAllPropConfigs() override {
+ return std::vector<std::unique_ptr<IHalPropConfig>>();
+ }
+
+ VhalClientResult<std::vector<std::unique_ptr<IHalPropConfig>>> getPropConfigs(
+ [[maybe_unused]] std::vector<int32_t> propIds) override {
+ return std::vector<std::unique_ptr<IHalPropConfig>>();
+ }
+
+ std::unique_ptr<ISubscriptionClient> getSubscriptionClient(
+ [[maybe_unused]] std::shared_ptr<ISubscriptionCallback> callback) override {
+ return nullptr;
+ }
+};
+
+class FakeRemoteTaskCallback : public BnRemoteTaskCallback {
+ public:
+ ScopedAStatus onRemoteTaskRequested(const std::string& clientId,
+ const std::vector<uint8_t>& data) override {
+ std::lock_guard<std::mutex> lockGuard(mLock);
+ mDataByClientId[clientId] = data;
+ mTaskCount++;
+ mCv.notify_all();
+ return ScopedAStatus::ok();
+ }
+
+ std::vector<uint8_t> getData(const std::string& clientId) { return mDataByClientId[clientId]; }
+
+ bool wait(size_t taskCount, size_t timeoutInSec) {
+ std::unique_lock<std::mutex> lock(mLock);
+ return mCv.wait_for(lock, std::chrono::seconds(timeoutInSec), [taskCount, this] {
+ ScopedLockAssertion lockAssertion(mLock);
+ return mTaskCount >= taskCount;
+ });
+ }
+
+ private:
+ std::mutex mLock;
+ std::unordered_map<std::string, std::vector<uint8_t>> mDataByClientId GUARDED_BY(mLock);
+ size_t mTaskCount GUARDED_BY(mLock) = 0;
+ std::condition_variable mCv;
+};
+
+class RemoteAccessServiceUnitTest : public ::testing::Test {
+ public:
+ virtual void SetUp() override {
+ mGrpcWakeupClientStub = std::make_unique<MockGrpcClientStub>();
+ mService = ndk::SharedRefBase::make<RemoteAccessService>(mGrpcWakeupClientStub.get());
+ }
+
+ MockGrpcClientStub* getGrpcWakeupClientStub() { return mGrpcWakeupClientStub.get(); }
+
+ RemoteAccessService* getService() { return mService.get(); }
+
+ void setRetryWaitInMs(size_t retryWaitInMs) { mService->setRetryWaitInMs(retryWaitInMs); }
+
+ ScopedAStatus getDeviceIdWithClient(IVhalClient& vhalClient, std::string* deviceId) {
+ return mService->getDeviceIdWithClient(vhalClient, deviceId);
+ }
+
+ private:
+ std::unique_ptr<MockGrpcClientStub> mGrpcWakeupClientStub;
+ std::shared_ptr<RemoteAccessService> mService;
+};
+
+TEST_F(RemoteAccessServiceUnitTest, TestGetWakeupServiceName) {
+ std::string serviceName;
+
+ ScopedAStatus status = getService()->getWakeupServiceName(&serviceName);
+
+ EXPECT_TRUE(status.isOk());
+ EXPECT_EQ(serviceName, "com.google.vehicle.wakeup");
+}
+
+TEST_F(RemoteAccessServiceUnitTest, TestNotifyApStateChangeWakeupRequired) {
+ bool isWakeupRequired = false;
+ EXPECT_CALL(*getGrpcWakeupClientStub(), NotifyWakeupRequired)
+ .WillOnce([&isWakeupRequired]([[maybe_unused]] ClientContext* context,
+ const NotifyWakeupRequiredRequest& request,
+ [[maybe_unused]] NotifyWakeupRequiredResponse* response) {
+ isWakeupRequired = request.iswakeuprequired();
+ return Status();
+ });
+
+ ApState newState = {
+ .isWakeupRequired = true,
+ };
+ ScopedAStatus status = getService()->notifyApStateChange(newState);
+
+ EXPECT_TRUE(status.isOk());
+ EXPECT_TRUE(isWakeupRequired);
+}
+
+TEST_F(RemoteAccessServiceUnitTest, TestGetRemoteTasks) {
+ GetRemoteTasksResponse response1;
+ std::vector<uint8_t> testData = {0xde, 0xad, 0xbe, 0xef};
+ response1.set_clientid("1");
+ response1.set_data(testData.data(), testData.size());
+ GetRemoteTasksResponse response2;
+ response2.set_clientid("2");
+ std::shared_ptr<FakeRemoteTaskCallback> callback =
+ ndk::SharedRefBase::make<FakeRemoteTaskCallback>();
+
+ ON_CALL(*getGrpcWakeupClientStub(), GetRemoteTasksRaw)
+ .WillByDefault(
+ [response1, response2]([[maybe_unused]] ClientContext* context,
+ [[maybe_unused]] const GetRemoteTasksRequest& request) {
+ // mockReader ownership will be transferred to the client so we don't own it
+ // here.
+ MockClientReader<GetRemoteTasksResponse>* mockClientReader =
+ new MockClientReader<GetRemoteTasksResponse>();
+ EXPECT_CALL(*mockClientReader, Finish()).WillOnce(Return(Status::OK));
+ EXPECT_CALL(*mockClientReader, Read(_))
+ .WillOnce(DoAll(SetArgPointee<0>(response1), Return(true)))
+ .WillOnce(DoAll(SetArgPointee<0>(response2), Return(true)))
+ .WillRepeatedly(Return(false));
+ return mockClientReader;
+ });
+
+ getService()->setRemoteTaskCallback(callback);
+ // Start the long live connection to receive tasks.
+ ApState newState = {
+ .isReadyForRemoteTask = true,
+ };
+ ASSERT_TRUE(getService()->notifyApStateChange(newState).isOk());
+
+ ASSERT_TRUE(callback->wait(/*taskCount=*/2, /*timeoutInSec=*/10))
+ << "Did not receive enough tasks";
+ EXPECT_EQ(callback->getData("1"), testData);
+ EXPECT_EQ(callback->getData("2"), std::vector<uint8_t>());
+}
+
+TEST_F(RemoteAccessServiceUnitTest, TestGetRemoteTasksRetryConnection) {
+ GetRemoteTasksResponse response;
+ std::shared_ptr<FakeRemoteTaskCallback> callback =
+ ndk::SharedRefBase::make<FakeRemoteTaskCallback>();
+
+ ON_CALL(*getGrpcWakeupClientStub(), GetRemoteTasksRaw)
+ .WillByDefault([response]([[maybe_unused]] ClientContext* context,
+ [[maybe_unused]] const GetRemoteTasksRequest& request) {
+ // mockReader ownership will be transferred to the client so we don't own it here.
+ MockClientReader<GetRemoteTasksResponse>* mockClientReader =
+ new MockClientReader<GetRemoteTasksResponse>();
+ EXPECT_CALL(*mockClientReader, Finish()).WillOnce(Return(Status::OK));
+ // Connection fails after receiving one task. Should retry after some time.
+ EXPECT_CALL(*mockClientReader, Read(_))
+ .WillOnce(DoAll(SetArgPointee<0>(response), Return(true)))
+ .WillRepeatedly(Return(false));
+ return mockClientReader;
+ });
+
+ getService()->setRemoteTaskCallback(callback);
+ setRetryWaitInMs(100);
+ // Start the long live connection to receive tasks.
+ ApState newState = {
+ .isReadyForRemoteTask = true,
+ };
+ ASSERT_TRUE(getService()->notifyApStateChange(newState).isOk());
+
+ ASSERT_TRUE(callback->wait(/*taskCount=*/2, /*timeoutInSec=*/10))
+ << "Did not receive enough tasks";
+}
+
+TEST_F(RemoteAccessServiceUnitTest, TestGetRemoteTasksDefaultNotReady) {
+ GetRemoteTasksResponse response1;
+ std::vector<uint8_t> testData = {0xde, 0xad, 0xbe, 0xef};
+ response1.set_clientid("1");
+ response1.set_data(testData.data(), testData.size());
+ GetRemoteTasksResponse response2;
+ response2.set_clientid("2");
+ std::shared_ptr<FakeRemoteTaskCallback> callback =
+ ndk::SharedRefBase::make<FakeRemoteTaskCallback>();
+
+ EXPECT_CALL(*getGrpcWakeupClientStub(), GetRemoteTasksRaw).Times(0);
+
+ // Default state is not ready for remote tasks, so no callback will be called.
+ getService()->setRemoteTaskCallback(callback);
+
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+}
+
+TEST_F(RemoteAccessServiceUnitTest, TestGetRemoteTasksNotReadyAfterReady) {
+ GetRemoteTasksResponse response1;
+ std::vector<uint8_t> testData = {0xde, 0xad, 0xbe, 0xef};
+ response1.set_clientid("1");
+ response1.set_data(testData.data(), testData.size());
+ GetRemoteTasksResponse response2;
+ response2.set_clientid("2");
+ std::shared_ptr<FakeRemoteTaskCallback> callback =
+ ndk::SharedRefBase::make<FakeRemoteTaskCallback>();
+
+ ON_CALL(*getGrpcWakeupClientStub(), GetRemoteTasksRaw)
+ .WillByDefault(
+ [response1, response2]([[maybe_unused]] ClientContext* context,
+ [[maybe_unused]] const GetRemoteTasksRequest& request) {
+ // mockReader ownership will be transferred to the client so we don't own it
+ // here.
+ MockClientReader<GetRemoteTasksResponse>* mockClientReader =
+ new MockClientReader<GetRemoteTasksResponse>();
+ EXPECT_CALL(*mockClientReader, Finish()).WillOnce(Return(Status::OK));
+ EXPECT_CALL(*mockClientReader, Read(_))
+ .WillOnce(DoAll(SetArgPointee<0>(response1), Return(true)))
+ .WillOnce(DoAll(SetArgPointee<0>(response2), Return(true)))
+ .WillRepeatedly(Return(false));
+ return mockClientReader;
+ });
+ // Should only be called once when is is ready for remote task.
+ EXPECT_CALL(*getGrpcWakeupClientStub(), GetRemoteTasksRaw).Times(1);
+
+ getService()->setRemoteTaskCallback(callback);
+ setRetryWaitInMs(100);
+ // Start the long live connection to receive tasks.
+ ApState newState = {
+ .isReadyForRemoteTask = true,
+ };
+ ASSERT_TRUE(getService()->notifyApStateChange(newState).isOk());
+ ASSERT_TRUE(callback->wait(/*taskCount=*/2, /*timeoutInSec=*/10))
+ << "Did not receive enough tasks";
+
+ // Stop the long live connection.
+ newState.isReadyForRemoteTask = false;
+ ASSERT_TRUE(getService()->notifyApStateChange(newState).isOk());
+
+ // Wait for the retry delay, but the loop should already exit.
+ std::this_thread::sleep_for(std::chrono::milliseconds(150));
+}
+
+TEST_F(RemoteAccessServiceUnitTest, testGetDeviceId) {
+ std::string deviceId;
+
+ FakeVhalClient vhalClient;
+
+ ASSERT_TRUE(getDeviceIdWithClient(vhalClient, &deviceId).isOk());
+ ASSERT_EQ(deviceId, kTestVin);
+}
+
+} // namespace remoteaccess
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/remoteaccess/test_grpc_server/README.md b/automotive/remoteaccess/test_grpc_server/README.md
new file mode 100644
index 0000000..6bc1829
--- /dev/null
+++ b/automotive/remoteaccess/test_grpc_server/README.md
@@ -0,0 +1,314 @@
+# Test GRPC Server.
+
+A test GRPC server that implements wakeup_client.proto. This test server acts
+as a reference implementation for a remote wakeup client running on TCU. The
+test server does not communicate with any actual network server. It has the
+following behavior:
+
+* It starts a GRPC server on 'DGRPC_SERVICE_ADDRESS' compile flag which is
+ localhost:50051. The GRPC server provides the service according to
+ hardware/interfaces/automotive/remoteaccess/hal/default/proto/wakeup_client.proto.
+
+ In real implementation, DGRPC_SERVICE_ADDRESS can be specified to any IP
+ address where the TCU can be exposed to Application Processor. The default
+ remote access HAL implementation
+ (hardware/interfaces/automotive/remoteaccess/hal/default/Android.bp) also
+ uses DGRPC_SERVICE_ADDRESS to find this GRPC server, so it must have the
+ same IP address.
+
+* It generates a fake task using FakeTaskGenerator every 'kTaskIntervalInMs' ms.
+
+ In real implementation, it should receive task from the remote server.
+
+* Each fake task has an increasing unique client ID. The task data is always
+ what's defined for 'DATA' variable.
+
+ In real implementation, the client ID and task data should come from the
+ remote server.
+
+* The generated tasks are put into a task queue which is a priority queue sorted
+ by task received time.
+
+ In real implementation, if the server provides a task timestamp, then this
+ queue can be sorted by that task timestamp instead.
+
+* When the Application processor is started, the remote access HAL running on
+ Android will call 'GetRemoteTasks' to establish a long-live connection. This
+ connection is used to deliver all task data from remote wakeup client to
+ remote access HAL, which eventually to car service and applications.
+
+ When the 'GetRemoteTasks' is called, the wakeup client must send all the
+ pending tasks through the 'ServerWriter'. If no task is pending, then it must
+ block and wait for a new task to arrive.
+
+ If one task data fails to be sent through the channel, it likely means
+ the other side (Application processor) is shutting down or has closed the
+ channel. The wakeup client must put the task back to the pending queue and
+ wait for a new 'GetRemoteTasks' request to retry sending the task.
+
+* When a new task arrives, if 'WakeupRequired' is true, then try to wakeup
+ the Application Processor by sending a specific CAN message. It is possible that
+ the waking up is already in progress. This is okay since Vehicle Processor
+ should ignore wakeup message if a wakeup is already in progress.
+
+* When 'WakeupRequired' is updated from false to true, if there are unexpired
+ pending tasks in the task queue, try to wakeup Application Processor.
+
+ This is to handle the situation when a task arrives while the device is
+ shutting down. During the device shutdown, the channel to deliver the remote
+ tasks to Application Processor is shutdown so the new task will be added to the
+ task queue. 'WakeupRequired' will be set to false to prevent the wakeup
+ message preventing the shutdown. After the shutdown is complete,
+ 'WakeupRequired' will be set to true and this wakeup client must try to wake
+ up the device again to execute the pending tasks.
+
+* Every pending task has a timeout: 'kTaskTimeoutInMs'. If the pending task
+ is not delivered to remote access HAL before the timeout (through
+ GetRemoteTasks), the task timed out and a warning message is logged.
+
+ In real implementation, this kTaskTimeoutInMs has to be set long enough to
+ allow an Android bootup to happen. 20s is a reasonable value. When a task
+ timed out, the wakeup client should also report to remote task server about
+ the task timeout failure.
+
+## How to build the test wakeup client
+
+* Under android root: `source build/envsetup.sh`
+
+* `lunch sdk_car_x86_64-userdebug`
+
+* `make -j TestWakeupClientServer`
+
+* `make -j ApPowerControlLib`
+
+## How to push the test wakeup client to a TCU which runs Android.
+
+* Make the target device writable:
+
+ `adb root`
+
+ `adb remount` (remount might take a while)
+
+ `adb reboot`
+
+ `adb root`
+
+ `adb remount`
+
+* Under android root: `cd $ANDROID_PRODUCT_OUT`
+
+* `adb push vendor/bin/TestWakeupClientServer /vendor/bin`
+
+* `adb push vendor/lib/ApPowerControlLib.so /vendor/lib`
+
+* `adb shell`
+
+* `su`
+
+* `/vendor/bin/TestWakeupClientServer`
+
+## How to build and test the test wakeup client using one car emulator.
+
+In this test setup we will use one car emulator
+(sdk_car_x86_64-userdebug). We assume both the TCU and the remote access HAL
+runs on the same Android system, and they communicate through local loopback
+interface.
+
+* Under android root, `source build/envsetup.sh`
+
+* `lunch sdk_car_x86_64-userdebug`
+
+* `m -j`
+
+* Run the emulator, the '-read-only' flag is required to run multiple instances:
+
+ `emulator -writable-system -read-only`
+
+* The android lunch target: sdk_car_x86_64-userdebug and
+ cf_x86_64_auto-userdebug already contains the default remote access HAL. For
+ other lunch target, you can add the default remote access HAL by adding
+ 'android.hardware.automotive.remoteaccess@V1-default-service' to
+ 'PRODUCT_PACKAGES' variable in mk file, see `device/generic/car/common/car.mk`
+ as example.
+
+ To verify whether remote access HAL is running, you can use the following
+ command to check:
+
+ `dumpsys android.hardware.automotive.remoteaccess.IRemoteAccess/default`
+
+* Make the target device writable:
+
+ `adb root`
+
+ `adb remount` (remount might take a while)
+
+ `adb reboot`
+
+ `adb root`
+
+ `adb remount`
+
+* `make -j TestWakeupClientServer`
+
+* `adb push $ANDROID_PRODUCT_OUT/vendor/bin/TestWakeupClientServer /vendor/bin`
+
+* `adb shell`
+
+* `emulator_car_x86_64:/ # su`
+
+* `emulator_car_x86_64:/ # /vendor/bin/TestWakeupClientServer`
+
+* Remote access HAL should start by default when the car emulator starts. Now
+ the test wake up client should also be running and generating fake tasks.
+
+ Start a new session under android root
+
+ `source build/envsetup.sh`
+
+ `lunch sdk_car_x86_64-userdebug`
+
+ `adb shell`
+
+ `emulator_car_x86_64:/ # su`
+
+* Issue the command to start a simple debug callback that will capture all the
+ received tasks at the remote access HAL side:
+
+ `emulator_car_x86_64:/ # dumpsys android.hardware.automotive.remoteaccess.IRemoteAccess/default --start-debug-callback`
+
+* Issue the following debug command to remote access HAL to establish the
+ communication channel between it and the test wakeup client. This command
+ also notifies that wakeup is not required:
+
+ `emulator_car_x86_64:/ # dumpsys android.hardware.automotive.remoteaccess.IRemoteAccess/default --set-ap-state 1 0`
+
+* Wait for a while, issue the following command to show the received fake tasks:
+
+ `emulator_car_x86_64:/ # dumpsys android.hardware.automotive.remoteaccess.IRemoteAccess/default --show-task`
+
+ You should expect to see some received tasks printed out.
+
+* Simulate the Application Processor is shutting down by issuing the following
+ command:
+
+ `emulator_car_x86_64:/ # dumpsys android.hardware.automotive.remoteaccess.IRemoteAccess/default --set-ap-state 0 0`
+
+* Wait for a while, issue the following command to show received tasks again:
+
+ `emulator_car_x86_64:/ # dumpsys android.hardware.automotive.remoteaccess.IRemoteAccess/default --show-task`
+
+ You should expect to see no new tasks received since remote access HAL already
+ closed the communication channel.
+
+* Simulate the Application Processor is already shutdown and wake up is required
+ now:
+
+ `emulator_car_x86_64:/ # dumpsys android.hardware.automotive.remoteaccess.IRemoteAccess/default --set-ap-state 0 1`
+
+ Now you should expect to see the test wakeup client printing out messages
+ that it is trying to wake up application processor.
+
+* Simulate the Application Processor is waken up:
+
+ `emulator_car_x86_64:/ # dumpsys android.hardware.automotive.remoteaccess.IRemoteAccess/default --set-ap-state 1 0`
+
+* A new communication channel should have been established and all pending
+ non-expired tasks should be delivered to the remote access HAL.
+
+ `emulator_car_x86_64:/ # dumpsys android.hardware.automotive.remoteaccess.IRemoteAccess/default --show-task`
+
+* Now you can issue `ctrl c` on the first adb shell to stop the test wakeup
+ client.
+
+* After the test, you can use `ctrl D` to exit the adb shell.
+
+## How to build and test the test wakeup client using two car emulators.
+
+In this test case, we are going to use two car emulators, one as the
+Application Processor, one as the TCU.
+
+* Change the IP address to allow IP communication between different emulator
+ instances. For detail about why we change it this way, see [interconnecting
+ emulator instance](https://developer.android.com/studio/run/emulator-networking#connecting).
+
+ Change 'DGRPC_SERVICE_ADDRESS' in `[android_root]/hardware/interfaces/automotive/remoteaccess/test_grpc_server/impl/Android.bp` to
+ `10.0.2.15:50051`.
+
+ Change `DGRPC_SERVICE_ADDRESS` in '[android_root]/hardware/interfaces/automotive/remoteaccess/hal/defaut/Android.bp' to
+ `10.0.2.2:50051`.
+
+* Under android root: `source build/envsetup.sh`
+
+* `lunch sdk_car_x86_64-userdebug`
+
+* `m -j`
+
+* Start one car emulator as TCU
+
+ `emulator -writable-system -read-only`
+
+* Start a new shell session. Connect to the emulator's console,
+ see [Start and stop a console session](https://developer.android.com/studio/run/emulator-console#console-session)
+ for detail.
+
+ `telnet localhost 5554`
+
+* `auth auth_token` where auth_token must match the contents of the
+ `~/.emulator_console_auth_token` file.
+
+* `redir add tcp:50051:50051`
+
+* Exit the telnet session using 'ctrl-C'
+
+ Make the target device writable:
+
+ Under android root:
+
+ `source build/envsetup.sh`
+
+ `lunch sdk_car_x86_64-userdebug`
+
+ `adb root`
+
+ `adb remount` (remount might take a while)
+
+ `adb reboot`
+
+ `adb root`
+
+ `adb remount`
+
+* `make -j TestWakeupClientServer`
+
+* `adb push $ANDROID_PRODUCT_OUT/vendor/bin/TestWakeupClientServer /vendor/bin`
+
+* `adb shell`
+
+* `emulator_car_x86_64:/ # su`
+
+* `emulator_car_x86_64:/ # /vendor/bin/TestWakeupClientServer`
+
+* Start a new shell under android root, start another car emulator as the Application Processor:
+
+ `source build/envsetup.sh`
+
+ `lunch sdk_car_x86_64-userdebug`
+
+ `emulator -writable-system -read-only`
+
+* Open a new shell under android root:
+
+ `source build/envsetup.sh`
+
+ `lunch sdk_car_x86_64-userdebug`
+
+* Connect to adb shell for the application processor:
+
+ `adb -s emulator-5556 shell`
+
+ `emulator_car_x86_64:/ # su`
+
+* Follow the test instructions for one car emulator using the 'dumpsys'
+ commands.
+
+* After the test, you can use `ctrl D` to exit the adb shell.
diff --git a/automotive/remoteaccess/test_grpc_server/impl/Android.bp b/automotive/remoteaccess/test_grpc_server/impl/Android.bp
new file mode 100644
index 0000000..152b528
--- /dev/null
+++ b/automotive/remoteaccess/test_grpc_server/impl/Android.bp
@@ -0,0 +1,43 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_binary {
+ name: "TestWakeupClientServer",
+ vendor: true,
+ srcs: ["src/*.cpp"],
+ local_include_dirs: ["include"],
+ shared_libs: [
+ "libbase",
+ "libutils",
+ "libgrpc++",
+ "libprotobuf-cpp-full",
+ "//hardware/interfaces/automotive/remoteaccess/test_grpc_server/lib:ApPowerControlLib",
+ ],
+ whole_static_libs: [
+ "wakeup_client_protos",
+ ],
+ cflags: [
+ "-Wno-unused-parameter",
+ "-DGRPC_SERVICE_ADDRESS=\"localhost:50051\"",
+ ],
+}
diff --git a/automotive/remoteaccess/test_grpc_server/impl/include/TestWakeupClientServiceImpl.h b/automotive/remoteaccess/test_grpc_server/impl/include/TestWakeupClientServiceImpl.h
new file mode 100644
index 0000000..6b86b35
--- /dev/null
+++ b/automotive/remoteaccess/test_grpc_server/impl/include/TestWakeupClientServiceImpl.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android-base/thread_annotations.h>
+#include <utils/Looper.h>
+#include <wakeup_client.grpc.pb.h>
+#include <condition_variable>
+#include <mutex>
+#include <queue>
+#include <string>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace remoteaccess {
+
+// A class to generate fake task for testing. Not required for real implementation. In real
+// implementation, the task should come from remote task server. This class is thread-safe.
+class FakeTaskGenerator final {
+ public:
+ GetRemoteTasksResponse generateTask();
+
+ private:
+ // Simulates the client ID for each task.
+ std::atomic<int> mCurrentClientId = 0;
+ constexpr static uint8_t DATA[] = {0xde, 0xad, 0xbe, 0xef};
+};
+
+struct TaskInfo {
+ // This is unique per-task. Note that a task might be popped and put back into the task queue,
+ // it will have a new task ID but the same clientId in the task data.
+ int taskId;
+ int64_t timestampInMs;
+ GetRemoteTasksResponse taskData;
+};
+
+struct TaskInfoComparator {
+ // We want the smallest timestamp and smallest task ID on top.
+ bool operator()(const TaskInfo& l, const TaskInfo& r) {
+ return l.timestampInMs > r.timestampInMs ||
+ (l.timestampInMs == r.timestampInMs && l.taskId > r.taskId);
+ }
+};
+
+// forward-declaration.
+class TaskQueue;
+
+class TaskTimeoutMessageHandler final : public android::MessageHandler {
+ public:
+ TaskTimeoutMessageHandler(TaskQueue* taskQueue);
+ void handleMessage(const android::Message& message) override;
+
+ private:
+ TaskQueue* mTaskQueue;
+};
+
+// TaskQueue is thread-safe.
+class TaskQueue final {
+ public:
+ TaskQueue();
+ ~TaskQueue();
+
+ void add(const GetRemoteTasksResponse& response);
+ std::optional<GetRemoteTasksResponse> maybePopOne();
+ void waitForTask();
+ void stopWait();
+ void handleTaskTimeout();
+ bool isEmpty();
+
+ private:
+ std::thread mCheckTaskTimeoutThread;
+ std::mutex mLock;
+ std::priority_queue<TaskInfo, std::vector<TaskInfo>, TaskInfoComparator> mTasks
+ GUARDED_BY(mLock);
+ // A variable to notify mTasks is not empty.
+ std::condition_variable mTasksNotEmptyCv;
+ bool mStopped GUARDED_BY(mLock);
+ android::sp<Looper> mLooper;
+ android::sp<TaskTimeoutMessageHandler> mTaskTimeoutMessageHandler;
+ std::atomic<int> mTaskIdCounter = 0;
+
+ void checkForTestTimeoutLoop();
+ void waitForTaskWithLock(std::unique_lock<std::mutex>& lock);
+};
+
+class TestWakeupClientServiceImpl final : public WakeupClient::Service {
+ public:
+ TestWakeupClientServiceImpl();
+
+ ~TestWakeupClientServiceImpl();
+
+ grpc::Status GetRemoteTasks(grpc::ServerContext* context, const GetRemoteTasksRequest* request,
+ grpc::ServerWriter<GetRemoteTasksResponse>* writer) override;
+
+ grpc::Status NotifyWakeupRequired(grpc::ServerContext* context,
+ const NotifyWakeupRequiredRequest* request,
+ NotifyWakeupRequiredResponse* response) override;
+
+ private:
+ // This is a thread for communicating with remote wakeup server (via network) and receive tasks
+ // from it.
+ std::thread mThread;
+ // A variable to notify server is stopping.
+ std::condition_variable mServerStoppedCv;
+ // Whether wakeup AP is required for executing tasks.
+ std::atomic<bool> mWakeupRequired = true;
+ std::mutex mLock;
+ bool mServerStopped GUARDED_BY(mLock);
+
+ // Thread-safe. For test impl only.
+ FakeTaskGenerator mFakeTaskGenerator;
+ // Thread-sfae.
+ TaskQueue mTaskQueue;
+
+ void fakeTaskGenerateLoop();
+
+ void wakeupApplicationProcessor();
+};
+
+} // namespace remoteaccess
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/remoteaccess/test_grpc_server/impl/src/TestWakeupClientServiceImpl.cpp b/automotive/remoteaccess/test_grpc_server/impl/src/TestWakeupClientServiceImpl.cpp
new file mode 100644
index 0000000..7dcd31e
--- /dev/null
+++ b/automotive/remoteaccess/test_grpc_server/impl/src/TestWakeupClientServiceImpl.cpp
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "TestWakeupClientServiceImpl.h"
+
+#include "ApPowerControl.h"
+
+#include <android-base/stringprintf.h>
+#include <inttypes.h>
+#include <utils/Looper.h>
+#include <utils/SystemClock.h>
+#include <chrono>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace remoteaccess {
+
+namespace {
+
+using ::android::uptimeMillis;
+using ::android::base::ScopedLockAssertion;
+using ::android::base::StringPrintf;
+using ::grpc::ServerContext;
+using ::grpc::ServerWriter;
+using ::grpc::Status;
+
+constexpr int kTaskIntervalInMs = 5'000;
+constexpr int64_t KTaskTimeoutInMs = 20'000;
+
+} // namespace
+
+GetRemoteTasksResponse FakeTaskGenerator::generateTask() {
+ int clientId = mCurrentClientId++;
+ GetRemoteTasksResponse response;
+ response.set_data(std::string(reinterpret_cast<const char*>(DATA), sizeof(DATA)));
+ std::string clientIdStr = StringPrintf("%d", clientId);
+ response.set_clientid(clientIdStr);
+ return response;
+}
+
+TaskTimeoutMessageHandler::TaskTimeoutMessageHandler(TaskQueue* taskQueue)
+ : mTaskQueue(taskQueue) {}
+
+void TaskTimeoutMessageHandler::handleMessage(const android::Message& message) {
+ mTaskQueue->handleTaskTimeout();
+}
+
+TaskQueue::TaskQueue() {
+ mTaskTimeoutMessageHandler = android::sp<TaskTimeoutMessageHandler>::make(this);
+ mLooper = Looper::prepare(/*opts=*/0);
+ mCheckTaskTimeoutThread = std::thread([this] { checkForTestTimeoutLoop(); });
+}
+
+TaskQueue::~TaskQueue() {
+ {
+ std::lock_guard<std::mutex> lockGuard(mLock);
+ mStopped = true;
+ }
+ while (true) {
+ // Remove all pending timeout handlers from queue.
+ if (!maybePopOne().has_value()) {
+ break;
+ }
+ }
+ if (mCheckTaskTimeoutThread.joinable()) {
+ mCheckTaskTimeoutThread.join();
+ }
+}
+
+std::optional<GetRemoteTasksResponse> TaskQueue::maybePopOne() {
+ std::lock_guard<std::mutex> lockGuard(mLock);
+ if (mTasks.size() == 0) {
+ return std::nullopt;
+ }
+ TaskInfo response = std::move(mTasks.top());
+ mTasks.pop();
+ mLooper->removeMessages(mTaskTimeoutMessageHandler, response.taskId);
+ return std::move(response.taskData);
+}
+
+void TaskQueue::add(const GetRemoteTasksResponse& task) {
+ std::lock_guard<std::mutex> lockGuard(mLock);
+ if (mStopped) {
+ return;
+ }
+ int taskId = mTaskIdCounter++;
+ mTasks.push(TaskInfo{
+ .taskId = taskId,
+ .timestampInMs = uptimeMillis(),
+ .taskData = task,
+ });
+ android::Message message(taskId);
+ mLooper->sendMessageDelayed(KTaskTimeoutInMs * 1000, mTaskTimeoutMessageHandler, message);
+ mTasksNotEmptyCv.notify_all();
+}
+
+void TaskQueue::waitForTask() {
+ std::unique_lock<std::mutex> lock(mLock);
+ waitForTaskWithLock(lock);
+}
+
+void TaskQueue::waitForTaskWithLock(std::unique_lock<std::mutex>& lock) {
+ mTasksNotEmptyCv.wait(lock, [this] {
+ ScopedLockAssertion lockAssertion(mLock);
+ return mTasks.size() > 0 || mStopped;
+ });
+}
+
+void TaskQueue::stopWait() {
+ std::lock_guard<std::mutex> lockGuard(mLock);
+ mStopped = true;
+ mTasksNotEmptyCv.notify_all();
+}
+
+bool TaskQueue::isEmpty() {
+ std::lock_guard<std::mutex> lockGuard(mLock);
+ return mTasks.size() == 0 || mStopped;
+}
+
+void TaskQueue::checkForTestTimeoutLoop() {
+ Looper::setForThread(mLooper);
+
+ while (true) {
+ {
+ std::unique_lock<std::mutex> lock(mLock);
+ if (mStopped) {
+ return;
+ }
+ }
+
+ mLooper->pollAll(/*timeoutMillis=*/-1);
+ }
+}
+
+void TaskQueue::handleTaskTimeout() {
+ // We know which task timed-out from the taskId in the message. However, there is no easy way
+ // to remove a specific task with the task ID from the priority_queue, so we just check from
+ // the top of the queue (which have the oldest tasks).
+ std::lock_guard<std::mutex> lockGuard(mLock);
+ int64_t now = uptimeMillis();
+ while (mTasks.size() > 0) {
+ const TaskInfo& taskInfo = mTasks.top();
+ if (taskInfo.timestampInMs + KTaskTimeoutInMs > now) {
+ break;
+ }
+ // In real implementation, this should report task failure to remote wakeup server.
+ printf("Task for client ID: %s timed-out, added at %" PRId64 " ms, now %" PRId64 " ms",
+ taskInfo.taskData.clientid().c_str(), taskInfo.timestampInMs, now);
+ mTasks.pop();
+ }
+}
+
+TestWakeupClientServiceImpl::TestWakeupClientServiceImpl() {
+ mThread = std::thread([this] { fakeTaskGenerateLoop(); });
+}
+
+TestWakeupClientServiceImpl::~TestWakeupClientServiceImpl() {
+ {
+ std::lock_guard<std::mutex> lockGuard(mLock);
+ mServerStopped = true;
+ mServerStoppedCv.notify_all();
+ }
+ mTaskQueue.stopWait();
+ if (mThread.joinable()) {
+ mThread.join();
+ }
+}
+
+void TestWakeupClientServiceImpl::fakeTaskGenerateLoop() {
+ // In actual implementation, this should communicate with the remote server and receives tasks
+ // from it. Here we simulate receiving one remote task every {kTaskIntervalInMs}ms.
+ while (true) {
+ mTaskQueue.add(mFakeTaskGenerator.generateTask());
+ printf("Received a new task\n");
+ if (mWakeupRequired) {
+ wakeupApplicationProcessor();
+ }
+
+ printf("Sleeping for %d seconds until next task\n", kTaskIntervalInMs);
+
+ std::unique_lock lk(mLock);
+ if (mServerStoppedCv.wait_for(lk, std::chrono::milliseconds(kTaskIntervalInMs), [this] {
+ ScopedLockAssertion lockAssertion(mLock);
+ return mServerStopped;
+ })) {
+ // If the stopped flag is set, we are quitting, exit the loop.
+ return;
+ }
+ }
+}
+
+Status TestWakeupClientServiceImpl::GetRemoteTasks(ServerContext* context,
+ const GetRemoteTasksRequest* request,
+ ServerWriter<GetRemoteTasksResponse>* writer) {
+ printf("GetRemoteTasks called\n");
+ while (true) {
+ mTaskQueue.waitForTask();
+
+ while (true) {
+ auto maybeTask = mTaskQueue.maybePopOne();
+ if (!maybeTask.has_value()) {
+ // No task left, loop again and wait for another task(s).
+ break;
+ }
+ // Loop through all the task in the queue but obtain lock for each element so we don't
+ // hold lock while writing the response.
+ const GetRemoteTasksResponse& response = maybeTask.value();
+ if (!writer->Write(response)) {
+ // Broken stream, maybe the client is shutting down.
+ printf("Failed to deliver remote task to remote access HAL\n");
+ // The task failed to be sent, add it back to the queue. The order might change, but
+ // it is okay.
+ mTaskQueue.add(response);
+ return Status::CANCELLED;
+ }
+ }
+ }
+ return Status::OK;
+}
+
+Status TestWakeupClientServiceImpl::NotifyWakeupRequired(ServerContext* context,
+ const NotifyWakeupRequiredRequest* request,
+ NotifyWakeupRequiredResponse* response) {
+ if (request->iswakeuprequired() && !mWakeupRequired && !mTaskQueue.isEmpty()) {
+ // If wakeup is now required and previously not required, this means we have finished
+ // shutting down the device. If there are still pending tasks, try waking up AP again
+ // to finish executing those tasks.
+ wakeupApplicationProcessor();
+ }
+ mWakeupRequired = request->iswakeuprequired();
+ return Status::OK;
+}
+
+void TestWakeupClientServiceImpl::wakeupApplicationProcessor() {
+ wakeupAp();
+}
+
+} // namespace remoteaccess
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/remoteaccess/test_grpc_server/impl/src/main.cpp b/automotive/remoteaccess/test_grpc_server/impl/src/main.cpp
new file mode 100644
index 0000000..d3f519c
--- /dev/null
+++ b/automotive/remoteaccess/test_grpc_server/impl/src/main.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string>
+
+#include "TestWakeupClientServiceImpl.h"
+
+#include <grpc/grpc.h>
+#include <grpcpp/security/server_credentials.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
+
+using ::android::hardware::automotive::remoteaccess::TestWakeupClientServiceImpl;
+using ::grpc::Server;
+using ::grpc::ServerBuilder;
+using ::grpc::ServerWriter;
+
+void RunServer(const std::string& serviceAddr) {
+ std::shared_ptr<TestWakeupClientServiceImpl> service =
+ std::make_unique<TestWakeupClientServiceImpl>();
+
+ ServerBuilder builder;
+ builder.AddListeningPort(serviceAddr, grpc::InsecureServerCredentials());
+ builder.RegisterService(service.get());
+ std::unique_ptr<Server> server(builder.BuildAndStart());
+ printf("Test Remote Access GRPC Server listening on %s\n", serviceAddr.c_str());
+ server->Wait();
+}
+
+int main(int argc, char** argv) {
+ std::string serviceAddr = GRPC_SERVICE_ADDRESS;
+ if (argc > 1) {
+ serviceAddr = argv[1];
+ }
+ RunServer(serviceAddr);
+ return 0;
+}
diff --git a/automotive/remoteaccess/test_grpc_server/lib/Android.bp b/automotive/remoteaccess/test_grpc_server/lib/Android.bp
new file mode 100644
index 0000000..7e95f53
--- /dev/null
+++ b/automotive/remoteaccess/test_grpc_server/lib/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+soong_namespace {}
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_shared {
+ name: "ApPowerControlLib",
+ vendor: true,
+ srcs: ["*.cpp"],
+ local_include_dirs: ["."],
+ export_include_dirs: ["."],
+}
diff --git a/automotive/remoteaccess/test_grpc_server/lib/ApPowerControl.cpp b/automotive/remoteaccess/test_grpc_server/lib/ApPowerControl.cpp
new file mode 100644
index 0000000..862fed1
--- /dev/null
+++ b/automotive/remoteaccess/test_grpc_server/lib/ApPowerControl.cpp
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ApPowerControl.h"
+
+#include <cstdio>
+
+void wakeupAp() {
+ printf("Waking up application processor...\n");
+}
diff --git a/automotive/remoteaccess/test_grpc_server/lib/ApPowerControl.h b/automotive/remoteaccess/test_grpc_server/lib/ApPowerControl.h
new file mode 100644
index 0000000..9560576
--- /dev/null
+++ b/automotive/remoteaccess/test_grpc_server/lib/ApPowerControl.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Wakeup application processor if not already waken up.
+void wakeupAp();
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/automotive/sv/OWNERS b/automotive/sv/OWNERS
new file mode 100644
index 0000000..af6788b
--- /dev/null
+++ b/automotive/sv/OWNERS
@@ -0,0 +1 @@
+tanmayp@google.com
diff --git a/automotive/vehicle/2.0/default/VehicleService.cpp b/automotive/vehicle/2.0/default/VehicleService.cpp
index 12e15f9..2968232 100644
--- a/automotive/vehicle/2.0/default/VehicleService.cpp
+++ b/automotive/vehicle/2.0/default/VehicleService.cpp
@@ -33,7 +33,7 @@
auto store = std::make_unique<VehiclePropertyStore>();
auto connector = std::make_unique<DefaultVehicleConnector>();
auto hal = std::make_unique<DefaultVehicleHal>(store.get(), connector.get());
- auto service = std::make_unique<VehicleHalManager>(hal.get());
+ auto service = android::sp<VehicleHalManager>::make(hal.get());
connector->setValuePool(hal->getValuePool());
android::hardware::configureRpcThreadpool(4, true /* callerWillJoin */);
diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal
index 7c8e1f5..9e4f252 100644
--- a/automotive/vehicle/2.0/types.hal
+++ b/automotive/vehicle/2.0/types.hal
@@ -1632,10 +1632,8 @@
*
* The Android properties are:
*
- * int32Values[0] : Input code identifying the function representing this event. Valid event
- * types are defined by CustomInputType.CUSTOM_EVENT_F1 up to
- * CustomInputType.CUSTOM_EVENT_F10. They represent the custom event to be
- * defined by OEM partners.
+ * int32Values[0] : Input code identifying the function representing this event. OEMs are free
+ * to use any signed 32 bits number to represent the input code value.
* int32Values[1] : target display type defined in VehicleDisplay. Events not tied to specific
* display must be sent to VehicleDisplay#MAIN.
* int32Values[2] : repeat counter, if 0 then event is not repeated. Values 1 or above means
@@ -5326,10 +5324,11 @@
*/
enum CustomInputType : int32_t {
/**
- * Ten functions representing the custom input code to be defined and implemented by OEM
- * partners.
+ * Ten optional function codes to be used in case OEM don't need more than 10 input code values.
*
- * OEMs need to formally contact Android team if more than 10 functions are required.
+ * OEMs are free to use any signed 32 bits number to represent the input code value.
+ * The following function keys are only for convenience and any other integer values are
+ * also allowed.
*/
CUSTOM_EVENT_F1 = 1001,
CUSTOM_EVENT_F2 = 1002,
diff --git a/bluetooth/1.0/Android.bp b/bluetooth/1.0/Android.bp
index 20775dd..bd1ca69 100644
--- a/bluetooth/1.0/Android.bp
+++ b/bluetooth/1.0/Android.bp
@@ -23,6 +23,6 @@
gen_java: true,
apex_available: [
"//apex_available:platform",
- "com.android.bluetooth",
+ "com.android.btservices",
],
}
diff --git a/bluetooth/1.0/default/OWNERS b/bluetooth/1.0/default/OWNERS
deleted file mode 100644
index 5df5bfe..0000000
--- a/bluetooth/1.0/default/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-eisenbach@google.com
-mylesgw@google.com
-pavlin@google.com
diff --git a/bluetooth/1.0/default/bluetooth_hci.cc b/bluetooth/1.0/default/bluetooth_hci.cc
index a2211f4..869c723 100644
--- a/bluetooth/1.0/default/bluetooth_hci.cc
+++ b/bluetooth/1.0/default/bluetooth_hci.cc
@@ -33,7 +33,8 @@
class BluetoothDeathRecipient : public hidl_death_recipient {
public:
- BluetoothDeathRecipient(const sp<IBluetoothHci> hci) : mHci(hci) {}
+ BluetoothDeathRecipient(const sp<IBluetoothHci> hci)
+ : mHci(hci), has_died_(false) {}
virtual void serviceDied(
uint64_t /*cookie*/,
@@ -51,7 +52,7 @@
};
BluetoothHci::BluetoothHci()
- : death_recipient_(new BluetoothDeathRecipient(this)) {}
+ : death_recipient_(new BluetoothDeathRecipient(this)) {bt_enabled = 0;}
Return<void> BluetoothHci::initialize(
const ::android::sp<IBluetoothHciCallbacks>& cb) {
@@ -61,8 +62,19 @@
return Void();
}
+ if (bt_enabled == 1) {
+ ALOGE("initialize was called!");
+ return Void();
+ }
+ bt_enabled = 1;
death_recipient_->setHasDied(false);
cb->linkToDeath(death_recipient_, 0);
+ unlink_cb_ = [cb](sp<BluetoothDeathRecipient>& death_recipient) {
+ if (death_recipient->getHasDied())
+ ALOGI("Skipping unlink call, service died.");
+ else
+ cb->unlinkToDeath(death_recipient);
+ };
bool rc = VendorInterface::Initialize(
[cb](bool status) {
@@ -112,6 +124,12 @@
Return<void> BluetoothHci::close() {
ALOGI("BluetoothHci::close()");
+
+ if (bt_enabled != 1) {
+ ALOGE("should initialize first!");
+ return Void();
+ }
+ bt_enabled = 0;
unlink_cb_(death_recipient_);
VendorInterface::Shutdown();
return Void();
@@ -134,6 +152,11 @@
void BluetoothHci::sendDataToController(const uint8_t type,
const hidl_vec<uint8_t>& data) {
+ if (bt_enabled != 1) {
+ ALOGE("should initialize first!");
+ return;
+ }
+
VendorInterface::get()->Send(type, data.data(), data.size());
}
diff --git a/bluetooth/1.0/default/bluetooth_hci.h b/bluetooth/1.0/default/bluetooth_hci.h
index c966990..5130c87 100644
--- a/bluetooth/1.0/default/bluetooth_hci.h
+++ b/bluetooth/1.0/default/bluetooth_hci.h
@@ -48,6 +48,7 @@
void sendDataToController(const uint8_t type, const hidl_vec<uint8_t>& data);
::android::sp<BluetoothDeathRecipient> death_recipient_;
std::function<void(sp<BluetoothDeathRecipient>&)> unlink_cb_;
+ int bt_enabled;
};
extern "C" IBluetoothHci* HIDL_FETCH_IBluetoothHci(const char* name);
diff --git a/bluetooth/1.0/default/test/fuzzer/bluetoothV1.0_fuzzer.cpp b/bluetooth/1.0/default/test/fuzzer/bluetoothV1.0_fuzzer.cpp
index 90cdc66..fb8df99 100644
--- a/bluetooth/1.0/default/test/fuzzer/bluetoothV1.0_fuzzer.cpp
+++ b/bluetooth/1.0/default/test/fuzzer/bluetoothV1.0_fuzzer.cpp
@@ -88,11 +88,18 @@
}
mBtHci->close();
mBtHci.clear();
+ for (size_t i = 0; i < mFdCount; ++i) {
+ if (mFdList[i]) {
+ close(mFdList[i]);
+ }
+ }
}
bool init(const uint8_t* data, size_t size);
void process();
private:
+ size_t mFdCount = 1;
+ int32_t mFdList[CH_MAX] = {0};
sp<BluetoothHci> mBtHci = nullptr;
FuzzedDataProvider* mFdp = nullptr;
};
@@ -143,17 +150,15 @@
bool shouldSetH4Protocol = mFdp->ConsumeBool();
BtVendor* btVendor = BtVendor::getInstance();
- size_t fdcount = 1;
- int32_t fdList[CH_MAX] = {0};
if (!shouldSetH4Protocol) {
- fdcount = mFdp->ConsumeIntegralInRange<size_t>(kMinFdcount, CH_MAX - 1);
+ mFdCount = mFdp->ConsumeIntegralInRange<size_t>(kMinFdcount, CH_MAX - 1);
}
- for (size_t i = 0; i < fdcount; ++i) {
- fdList[i] = open("/dev/null", O_RDWR | O_CREAT);
+ for (size_t i = 0; i < mFdCount; ++i) {
+ mFdList[i] = open("/dev/null", O_RDWR | O_CREAT);
}
- btVendor->populateFdList(fdList, fdcount);
+ btVendor->populateFdList(mFdList, mFdCount);
mBtHci->initialize(bluetoothCallback);
if (!bluetoothCallback->isInitialized) {
@@ -181,12 +186,6 @@
}
btVendor->callRemainingCbacks();
-
- for (size_t i = 0; i < fdcount; ++i) {
- if (fdList[i]) {
- close(fdList[i]);
- }
- }
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
diff --git a/bluetooth/1.0/default/vendor_interface.cc b/bluetooth/1.0/default/vendor_interface.cc
index 1d15dd6..c23d667 100644
--- a/bluetooth/1.0/default/vendor_interface.cc
+++ b/bluetooth/1.0/default/vendor_interface.cc
@@ -36,6 +36,8 @@
"BLUETOOTH_VENDOR_LIB_INTERFACE";
static const int INVALID_FD = -1;
+std::mutex vendor_mutex_;
+std::mutex initcb_mutex_;
namespace {
@@ -47,13 +49,25 @@
uint16_t opcode;
} internal_command;
+enum {
+ VENDOR_STATE_INIT = 1,
+ VENDOR_STATE_OPENING, /* during opening */
+ VENDOR_STATE_OPENED, /* open in fops_open */
+ VENDOR_STATE_CLOSING, /* during closing */
+ VENDOR_STATE_CLOSED, /* closed */
+
+ VENDOR_STATE_MSG_NUM
+} ;
+
+uint8_t vstate = VENDOR_STATE_INIT;
+
// True when LPM is not enabled yet or wake is not asserted.
bool lpm_wake_deasserted;
uint32_t lpm_timeout_ms;
bool recent_activity_flag;
VendorInterface* g_vendor_interface = nullptr;
-std::mutex wakeup_mutex_;
+static VendorInterface vendor_interface;
HC_BT_HDR* WrapPacketAndCopy(uint16_t event, const hidl_vec<uint8_t>& data) {
size_t packet_size = data.size() + sizeof(HC_BT_HDR);
@@ -167,11 +181,8 @@
InitializeCompleteCallback initialize_complete_cb,
PacketReadCallback event_cb, PacketReadCallback acl_cb,
PacketReadCallback sco_cb, PacketReadCallback iso_cb) {
- if (g_vendor_interface) {
- ALOGE("%s: No previous Shutdown()?", __func__);
- return false;
- }
- g_vendor_interface = new VendorInterface();
+ ALOGI("%s: VendorInterface::Initialize", __func__);
+ g_vendor_interface = &vendor_interface;
return g_vendor_interface->Open(initialize_complete_cb, event_cb, acl_cb,
sco_cb, iso_cb);
}
@@ -179,9 +190,8 @@
void VendorInterface::Shutdown() {
LOG_ALWAYS_FATAL_IF(!g_vendor_interface, "%s: No Vendor interface!",
__func__);
+ ALOGI("%s: VendorInterface::Shutdown", __func__);
g_vendor_interface->Close();
- delete g_vendor_interface;
- g_vendor_interface = nullptr;
}
VendorInterface* VendorInterface::get() { return g_vendor_interface; }
@@ -191,144 +201,189 @@
PacketReadCallback acl_cb,
PacketReadCallback sco_cb,
PacketReadCallback iso_cb) {
- initialize_complete_cb_ = initialize_complete_cb;
+ {
+ std::unique_lock<std::mutex> guard(vendor_mutex_);
+ if (vstate == VENDOR_STATE_OPENED) {
+ ALOGW("VendorInterface opened!");
+ return true;
+ }
- // Initialize vendor interface
+ if ((vstate == VENDOR_STATE_CLOSING) ||
+ (vstate == VENDOR_STATE_OPENING)) {
+ ALOGW("VendorInterface open/close is on-going !");
+ return true;
+ }
- lib_handle_ = dlopen(VENDOR_LIBRARY_NAME, RTLD_NOW);
- if (!lib_handle_) {
- ALOGE("%s unable to open %s (%s)", __func__, VENDOR_LIBRARY_NAME,
- dlerror());
- return false;
- }
+ vstate = VENDOR_STATE_OPENING;
+ ALOGI("%s: VendorInterface::Open", __func__);
- lib_interface_ = reinterpret_cast<bt_vendor_interface_t*>(
- dlsym(lib_handle_, VENDOR_LIBRARY_SYMBOL_NAME));
- if (!lib_interface_) {
- ALOGE("%s unable to find symbol %s in %s (%s)", __func__,
- VENDOR_LIBRARY_SYMBOL_NAME, VENDOR_LIBRARY_NAME, dlerror());
- return false;
- }
+ initialize_complete_cb_ = initialize_complete_cb;
+ // Initialize vendor interface
+
+ lib_handle_ = dlopen(VENDOR_LIBRARY_NAME, RTLD_NOW);
+ if (!lib_handle_) {
+ ALOGE("%s unable to open %s (%s)", __func__, VENDOR_LIBRARY_NAME,
+ dlerror());
+ return false;
+ }
+
+ lib_interface_ = reinterpret_cast<bt_vendor_interface_t*>(
+ dlsym(lib_handle_, VENDOR_LIBRARY_SYMBOL_NAME));
+ if (!lib_interface_) {
+ ALOGE("%s unable to find symbol %s in %s (%s)", __func__,
+ VENDOR_LIBRARY_SYMBOL_NAME, VENDOR_LIBRARY_NAME, dlerror());
+ return false;
+ }
// Get the local BD address
- uint8_t local_bda[BluetoothAddress::kBytes];
- if (!BluetoothAddress::get_local_address(local_bda)) {
- LOG_ALWAYS_FATAL("%s: No Bluetooth Address!", __func__);
- }
- int status = lib_interface_->init(&lib_callbacks, (unsigned char*)local_bda);
- if (status) {
- ALOGE("%s unable to initialize vendor library: %d", __func__, status);
- return false;
- }
+ uint8_t local_bda[BluetoothAddress::kBytes] = {0, 0, 0, 0, 0, 0};
+ if (!BluetoothAddress::get_local_address(local_bda)) {
+ // BT driver will get BD address from NVRAM for MTK solution
+ ALOGW("%s: No pre-set Bluetooth Address!", __func__);
+ }
+ int status = lib_interface_->init(&lib_callbacks, (unsigned char*)local_bda);
+ if (status) {
+ ALOGE("%s unable to initialize vendor library: %d", __func__, status);
+ return false;
+ }
- ALOGD("%s vendor library loaded", __func__);
+ ALOGD("%s vendor library loaded", __func__);
// Power on the controller
- int power_state = BT_VND_PWR_ON;
- lib_interface_->op(BT_VND_OP_POWER_CTRL, &power_state);
+ int power_state = BT_VND_PWR_ON;
+ lib_interface_->op(BT_VND_OP_POWER_CTRL, &power_state);
// Get the UART socket(s)
- int fd_list[CH_MAX] = {0};
- int fd_count = lib_interface_->op(BT_VND_OP_USERIAL_OPEN, &fd_list);
+ int fd_list[CH_MAX] = {0};
+ int fd_count = lib_interface_->op(BT_VND_OP_USERIAL_OPEN, &fd_list);
- if (fd_count < 1 || fd_count > CH_MAX - 1) {
- ALOGE("%s: fd_count %d is invalid!", __func__, fd_count);
- return false;
- }
-
- for (int i = 0; i < fd_count; i++) {
- if (fd_list[i] == INVALID_FD) {
- ALOGE("%s: fd %d is invalid!", __func__, fd_list[i]);
+ if (fd_count < 1 || fd_count > CH_MAX - 1) {
+ ALOGE("%s: fd_count %d is invalid!", __func__, fd_count);
return false;
}
- }
- event_cb_ = event_cb;
- PacketReadCallback intercept_events = [this](const hidl_vec<uint8_t>& event) {
- HandleIncomingEvent(event);
- };
+ for (int i = 0; i < fd_count; i++) {
+ if (fd_list[i] == INVALID_FD) {
+ ALOGE("%s: fd %d is invalid!", __func__, fd_list[i]);
+ return false;
+ }
+ }
- if (fd_count == 1) {
- hci::H4Protocol* h4_hci =
- new hci::H4Protocol(fd_list[0], intercept_events, acl_cb, sco_cb, iso_cb);
- fd_watcher_.WatchFdForNonBlockingReads(
- fd_list[0], [h4_hci](int fd) { h4_hci->OnDataReady(fd); });
- hci_ = h4_hci;
- } else {
- hci::MctProtocol* mct_hci =
- new hci::MctProtocol(fd_list, intercept_events, acl_cb);
- fd_watcher_.WatchFdForNonBlockingReads(
- fd_list[CH_EVT], [mct_hci](int fd) { mct_hci->OnEventDataReady(fd); });
- fd_watcher_.WatchFdForNonBlockingReads(
- fd_list[CH_ACL_IN], [mct_hci](int fd) { mct_hci->OnAclDataReady(fd); });
- hci_ = mct_hci;
- }
+ event_cb_ = event_cb;
+ PacketReadCallback intercept_events = [this](const hidl_vec<uint8_t>& event) {
+ HandleIncomingEvent(event);
+ };
+
+ if (fd_count == 1) {
+ hci::H4Protocol* h4_hci =
+ new hci::H4Protocol(fd_list[0], intercept_events, acl_cb, sco_cb, iso_cb);
+ fd_watcher_.WatchFdForNonBlockingReads(
+ fd_list[0], [h4_hci](int fd) { h4_hci->OnDataReady(fd); });
+ hci_ = h4_hci;
+ } else {
+ hci::MctProtocol* mct_hci =
+ new hci::MctProtocol(fd_list, intercept_events, acl_cb);
+ fd_watcher_.WatchFdForNonBlockingReads(
+ fd_list[CH_EVT], [mct_hci](int fd) { mct_hci->OnEventDataReady(fd); });
+ fd_watcher_.WatchFdForNonBlockingReads(
+ fd_list[CH_ACL_IN],
+ [mct_hci](int fd) { mct_hci->OnAclDataReady(fd); });
+ hci_ = mct_hci;
+ }
// Initially, the power management is off.
- lpm_wake_deasserted = true;
+ lpm_wake_deasserted = true;
// Start configuring the firmware
- firmware_startup_timer_ = new FirmwareStartupTimer();
- lib_interface_->op(BT_VND_OP_FW_CFG, nullptr);
+ firmware_startup_timer_ = new FirmwareStartupTimer();
+ lib_interface_->op(BT_VND_OP_FW_CFG, nullptr);
+ vstate = VENDOR_STATE_OPENED;
+ ALOGI("%s: VendorInterface::Open done!!!", __func__);
+ } // vendor_mutex_ done
return true;
}
void VendorInterface::Close() {
// These callbacks may send HCI events (vendor-dependent), so make sure to
// StopWatching the file descriptor after this.
+
+ if (vstate != VENDOR_STATE_OPENED) {
+ ALOGW("VendorInterface is not allow close(%d)", vstate);
+ return;
+ }
+ vstate = VENDOR_STATE_CLOSING;
+ ALOGI("%s: VendorInterface::Close", __func__);
+
if (lib_interface_ != nullptr) {
+ lib_interface_->cleanup();
bt_vendor_lpm_mode_t mode = BT_VND_LPM_DISABLE;
lib_interface_->op(BT_VND_OP_LPM_SET_MODE, &mode);
}
- fd_watcher_.StopWatchingFileDescriptors();
+ {
+ std::unique_lock<std::mutex> guard(vendor_mutex_);
- if (hci_ != nullptr) {
- delete hci_;
- hci_ = nullptr;
- }
+ fd_watcher_.StopWatchingFileDescriptors();
+ if (hci_ != nullptr) {
+ delete hci_;
+ hci_ = nullptr;
+ }
- if (lib_interface_ != nullptr) {
- lib_interface_->op(BT_VND_OP_USERIAL_CLOSE, nullptr);
+ if (lib_interface_ != nullptr) {
+ lib_interface_->op(BT_VND_OP_USERIAL_CLOSE, nullptr);
- int power_state = BT_VND_PWR_OFF;
- lib_interface_->op(BT_VND_OP_POWER_CTRL, &power_state);
+ int power_state = BT_VND_PWR_OFF;
+ lib_interface_->op(BT_VND_OP_POWER_CTRL, &power_state);
- lib_interface_->cleanup();
- lib_interface_ = nullptr;
- }
+ lib_interface_ = nullptr;
+ }
- if (lib_handle_ != nullptr) {
- dlclose(lib_handle_);
- lib_handle_ = nullptr;
- }
+ if (lib_handle_ != nullptr) {
+ dlclose(lib_handle_);
+ lib_handle_ = nullptr;
+ }
- if (firmware_startup_timer_ != nullptr) {
- delete firmware_startup_timer_;
- firmware_startup_timer_ = nullptr;
- }
+ if (firmware_startup_timer_ != nullptr) {
+ delete firmware_startup_timer_;
+ firmware_startup_timer_ = nullptr;
+ }
+ vstate = VENDOR_STATE_CLOSED;
+ } // vendor_mutex_ done
+ ALOGI("%s: VendorInterface::Close done!!!", __func__);
}
size_t VendorInterface::Send(uint8_t type, const uint8_t* data, size_t length) {
- std::unique_lock<std::mutex> lock(wakeup_mutex_);
- recent_activity_flag = true;
+ {
+ std::unique_lock<std::mutex> guard(vendor_mutex_);
- if (lpm_wake_deasserted == true) {
- // Restart the timer.
- fd_watcher_.ConfigureTimeout(std::chrono::milliseconds(lpm_timeout_ms),
+ if (vstate != VENDOR_STATE_OPENED) {
+ ALOGW("VendorInterface is not open yet(%d)!", vstate);
+ return 0;
+ }
+ ALOGI("%s: VendorInterface::Send", __func__);
+
+ if (lib_interface_ == nullptr) {
+ ALOGE("lib_interface_ is null");
+ return 0;
+ }
+ recent_activity_flag = true;
+ if (lpm_wake_deasserted == true) {
+ // Restart the timer.
+ fd_watcher_.ConfigureTimeout(std::chrono::milliseconds(lpm_timeout_ms),
[this]() { OnTimeout(); });
- // Assert wake.
- lpm_wake_deasserted = false;
- bt_vendor_lpm_wake_state_t wakeState = BT_VND_LPM_WAKE_ASSERT;
- lib_interface_->op(BT_VND_OP_LPM_WAKE_SET_STATE, &wakeState);
- ALOGV("%s: Sent wake before (%02x)", __func__, data[0] | (data[1] << 8));
- }
+ // Assert wake.
+ lpm_wake_deasserted = false;
+ bt_vendor_lpm_wake_state_t wakeState = BT_VND_LPM_WAKE_ASSERT;
+ lib_interface_->op(BT_VND_OP_LPM_WAKE_SET_STATE, &wakeState);
+ ALOGV("%s: Sent wake before (%02x)", __func__, data[0] | (data[1] << 8));
+ }
- return hci_->Send(type, data, length);
+ return hci_ ? hci_->Send(type, data, length) : 0;
+ } // vendor_mutex_ done
}
void VendorInterface::OnFirmwareConfigured(uint8_t result) {
@@ -339,25 +394,36 @@
firmware_startup_timer_ = nullptr;
}
- if (initialize_complete_cb_ != nullptr) {
- initialize_complete_cb_(result == 0);
- initialize_complete_cb_ = nullptr;
+ {
+ std::unique_lock<std::mutex> guard(initcb_mutex_);
+ ALOGD("%s OnFirmwareConfigured get lock", __func__);
+ if (initialize_complete_cb_ != nullptr) {
+ LOG_ALWAYS_FATAL_IF((result != 0),
+ "%s: Failed to init firmware!", __func__);
+ initialize_complete_cb_(result == 0);
+ }
+ } // initcb_mutex_ done
+
+ if (lib_interface_ != nullptr) {
+ lib_interface_->op(BT_VND_OP_GET_LPM_IDLE_TIMEOUT, &lpm_timeout_ms);
+ ALOGI("%s: lpm_timeout_ms %d", __func__, lpm_timeout_ms);
+
+ bt_vendor_lpm_mode_t mode = BT_VND_LPM_ENABLE;
+ lib_interface_->op(BT_VND_OP_LPM_SET_MODE, &mode);
+
+ ALOGD("%s Calling StartLowPowerWatchdog()", __func__);
+ fd_watcher_.ConfigureTimeout(std::chrono::milliseconds(lpm_timeout_ms),
+ [this]() { OnTimeout(); });
+ }
+ else {
+ ALOGE("lib_interface_ is null");
}
- lib_interface_->op(BT_VND_OP_GET_LPM_IDLE_TIMEOUT, &lpm_timeout_ms);
- ALOGI("%s: lpm_timeout_ms %d", __func__, lpm_timeout_ms);
-
- bt_vendor_lpm_mode_t mode = BT_VND_LPM_ENABLE;
- lib_interface_->op(BT_VND_OP_LPM_SET_MODE, &mode);
-
- ALOGD("%s Calling StartLowPowerWatchdog()", __func__);
- fd_watcher_.ConfigureTimeout(std::chrono::milliseconds(lpm_timeout_ms),
- [this]() { OnTimeout(); });
+ initialize_complete_cb_ = nullptr;
}
void VendorInterface::OnTimeout() {
ALOGV("%s", __func__);
- std::unique_lock<std::mutex> lock(wakeup_mutex_);
if (recent_activity_flag == false) {
lpm_wake_deasserted = true;
bt_vendor_lpm_wake_state_t wakeState = BT_VND_LPM_WAKE_DEASSERT;
diff --git a/bluetooth/1.0/default/vendor_interface.h b/bluetooth/1.0/default/vendor_interface.h
index 040f31a..2df3946 100644
--- a/bluetooth/1.0/default/vendor_interface.h
+++ b/bluetooth/1.0/default/vendor_interface.h
@@ -22,6 +22,8 @@
#include "bt_vendor_lib.h"
#include "hci_protocol.h"
+extern std::mutex initcb_mutex_;
+
namespace android {
namespace hardware {
namespace bluetooth {
@@ -45,10 +47,9 @@
size_t Send(uint8_t type, const uint8_t* data, size_t length);
void OnFirmwareConfigured(uint8_t result);
-
- private:
virtual ~VendorInterface() = default;
+ private:
bool Open(InitializeCompleteCallback initialize_complete_cb,
PacketReadCallback event_cb, PacketReadCallback acl_cb,
PacketReadCallback sco_cb, PacketReadCallback iso_cb);
diff --git a/bluetooth/1.0/vts/OWNERS b/bluetooth/1.0/vts/OWNERS
deleted file mode 100644
index 58d3a66..0000000
--- a/bluetooth/1.0/vts/OWNERS
+++ /dev/null
@@ -1,8 +0,0 @@
-zachoverflow@google.com
-siyuanh@google.com
-mylesgw@google.com
-jpawlowski@google.com
-apanicke@google.com
-stng@google.com
-hsz@google.com
-
diff --git a/bluetooth/1.0/vts/functional/OWNERS b/bluetooth/1.0/vts/functional/OWNERS
deleted file mode 100644
index 7f02612..0000000
--- a/bluetooth/1.0/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 27441
-bluetooth-reviews@google.com
diff --git a/bluetooth/1.1/Android.bp b/bluetooth/1.1/Android.bp
index 4ac2009..f8a05f1 100644
--- a/bluetooth/1.1/Android.bp
+++ b/bluetooth/1.1/Android.bp
@@ -23,6 +23,6 @@
gen_java: true,
apex_available: [
"//apex_available:platform",
- "com.android.bluetooth",
+ "com.android.btservices",
],
}
diff --git a/bluetooth/1.1/default/OWNERS b/bluetooth/1.1/default/OWNERS
deleted file mode 100644
index 0c01df6..0000000
--- a/bluetooth/1.1/default/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-zachoverflow@google.com
-mylesgw@google.com
-jpawlowski@google.com
diff --git a/bluetooth/1.1/vts/OWNERS b/bluetooth/1.1/vts/OWNERS
deleted file mode 100644
index ff6fd93..0000000
--- a/bluetooth/1.1/vts/OWNERS
+++ /dev/null
@@ -1,6 +0,0 @@
-zachoverflow@google.com
-siyuanh@google.com
-mylesgw@google.com
-jpawlowski@google.com
-hsz@google.com
-
diff --git a/bluetooth/1.1/vts/functional/VtsHalBluetoothV1_1TargetTest.xml b/bluetooth/1.1/vts/functional/VtsHalBluetoothV1_1TargetTest.xml
index d64751a..98b62ef 100644
--- a/bluetooth/1.1/vts/functional/VtsHalBluetoothV1_1TargetTest.xml
+++ b/bluetooth/1.1/vts/functional/VtsHalBluetoothV1_1TargetTest.xml
@@ -20,8 +20,11 @@
<target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
</target_preparer>
- <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
- <option name="bluetooth" value="off" />
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="settings put global ble_scan_always_enabled 0" />
+ <option name="run-command" value="su u$(am get-current-user)_system svc bluetooth disable" />
+ <option name="teardown-command" value="su u$(am get-current-user)_system svc bluetooth enable" />
+ <option name="teardown-command" value="settings put global ble_scan_always_enabled 1" />
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
diff --git a/bluetooth/OWNERS b/bluetooth/OWNERS
new file mode 100644
index 0000000..f401b8c
--- /dev/null
+++ b/bluetooth/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 27441
+
+henrichataing@google.com
+mylesgw@google.com
+siyuanh@google.com
diff --git a/bluetooth/a2dp/1.0/Android.bp b/bluetooth/a2dp/1.0/Android.bp
index 20776dc..6ffbefa 100644
--- a/bluetooth/a2dp/1.0/Android.bp
+++ b/bluetooth/a2dp/1.0/Android.bp
@@ -23,6 +23,6 @@
gen_java: false,
apex_available: [
"//apex_available:platform",
- "com.android.bluetooth",
+ "com.android.btservices",
],
}
diff --git a/bluetooth/aidl/Android.bp b/bluetooth/aidl/Android.bp
new file mode 100644
index 0000000..1788ed3
--- /dev/null
+++ b/bluetooth/aidl/Android.bp
@@ -0,0 +1,37 @@
+// This is the expected build file, but it may not be right in all cases
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+aidl_interface {
+ name: "android.hardware.bluetooth",
+ vendor_available: true,
+ host_supported: true,
+ srcs: ["android/hardware/bluetooth/*.aidl"],
+ stability: "vintf",
+ backend: {
+ cpp: {
+ // FIXME should this be disabled?
+ // prefer NDK backend which can be used anywhere
+ // If you disable this, you also need to delete the C++
+ // translate code.
+ enabled: true,
+ },
+ java: {
+ sdk_version: "module_current",
+ },
+ ndk: {
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.btservices",
+ ],
+ min_sdk_version: "33",
+ },
+ },
+}
diff --git a/bluetooth/aidl/aidl_api/android.hardware.bluetooth/current/android/hardware/bluetooth/IBluetoothHci.aidl b/bluetooth/aidl/aidl_api/android.hardware.bluetooth/current/android/hardware/bluetooth/IBluetoothHci.aidl
new file mode 100644
index 0000000..8b1cad2
--- /dev/null
+++ b/bluetooth/aidl/aidl_api/android.hardware.bluetooth/current/android/hardware/bluetooth/IBluetoothHci.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth;
+@VintfStability
+interface IBluetoothHci {
+ void close();
+ void initialize(in android.hardware.bluetooth.IBluetoothHciCallbacks callback);
+ void sendAclData(in byte[] data);
+ void sendHciCommand(in byte[] command);
+ void sendIsoData(in byte[] data);
+ void sendScoData(in byte[] data);
+}
diff --git a/bluetooth/aidl/aidl_api/android.hardware.bluetooth/current/android/hardware/bluetooth/IBluetoothHciCallbacks.aidl b/bluetooth/aidl/aidl_api/android.hardware.bluetooth/current/android/hardware/bluetooth/IBluetoothHciCallbacks.aidl
new file mode 100644
index 0000000..aecff7f
--- /dev/null
+++ b/bluetooth/aidl/aidl_api/android.hardware.bluetooth/current/android/hardware/bluetooth/IBluetoothHciCallbacks.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth;
+@VintfStability
+interface IBluetoothHciCallbacks {
+ void aclDataReceived(in byte[] data);
+ void hciEventReceived(in byte[] event);
+ void initializationComplete(in android.hardware.bluetooth.Status status);
+ void isoDataReceived(in byte[] data);
+ void scoDataReceived(in byte[] data);
+}
diff --git a/bluetooth/aidl/aidl_api/android.hardware.bluetooth/current/android/hardware/bluetooth/Status.aidl b/bluetooth/aidl/aidl_api/android.hardware.bluetooth/current/android/hardware/bluetooth/Status.aidl
new file mode 100644
index 0000000..da429b8
--- /dev/null
+++ b/bluetooth/aidl/aidl_api/android.hardware.bluetooth/current/android/hardware/bluetooth/Status.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth;
+@Backing(type="int") @VintfStability
+enum Status {
+ SUCCESS = 0,
+ ALREADY_INITIALIZED = 1,
+ UNABLE_TO_OPEN_INTERFACE = 2,
+ HARDWARE_INITIALIZATION_ERROR = 3,
+ UNKNOWN = 4,
+}
diff --git a/bluetooth/aidl/android/hardware/bluetooth/IBluetoothHci.aidl b/bluetooth/aidl/android/hardware/bluetooth/IBluetoothHci.aidl
new file mode 100644
index 0000000..db12986
--- /dev/null
+++ b/bluetooth/aidl/android/hardware/bluetooth/IBluetoothHci.aidl
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth;
+
+import android.hardware.bluetooth.IBluetoothHciCallbacks;
+
+/**
+ * The Host Controller Interface (HCI) is the layer defined by the Bluetooth
+ * specification between the software that runs on the host and the Bluetooth
+ * controller chip. This boundary is the natural choice for a Hardware
+ * Abstraction Layer (HAL). Dealing only in HCI packets and events simplifies
+ * the stack and abstracts away power management, initialization, and other
+ * implementation-specific details related to the hardware.
+ */
+@VintfStability
+interface IBluetoothHci {
+ /**
+ * Close the HCI interface
+ */
+ void close();
+
+ /**
+ * Initialize the Bluetooth interface and set the callbacks.
+ */
+ void initialize(in IBluetoothHciCallbacks callback);
+
+ /**
+ * Send an HCI ACL data packet (as specified in the Bluetooth Specification
+ * V4.2, Vol 2, Part 5, Section 5.4.2) to the Bluetooth controller.
+ * Packets must be processed in order.
+ * @param data HCI data packet to be sent
+ */
+ void sendAclData(in byte[] data);
+
+ /**
+ * Send an HCI command (as specified in the Bluetooth Specification
+ * V4.2, Vol 2, Part 5, Section 5.4.1) to the Bluetooth controller.
+ * Commands must be executed in order.
+ *
+ * @param command is the HCI command to be sent
+ */
+ void sendHciCommand(in byte[] command);
+
+ /**
+ * Send an ISO data packet (as specified in the Bluetooth Core
+ * Specification v5.2) to the Bluetooth controller.
+ * Packets must be processed in order.
+ * @param data HCI data packet to be sent
+ */
+ void sendIsoData(in byte[] data);
+
+ /**
+ * Send an SCO data packet (as specified in the Bluetooth Specification
+ * V4.2, Vol 2, Part 5, Section 5.4.3) to the Bluetooth controller.
+ * Packets must be processed in order.
+ * @param data HCI data packet to be sent
+ */
+ void sendScoData(in byte[] data);
+}
diff --git a/bluetooth/aidl/android/hardware/bluetooth/IBluetoothHciCallbacks.aidl b/bluetooth/aidl/android/hardware/bluetooth/IBluetoothHciCallbacks.aidl
new file mode 100644
index 0000000..000333e
--- /dev/null
+++ b/bluetooth/aidl/android/hardware/bluetooth/IBluetoothHciCallbacks.aidl
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth;
+
+import android.hardware.bluetooth.Status;
+
+/**
+ * The interface from the Bluetooth Controller to the stack.
+ */
+@VintfStability
+interface IBluetoothHciCallbacks {
+ /**
+ * Send an ACL data packet from the controller to the host.
+ * @param data the ACL HCI packet to be passed to the host stack
+ */
+ void aclDataReceived(in byte[] data);
+
+ /**
+ * This function is invoked when an HCI event is received from the
+ * Bluetooth controller to be forwarded to the Bluetooth stack.
+ * @param event is the HCI event to be sent to the Bluetooth stack.
+ */
+ void hciEventReceived(in byte[] event);
+
+ /**
+ * Invoked when the Bluetooth controller initialization has been
+ * completed.
+ */
+ void initializationComplete(in Status status);
+
+ /**
+ * Send a ISO data packet from the controller to the host.
+ * @param data the ISO HCI packet to be passed to the host stack
+ */
+ void isoDataReceived(in byte[] data);
+
+ /**
+ * Send a SCO data packet from the controller to the host.
+ * @param data the SCO HCI packet to be passed to the host stack
+ */
+ void scoDataReceived(in byte[] data);
+}
diff --git a/bluetooth/aidl/android/hardware/bluetooth/Status.aidl b/bluetooth/aidl/android/hardware/bluetooth/Status.aidl
new file mode 100644
index 0000000..4ec251a
--- /dev/null
+++ b/bluetooth/aidl/android/hardware/bluetooth/Status.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth;
+
+@VintfStability
+@Backing(type="int")
+enum Status {
+ SUCCESS,
+ ALREADY_INITIALIZED,
+ UNABLE_TO_OPEN_INTERFACE,
+ HARDWARE_INITIALIZATION_ERROR,
+ UNKNOWN,
+}
diff --git a/bluetooth/aidl/default/Android.bp b/bluetooth/aidl/default/Android.bp
new file mode 100644
index 0000000..d1761f5
--- /dev/null
+++ b/bluetooth/aidl/default/Android.bp
@@ -0,0 +1,79 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_defaults {
+ name: "android.hardware.bluetooth-service-build-defaults",
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ ],
+ shared_libs: [
+ "android.hardware.bluetooth-V1-ndk",
+ "libbase",
+ "libbinder_ndk",
+ "libcutils",
+ "libhidlbase",
+ "liblog",
+ "libutils",
+ ],
+ static_libs: [
+ "android.hardware.bluetooth.async",
+ "android.hardware.bluetooth.hci",
+ ],
+}
+
+cc_library_static {
+ name: "libbluetoothhcihalimpl",
+ vendor_available: true,
+ host_supported: true,
+ defaults: ["android.hardware.bluetooth-service-build-defaults"],
+ srcs: [
+ "BluetoothHci.cpp",
+ ],
+}
+
+cc_binary {
+ name: "android.hardware.bluetooth-service.default",
+ relative_install_path: "hw",
+ init_rc: ["bluetooth-service-default.rc"],
+ vintf_fragments: ["bluetooth-service-default.xml"],
+ vendor: true,
+ defaults: ["android.hardware.bluetooth-service-build-defaults"],
+ srcs: [
+ "service.cpp",
+ ],
+ shared_libs: [
+ "android.hardware.bluetooth-V1-ndk",
+ "libbase",
+ "libbinder_ndk",
+ "libhidlbase",
+ "libutils",
+ "liblog",
+ ],
+ static_libs: [
+ "libbluetoothhcihalimpl",
+ ],
+}
+
+cc_fuzz {
+ name: "android.hardware.bluetooth-service.default_fuzzer",
+ host_supported: true,
+ defaults: ["service_fuzzer_defaults"],
+ srcs: [
+ "test/fuzzer.cpp",
+ ],
+ static_libs: [
+ "android.hardware.bluetooth.async",
+ "android.hardware.bluetooth.hci",
+ "android.hardware.bluetooth-V1-ndk",
+ "libbluetoothhcihalimpl",
+ "liblog",
+ ],
+ fuzz_config: {
+ componentid: 27441,
+ cc: [
+ "mylesgw@google.com",
+ ],
+ },
+}
diff --git a/bluetooth/aidl/default/BluetoothHci.cpp b/bluetooth/aidl/default/BluetoothHci.cpp
new file mode 100644
index 0000000..4d4896d
--- /dev/null
+++ b/bluetooth/aidl/default/BluetoothHci.cpp
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.bluetooth.service.default"
+
+#include "BluetoothHci.h"
+
+#include <cutils/properties.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <poll.h>
+#include <string.h>
+#include <sys/uio.h>
+#include <termios.h>
+
+#include "log/log.h"
+
+namespace {
+int SetTerminalRaw(int fd) {
+ termios terminal_settings;
+ int rval = tcgetattr(fd, &terminal_settings);
+ if (rval < 0) {
+ return rval;
+ }
+ cfmakeraw(&terminal_settings);
+ rval = tcsetattr(fd, TCSANOW, &terminal_settings);
+ return rval;
+}
+} // namespace
+
+using namespace ::android::hardware::bluetooth::hci;
+using namespace ::android::hardware::bluetooth::async;
+
+namespace aidl::android::hardware::bluetooth::impl {
+
+void OnDeath(void* cookie);
+
+class BluetoothDeathRecipient {
+ public:
+ BluetoothDeathRecipient(BluetoothHci* hci) : mHci(hci) {}
+
+ void LinkToDeath(const std::shared_ptr<IBluetoothHciCallbacks>& cb) {
+ mCb = cb;
+ clientDeathRecipient_ = AIBinder_DeathRecipient_new(OnDeath);
+ auto linkToDeathReturnStatus = AIBinder_linkToDeath(
+ mCb->asBinder().get(), clientDeathRecipient_, this /* cookie */);
+ LOG_ALWAYS_FATAL_IF(linkToDeathReturnStatus != STATUS_OK,
+ "Unable to link to death recipient");
+ }
+
+ void UnlinkToDeath(const std::shared_ptr<IBluetoothHciCallbacks>& cb) {
+ LOG_ALWAYS_FATAL_IF(cb != mCb, "Unable to unlink mismatched pointers");
+ }
+
+ void serviceDied() {
+ if (mCb != nullptr && !AIBinder_isAlive(mCb->asBinder().get())) {
+ ALOGE("Bluetooth remote service has died");
+ } else {
+ ALOGE("BluetoothDeathRecipient::serviceDied called but service not dead");
+ return;
+ }
+ has_died_ = true;
+ mHci->close();
+ }
+ BluetoothHci* mHci;
+ std::shared_ptr<IBluetoothHciCallbacks> mCb;
+ AIBinder_DeathRecipient* clientDeathRecipient_;
+ bool getHasDied() const { return has_died_; }
+
+ private:
+ bool has_died_{false};
+};
+
+void OnDeath(void* cookie) {
+ auto* death_recipient = static_cast<BluetoothDeathRecipient*>(cookie);
+ death_recipient->serviceDied();
+}
+
+BluetoothHci::BluetoothHci(const std::string& dev_path) {
+ char property_bytes[PROPERTY_VALUE_MAX];
+ property_get("vendor.ser.bt-uart", property_bytes, dev_path.c_str());
+ mDevPath = std::string(property_bytes);
+ mDeathRecipient = std::make_shared<BluetoothDeathRecipient>(this);
+}
+
+ndk::ScopedAStatus BluetoothHci::initialize(
+ const std::shared_ptr<IBluetoothHciCallbacks>& cb) {
+ ALOGI(__func__);
+
+ mFd = open(mDevPath.c_str(), O_RDWR);
+ if (mFd < 0) {
+ ALOGE("Could not connect to bt: %s (%s)", mDevPath.c_str(),
+ strerror(errno));
+ return ndk::ScopedAStatus::fromServiceSpecificError(STATUS_BAD_VALUE);
+ }
+ if (int ret = SetTerminalRaw(mFd) < 0) {
+ ALOGE("Could not make %s a raw terminal %d(%s)", mDevPath.c_str(), ret,
+ strerror(errno));
+ return ndk::ScopedAStatus::fromServiceSpecificError(STATUS_BAD_VALUE);
+ }
+
+ mCb = cb;
+ if (mCb == nullptr) {
+ ALOGE("cb == nullptr! -> Unable to call initializationComplete(ERR)");
+ return ndk::ScopedAStatus::fromServiceSpecificError(STATUS_BAD_VALUE);
+ }
+
+ mDeathRecipient->LinkToDeath(mCb);
+
+ auto init_ret = cb->initializationComplete(Status::SUCCESS);
+ if (!init_ret.isOk()) {
+ if (!mDeathRecipient->getHasDied()) {
+ ALOGE("Error sending init callback, but no death notification.");
+ }
+ return ndk::ScopedAStatus::fromServiceSpecificError(
+ STATUS_FAILED_TRANSACTION);
+ }
+ mH4 = std::make_shared<H4Protocol>(
+ mFd,
+ [](const std::vector<uint8_t>& /* raw_command */) {
+ LOG_ALWAYS_FATAL("Unexpected command!");
+ },
+ [this](const std::vector<uint8_t>& raw_event) {
+ mCb->hciEventReceived(raw_event);
+ },
+ [this](const std::vector<uint8_t>& raw_acl) {
+ mCb->hciEventReceived(raw_acl);
+ },
+ [this](const std::vector<uint8_t>& raw_sco) {
+ mCb->hciEventReceived(raw_sco);
+ },
+ [this](const std::vector<uint8_t>& raw_iso) {
+ mCb->hciEventReceived(raw_iso);
+ },
+ [this]() {
+ ALOGI("HCI socket device disconnected");
+ mFdWatcher.StopWatchingFileDescriptors();
+ });
+ mFdWatcher.WatchFdForNonBlockingReads(mFd,
+ [this](int) { mH4->OnDataReady(); });
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus BluetoothHci::close() {
+ ALOGI(__func__);
+ mFdWatcher.StopWatchingFileDescriptors();
+ ::close(mFd);
+
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus BluetoothHci::sendHciCommand(
+ const std::vector<uint8_t>& packet) {
+ send(PacketType::COMMAND, packet);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus BluetoothHci::sendAclData(
+ const std::vector<uint8_t>& packet) {
+ send(PacketType::ACL_DATA, packet);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus BluetoothHci::sendScoData(
+ const std::vector<uint8_t>& packet) {
+ send(PacketType::SCO_DATA, packet);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus BluetoothHci::sendIsoData(
+ const std::vector<uint8_t>& packet) {
+ send(PacketType::ISO_DATA, packet);
+ return ndk::ScopedAStatus::ok();
+}
+
+void BluetoothHci::send(PacketType type, const std::vector<uint8_t>& v) {
+ mH4->Send(type, v);
+}
+
+} // namespace aidl::android::hardware::bluetooth::impl
diff --git a/bluetooth/aidl/default/BluetoothHci.h b/bluetooth/aidl/default/BluetoothHci.h
new file mode 100644
index 0000000..0ed0623
--- /dev/null
+++ b/bluetooth/aidl/default/BluetoothHci.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/bluetooth/BnBluetoothHci.h>
+#include <aidl/android/hardware/bluetooth/IBluetoothHciCallbacks.h>
+#include <log/log.h>
+
+#include <string>
+
+#include "async_fd_watcher.h"
+#include "h4_protocol.h"
+
+namespace aidl::android::hardware::bluetooth::impl {
+
+class BluetoothDeathRecipient;
+
+// This Bluetooth HAL implementation connects with a serial port at dev_path_.
+class BluetoothHci : public BnBluetoothHci {
+ public:
+ BluetoothHci(const std::string& dev_path = "/dev/hvc5");
+
+ ndk::ScopedAStatus initialize(
+ const std::shared_ptr<IBluetoothHciCallbacks>& cb) override;
+
+ ndk::ScopedAStatus sendHciCommand(
+ const std::vector<uint8_t>& packet) override;
+
+ ndk::ScopedAStatus sendAclData(const std::vector<uint8_t>& packet) override;
+
+ ndk::ScopedAStatus sendScoData(const std::vector<uint8_t>& packet) override;
+
+ ndk::ScopedAStatus sendIsoData(const std::vector<uint8_t>& packet) override;
+
+ ndk::ScopedAStatus close() override;
+
+ static void OnPacketReady();
+
+ static BluetoothHci* get();
+
+ private:
+ int mFd{-1};
+ std::shared_ptr<IBluetoothHciCallbacks> mCb = nullptr;
+
+ std::shared_ptr<::android::hardware::bluetooth::hci::H4Protocol> mH4;
+
+ std::shared_ptr<BluetoothDeathRecipient> mDeathRecipient;
+
+ std::string mDevPath;
+
+ ::android::hardware::bluetooth::async::AsyncFdWatcher mFdWatcher;
+
+ void send(::android::hardware::bluetooth::hci::PacketType type,
+ const std::vector<uint8_t>& packet);
+};
+
+} // namespace aidl::android::hardware::bluetooth::impl
diff --git a/bluetooth/aidl/default/bluetooth-service-default.rc b/bluetooth/aidl/default/bluetooth-service-default.rc
new file mode 100644
index 0000000..1841c77
--- /dev/null
+++ b/bluetooth/aidl/default/bluetooth-service-default.rc
@@ -0,0 +1,6 @@
+service bluetooth_hal_service /vendor/bin/hw/android.hardware.bluetooth-service.default
+ class hal
+ capabilities BLOCK_SUSPEND NET_ADMIN SYS_NICE
+ user bluetooth
+ group bluetooth
+ task_profiles HighPerformance
diff --git a/bluetooth/aidl/default/bluetooth-service-default.xml b/bluetooth/aidl/default/bluetooth-service-default.xml
new file mode 100644
index 0000000..bb05995
--- /dev/null
+++ b/bluetooth/aidl/default/bluetooth-service-default.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.bluetooth</name>
+ <fqname>IBluetoothHci/default</fqname>
+ </hal>
+</manifest>
diff --git a/bluetooth/aidl/default/service.cpp b/bluetooth/aidl/default/service.cpp
new file mode 100644
index 0000000..9af2a08
--- /dev/null
+++ b/bluetooth/aidl/default/service.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "aidl.android.hardware.bluetooth.service.default"
+
+#include <aidl/android/hardware/bluetooth/IBluetoothHci.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include "BluetoothHci.h"
+
+using ::aidl::android::hardware::bluetooth::impl::BluetoothHci;
+using ::android::hardware::configureRpcThreadpool;
+using ::android::hardware::joinRpcThreadpool;
+
+int main(int /* argc */, char** /* argv */) {
+ ALOGI("Bluetooth HAL starting");
+ if (!ABinderProcess_setThreadPoolMaxThreadCount(1)) {
+ ALOGI("failed to set thread pool max thread count");
+ return 1;
+ }
+
+ std::shared_ptr<BluetoothHci> service =
+ ndk::SharedRefBase::make<BluetoothHci>();
+ std::string instance = std::string() + BluetoothHci::descriptor + "/default";
+ auto result =
+ AServiceManager_addService(service->asBinder().get(), instance.c_str());
+ if (result == STATUS_OK) {
+ ABinderProcess_joinThreadPool();
+ } else {
+ ALOGE("Could not register as a service!");
+ }
+ return 0;
+}
diff --git a/bluetooth/aidl/default/test/fuzzer.cpp b/bluetooth/aidl/default/test/fuzzer.cpp
new file mode 100644
index 0000000..e7a1eef
--- /dev/null
+++ b/bluetooth/aidl/default/test/fuzzer.cpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fuzzbinder/libbinder_ndk_driver.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+#include "BluetoothHci.h"
+
+using aidl::android::hardware::bluetooth::impl::BluetoothHci;
+using android::fuzzService;
+using ndk::SharedRefBase;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ auto service = SharedRefBase::make<BluetoothHci>();
+
+ fuzzService(service->asBinder().get(), FuzzedDataProvider(data, size));
+
+ return 0;
+}
diff --git a/bluetooth/async/Android.bp b/bluetooth/async/Android.bp
new file mode 100644
index 0000000..bd7d7b8
--- /dev/null
+++ b/bluetooth/async/Android.bp
@@ -0,0 +1,41 @@
+package {
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_static {
+ name: "android.hardware.bluetooth.async",
+ vendor_available: true,
+ host_supported: true,
+ srcs: [
+ "async_fd_watcher.cc",
+ ],
+ export_include_dirs: ["."],
+ shared_libs: [
+ "liblog",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+}
+
+cc_test {
+ name: "bluetooth-vendor-interface-async-test",
+ host_supported: true,
+ srcs: [
+ "test/async_fd_watcher_unittest.cc",
+ ],
+ shared_libs: [
+ "liblog",
+ "libutils",
+ ],
+ static_libs: [
+ "android.hardware.bluetooth.async",
+ "libgmock",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ test_suites: ["general-tests"],
+}
diff --git a/bluetooth/async/async_fd_watcher.cc b/bluetooth/async/async_fd_watcher.cc
new file mode 100644
index 0000000..fb634ff
--- /dev/null
+++ b/bluetooth/async/async_fd_watcher.cc
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "async_fd_watcher.h"
+
+#include <string.h>
+
+#include <algorithm>
+#include <atomic>
+#include <condition_variable>
+#include <map>
+#include <mutex>
+#include <thread>
+#include <vector>
+
+#include "fcntl.h"
+#include "log/log.h"
+#include "sys/select.h"
+#include "unistd.h"
+
+static const int INVALID_FD = -1;
+
+namespace android::hardware::bluetooth::async {
+
+int AsyncFdWatcher::WatchFdForNonBlockingReads(
+ int file_descriptor, const ReadCallback& on_read_fd_ready_callback) {
+ // Add file descriptor and callback
+ {
+ std::unique_lock<std::mutex> guard(internal_mutex_);
+ watched_fds_[file_descriptor] = on_read_fd_ready_callback;
+ }
+
+ // Start the thread if not started yet
+ return tryStartThread();
+}
+
+int AsyncFdWatcher::ConfigureTimeout(
+ const std::chrono::milliseconds timeout,
+ const TimeoutCallback& on_timeout_callback) {
+ // Add timeout and callback
+ {
+ std::unique_lock<std::mutex> guard(timeout_mutex_);
+ timeout_cb_ = on_timeout_callback;
+ timeout_ms_ = timeout;
+ }
+
+ notifyThread();
+ return 0;
+}
+
+void AsyncFdWatcher::StopWatchingFileDescriptors() { stopThread(); }
+
+AsyncFdWatcher::~AsyncFdWatcher() {}
+
+// Make sure to call this with at least one file descriptor ready to be
+// watched upon or the thread routine will return immediately
+int AsyncFdWatcher::tryStartThread() {
+ if (std::atomic_exchange(&running_, true)) return 0;
+
+ // Set up the communication channel
+ int pipe_fds[2];
+ if (pipe2(pipe_fds, O_NONBLOCK)) return -1;
+
+ notification_listen_fd_ = pipe_fds[0];
+ notification_write_fd_ = pipe_fds[1];
+
+ thread_ = std::thread([this]() { ThreadRoutine(); });
+ if (!thread_.joinable()) return -1;
+
+ return 0;
+}
+
+int AsyncFdWatcher::stopThread() {
+ if (!std::atomic_exchange(&running_, false)) return 0;
+
+ notifyThread();
+ if (std::this_thread::get_id() != thread_.get_id()) {
+ thread_.join();
+ }
+
+ {
+ std::unique_lock<std::mutex> guard(internal_mutex_);
+ watched_fds_.clear();
+ }
+
+ {
+ std::unique_lock<std::mutex> guard(timeout_mutex_);
+ timeout_cb_ = nullptr;
+ }
+
+ close(notification_listen_fd_);
+ close(notification_write_fd_);
+
+ return 0;
+}
+
+int AsyncFdWatcher::notifyThread() {
+ uint8_t buffer[] = {0};
+ if (TEMP_FAILURE_RETRY(write(notification_write_fd_, &buffer, 1)) < 0) {
+ return -1;
+ }
+ return 0;
+}
+
+void AsyncFdWatcher::ThreadRoutine() {
+ while (running_) {
+ fd_set read_fds;
+ FD_ZERO(&read_fds);
+ FD_SET(notification_listen_fd_, &read_fds);
+ int max_read_fd = INVALID_FD;
+ for (auto& it : watched_fds_) {
+ FD_SET(it.first, &read_fds);
+ max_read_fd = std::max(max_read_fd, it.first);
+ }
+
+ struct timeval timeout;
+ struct timeval* timeout_ptr = NULL;
+ if (timeout_ms_ > std::chrono::milliseconds(0)) {
+ timeout.tv_sec = timeout_ms_.count() / 1000;
+ timeout.tv_usec = (timeout_ms_.count() % 1000) * 1000;
+ timeout_ptr = &timeout;
+ }
+
+ // Wait until there is data available to read on some FD.
+ int nfds = std::max(notification_listen_fd_, max_read_fd);
+ int retval = select(nfds + 1, &read_fds, NULL, NULL, timeout_ptr);
+
+ // There was some error.
+ if (retval < 0) continue;
+
+ // Timeout.
+ if (retval == 0) {
+ // Allow the timeout callback to modify the timeout.
+ TimeoutCallback saved_cb;
+ {
+ std::unique_lock<std::mutex> guard(timeout_mutex_);
+ if (timeout_ms_ > std::chrono::milliseconds(0)) saved_cb = timeout_cb_;
+ }
+ if (saved_cb != nullptr) saved_cb();
+ continue;
+ }
+
+ // Read data from the notification FD.
+ if (FD_ISSET(notification_listen_fd_, &read_fds)) {
+ char buffer[] = {0};
+ TEMP_FAILURE_RETRY(read(notification_listen_fd_, buffer, 1));
+ continue;
+ }
+
+ // Invoke the data ready callbacks if appropriate.
+ {
+ // Hold the mutex to make sure that the callbacks are still valid.
+ std::unique_lock<std::mutex> guard(internal_mutex_);
+ for (auto& it : watched_fds_) {
+ if (FD_ISSET(it.first, &read_fds)) {
+ it.second(it.first);
+ }
+ }
+ }
+ }
+}
+
+} // namespace android::hardware::bluetooth::async
diff --git a/bluetooth/async/async_fd_watcher.h b/bluetooth/async/async_fd_watcher.h
new file mode 100644
index 0000000..b50a7a0
--- /dev/null
+++ b/bluetooth/async/async_fd_watcher.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <map>
+#include <mutex>
+#include <thread>
+
+namespace android::hardware::bluetooth::async {
+
+using ReadCallback = std::function<void(int)>;
+using TimeoutCallback = std::function<void(void)>;
+
+class AsyncFdWatcher {
+ public:
+ AsyncFdWatcher() = default;
+ ~AsyncFdWatcher();
+
+ int WatchFdForNonBlockingReads(int file_descriptor,
+ const ReadCallback& on_read_fd_ready_callback);
+ int ConfigureTimeout(const std::chrono::milliseconds timeout,
+ const TimeoutCallback& on_timeout_callback);
+ void StopWatchingFileDescriptors();
+
+ private:
+ AsyncFdWatcher(const AsyncFdWatcher&) = delete;
+ AsyncFdWatcher& operator=(const AsyncFdWatcher&) = delete;
+
+ int tryStartThread();
+ int stopThread();
+ int notifyThread();
+ void ThreadRoutine();
+
+ std::atomic_bool running_{false};
+ std::thread thread_;
+ std::mutex internal_mutex_;
+ std::mutex timeout_mutex_;
+
+ std::map<int, ReadCallback> watched_fds_;
+ int notification_listen_fd_;
+ int notification_write_fd_;
+ TimeoutCallback timeout_cb_;
+ std::chrono::milliseconds timeout_ms_;
+};
+
+} // namespace android::hardware::bluetooth::async
diff --git a/bluetooth/async/test/async_fd_watcher_unittest.cc b/bluetooth/async/test/async_fd_watcher_unittest.cc
new file mode 100644
index 0000000..6d75f10
--- /dev/null
+++ b/bluetooth/async/test/async_fd_watcher_unittest.cc
@@ -0,0 +1,377 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "async_fd_watcher_unittest"
+
+#include "async_fd_watcher.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <log/log.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <cstdint>
+#include <cstring>
+#include <vector>
+
+namespace android::hardware::bluetooth::async_test {
+
+using android::hardware::bluetooth::async::AsyncFdWatcher;
+
+class AsyncFdWatcherSocketTest : public ::testing::Test {
+ public:
+ static const uint16_t kPort = 6111;
+ static const size_t kBufferSize = 16;
+
+ bool CheckBufferEquals() {
+ return strcmp(server_buffer_, client_buffer_) == 0;
+ }
+
+ protected:
+ int StartServer() {
+ ALOGD("%s", __func__);
+ struct sockaddr_in serv_addr;
+ int fd = socket(AF_INET, SOCK_STREAM, 0);
+ EXPECT_FALSE(fd < 0);
+
+ memset(&serv_addr, 0, sizeof(serv_addr));
+ serv_addr.sin_family = AF_INET;
+ serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ serv_addr.sin_port = htons(kPort);
+ int reuse_flag = 1;
+ EXPECT_FALSE(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse_flag,
+ sizeof(reuse_flag)) < 0);
+ EXPECT_FALSE(bind(fd, (sockaddr*)&serv_addr, sizeof(serv_addr)) < 0);
+
+ ALOGD("%s before listen", __func__);
+ listen(fd, 1);
+ return fd;
+ }
+
+ int AcceptConnection(int fd) {
+ ALOGD("%s", __func__);
+ struct sockaddr_in cli_addr;
+ memset(&cli_addr, 0, sizeof(cli_addr));
+ socklen_t clilen = sizeof(cli_addr);
+
+ int connection_fd = accept(fd, (struct sockaddr*)&cli_addr, &clilen);
+ EXPECT_FALSE(connection_fd < 0);
+
+ return connection_fd;
+ }
+
+ void ReadIncomingMessage(int fd) {
+ ALOGD("%s", __func__);
+ int n = TEMP_FAILURE_RETRY(read(fd, server_buffer_, kBufferSize - 1));
+ EXPECT_FALSE(n < 0);
+
+ if (n == 0) { // got EOF
+ ALOGD("%s: EOF", __func__);
+ } else {
+ ALOGD("%s: Got something", __func__);
+ n = write(fd, "1", 1);
+ }
+ }
+
+ void SetUp() override {
+ ALOGD("%s", __func__);
+ memset(server_buffer_, 0, kBufferSize);
+ memset(client_buffer_, 0, kBufferSize);
+ }
+
+ void ConfigureServer() {
+ socket_fd_ = StartServer();
+
+ conn_watcher_.WatchFdForNonBlockingReads(socket_fd_, [this](int fd) {
+ int connection_fd = AcceptConnection(fd);
+ ALOGD("%s: Conn_watcher fd = %d", __func__, fd);
+
+ conn_watcher_.ConfigureTimeout(std::chrono::seconds(0), []() {
+ bool connection_timeout_cleared = false;
+ ASSERT_TRUE(connection_timeout_cleared);
+ });
+
+ ALOGD("%s: 3", __func__);
+ async_fd_watcher_.WatchFdForNonBlockingReads(
+ connection_fd, [this](int fd) { ReadIncomingMessage(fd); });
+
+ // Time out if it takes longer than a second.
+ SetTimeout(std::chrono::seconds(1));
+ });
+ conn_watcher_.ConfigureTimeout(std::chrono::seconds(1), []() {
+ bool connection_timeout = true;
+ ASSERT_FALSE(connection_timeout);
+ });
+ }
+
+ void CleanUpServer() {
+ async_fd_watcher_.StopWatchingFileDescriptors();
+ conn_watcher_.StopWatchingFileDescriptors();
+ close(socket_fd_);
+ }
+
+ void TearDown() override {
+ ALOGD("%s 3", __func__);
+ EXPECT_TRUE(CheckBufferEquals());
+ }
+
+ void OnTimeout() {
+ ALOGD("%s", __func__);
+ timed_out_ = true;
+ }
+
+ void ClearTimeout() {
+ ALOGD("%s", __func__);
+ timed_out_ = false;
+ }
+
+ bool TimedOut() {
+ ALOGD("%s %d", __func__, timed_out_ ? 1 : 0);
+ return timed_out_;
+ }
+
+ void SetTimeout(std::chrono::milliseconds timeout_ms) {
+ ALOGD("%s", __func__);
+ async_fd_watcher_.ConfigureTimeout(timeout_ms, [this]() { OnTimeout(); });
+ ClearTimeout();
+ }
+
+ int ConnectClient() {
+ ALOGD("%s", __func__);
+ int socket_cli_fd = socket(AF_INET, SOCK_STREAM, 0);
+ EXPECT_FALSE(socket_cli_fd < 0);
+
+ struct sockaddr_in serv_addr;
+ memset((void*)&serv_addr, 0, sizeof(serv_addr));
+ serv_addr.sin_family = AF_INET;
+ serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ serv_addr.sin_port = htons(kPort);
+
+ int result =
+ connect(socket_cli_fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
+ EXPECT_FALSE(result < 0);
+
+ return socket_cli_fd;
+ }
+
+ void WriteFromClient(int socket_cli_fd) {
+ ALOGD("%s", __func__);
+ strcpy(client_buffer_, "1");
+ int n = write(socket_cli_fd, client_buffer_, strlen(client_buffer_));
+ EXPECT_TRUE(n > 0);
+ }
+
+ void AwaitServerResponse(int socket_cli_fd) {
+ ALOGD("%s", __func__);
+ int n = read(socket_cli_fd, client_buffer_, 1);
+ ALOGD("%s done", __func__);
+ EXPECT_TRUE(n > 0);
+ }
+
+ private:
+ AsyncFdWatcher async_fd_watcher_;
+ AsyncFdWatcher conn_watcher_;
+ int socket_fd_;
+ char server_buffer_[kBufferSize];
+ char client_buffer_[kBufferSize];
+ bool timed_out_;
+};
+
+// Use a single AsyncFdWatcher to signal a connection to the server socket.
+TEST_F(AsyncFdWatcherSocketTest, Connect) {
+ int socket_fd = StartServer();
+
+ AsyncFdWatcher conn_watcher;
+ conn_watcher.WatchFdForNonBlockingReads(socket_fd, [this](int fd) {
+ int connection_fd = AcceptConnection(fd);
+ close(connection_fd);
+ });
+
+ // Fail if the client doesn't connect within 1 second.
+ conn_watcher.ConfigureTimeout(std::chrono::seconds(1), []() {
+ bool connection_timeout = true;
+ ASSERT_FALSE(connection_timeout);
+ });
+
+ int socket_cli_fd = ConnectClient();
+ conn_watcher.StopWatchingFileDescriptors();
+ close(socket_fd);
+ close(socket_cli_fd);
+}
+
+// Use a single AsyncFdWatcher to signal a connection to the server socket.
+TEST_F(AsyncFdWatcherSocketTest, TimedOutConnect) {
+ int socket_fd = StartServer();
+ bool timed_out = false;
+ bool* timeout_ptr = &timed_out;
+
+ AsyncFdWatcher conn_watcher;
+ conn_watcher.WatchFdForNonBlockingReads(socket_fd, [this](int fd) {
+ int connection_fd = AcceptConnection(fd);
+ close(connection_fd);
+ });
+
+ // Set the timeout flag after 100ms.
+ conn_watcher.ConfigureTimeout(std::chrono::milliseconds(100),
+ [timeout_ptr]() { *timeout_ptr = true; });
+ EXPECT_FALSE(timed_out);
+ sleep(1);
+ EXPECT_TRUE(timed_out);
+ conn_watcher.StopWatchingFileDescriptors();
+ close(socket_fd);
+}
+
+// Modify the timeout in a timeout callback.
+TEST_F(AsyncFdWatcherSocketTest, TimedOutSchedulesTimeout) {
+ int socket_fd = StartServer();
+ bool timed_out = false;
+ bool timed_out2 = false;
+
+ AsyncFdWatcher conn_watcher;
+ conn_watcher.WatchFdForNonBlockingReads(socket_fd, [this](int fd) {
+ int connection_fd = AcceptConnection(fd);
+ close(connection_fd);
+ });
+
+ // Set a timeout flag in each callback.
+ conn_watcher.ConfigureTimeout(std::chrono::milliseconds(500),
+ [&conn_watcher, &timed_out, &timed_out2]() {
+ timed_out = true;
+ conn_watcher.ConfigureTimeout(
+ std::chrono::seconds(1),
+ [&timed_out2]() { timed_out2 = true; });
+ });
+ EXPECT_FALSE(timed_out);
+ EXPECT_FALSE(timed_out2);
+ sleep(1);
+ EXPECT_TRUE(timed_out);
+ EXPECT_FALSE(timed_out2);
+ sleep(1);
+ EXPECT_TRUE(timed_out);
+ EXPECT_TRUE(timed_out2);
+ conn_watcher.StopWatchingFileDescriptors();
+ close(socket_fd);
+}
+
+MATCHER_P(ReadAndMatchSingleChar, byte,
+ "Reads a byte from the file descriptor and matches the value against "
+ "byte") {
+ char inbuf[1] = {0};
+
+ int n = TEMP_FAILURE_RETRY(read(arg, inbuf, 1));
+
+ TEMP_FAILURE_RETRY(write(arg, inbuf, 1));
+ if (n != 1) {
+ return false;
+ }
+ return inbuf[0] == byte;
+};
+
+// Use a single AsyncFdWatcher to watch two file descriptors.
+TEST_F(AsyncFdWatcherSocketTest, WatchTwoFileDescriptors) {
+ int sockfd1[2];
+ int sockfd2[2];
+ socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd1);
+ socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd2);
+
+ testing::MockFunction<void(int)> cb1;
+ testing::MockFunction<void(int)> cb2;
+
+ AsyncFdWatcher watcher;
+ watcher.WatchFdForNonBlockingReads(sockfd1[0], cb1.AsStdFunction());
+
+ watcher.WatchFdForNonBlockingReads(sockfd2[0], cb2.AsStdFunction());
+
+ EXPECT_CALL(cb1, Call(ReadAndMatchSingleChar('1')));
+ char one_buf[1] = {'1'};
+ TEMP_FAILURE_RETRY(write(sockfd1[1], one_buf, sizeof(one_buf)));
+
+ EXPECT_CALL(cb2, Call(ReadAndMatchSingleChar('2')));
+ char two_buf[1] = {'2'};
+ TEMP_FAILURE_RETRY(write(sockfd2[1], two_buf, sizeof(two_buf)));
+
+ // Blocking read instead of a flush.
+ TEMP_FAILURE_RETRY(read(sockfd1[1], one_buf, sizeof(one_buf)));
+ TEMP_FAILURE_RETRY(read(sockfd2[1], two_buf, sizeof(two_buf)));
+
+ watcher.StopWatchingFileDescriptors();
+}
+
+// Use two AsyncFdWatchers to set up a server socket.
+TEST_F(AsyncFdWatcherSocketTest, ClientServer) {
+ ConfigureServer();
+ int socket_cli_fd = ConnectClient();
+
+ WriteFromClient(socket_cli_fd);
+
+ AwaitServerResponse(socket_cli_fd);
+
+ close(socket_cli_fd);
+ CleanUpServer();
+}
+
+// Use two AsyncFdWatchers to set up a server socket, which times out.
+TEST_F(AsyncFdWatcherSocketTest, TimeOutTest) {
+ ConfigureServer();
+ int socket_cli_fd = ConnectClient();
+
+ while (!TimedOut()) sleep(1);
+
+ close(socket_cli_fd);
+ CleanUpServer();
+}
+
+// Use two AsyncFdWatchers to set up a server socket, which times out.
+TEST_F(AsyncFdWatcherSocketTest, RepeatedTimeOutTest) {
+ ConfigureServer();
+ int socket_cli_fd = ConnectClient();
+ ClearTimeout();
+
+ // Time out when there are no writes.
+ EXPECT_FALSE(TimedOut());
+ sleep(2);
+ EXPECT_TRUE(TimedOut());
+ ClearTimeout();
+
+ // Don't time out when there is a write.
+ WriteFromClient(socket_cli_fd);
+ AwaitServerResponse(socket_cli_fd);
+ EXPECT_FALSE(TimedOut());
+ ClearTimeout();
+
+ // Time out when the write is late.
+ sleep(2);
+ WriteFromClient(socket_cli_fd);
+ AwaitServerResponse(socket_cli_fd);
+ EXPECT_TRUE(TimedOut());
+ ClearTimeout();
+
+ // Time out when there is a pause after a write.
+ WriteFromClient(socket_cli_fd);
+ sleep(2);
+ AwaitServerResponse(socket_cli_fd);
+ EXPECT_TRUE(TimedOut());
+ ClearTimeout();
+
+ close(socket_cli_fd);
+ CleanUpServer();
+}
+
+} // namespace android::hardware::bluetooth::async_test
diff --git a/bluetooth/audio/2.0/Android.bp b/bluetooth/audio/2.0/Android.bp
index e4d48c1..725ec11 100644
--- a/bluetooth/audio/2.0/Android.bp
+++ b/bluetooth/audio/2.0/Android.bp
@@ -26,6 +26,6 @@
gen_java: false,
apex_available: [
"//apex_available:platform",
- "com.android.bluetooth",
+ "com.android.btservices",
],
}
diff --git a/bluetooth/audio/2.1/Android.bp b/bluetooth/audio/2.1/Android.bp
index 1175fb3..4ca0bef 100644
--- a/bluetooth/audio/2.1/Android.bp
+++ b/bluetooth/audio/2.1/Android.bp
@@ -25,7 +25,7 @@
],
apex_available: [
"//apex_available:platform",
- "com.android.bluetooth",
+ "com.android.btservices",
],
gen_java: false,
}
diff --git a/bluetooth/audio/aidl/Android.bp b/bluetooth/audio/aidl/Android.bp
index c581702..4aea83f 100644
--- a/bluetooth/audio/aidl/Android.bp
+++ b/bluetooth/audio/aidl/Android.bp
@@ -40,12 +40,9 @@
enabled: false,
},
ndk: {
- vndk: {
- enabled: true,
- },
apex_available: [
"//apex_available:platform",
- "com.android.bluetooth",
+ "com.android.btservices",
],
min_sdk_version: "31",
},
diff --git a/bluetooth/hci/Android.bp b/bluetooth/hci/Android.bp
new file mode 100644
index 0000000..f0f6e8f
--- /dev/null
+++ b/bluetooth/hci/Android.bp
@@ -0,0 +1,46 @@
+package {
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_static {
+ name: "android.hardware.bluetooth.hci",
+ vendor_available: true,
+ host_supported: true,
+ defaults: ["hidl_defaults"],
+ srcs: [
+ "hci_packetizer.cc",
+ "h4_protocol.cc",
+ ],
+ export_include_dirs: ["."],
+ shared_libs: [
+ "libbase",
+ "libhidlbase",
+ "liblog",
+ "libutils",
+ ],
+}
+
+cc_test {
+ name: "bluetooth-vendor-interface-hci-test",
+ host_supported: true,
+ defaults: ["hidl_defaults"],
+ srcs: [
+ "test/h4_protocol_unittest.cc",
+ ],
+ shared_libs: [
+ "libbase",
+ "libhidlbase",
+ "liblog",
+ "libutils",
+ ],
+ static_libs: [
+ "android.hardware.bluetooth.async",
+ "android.hardware.bluetooth.hci",
+ "libgmock",
+ ],
+ sanitize: {
+ address: true,
+ cfi: true,
+ },
+ test_suites: ["general-tests"],
+}
diff --git a/bluetooth/hci/h4_protocol.cc b/bluetooth/hci/h4_protocol.cc
new file mode 100644
index 0000000..97ba7aa
--- /dev/null
+++ b/bluetooth/hci/h4_protocol.cc
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "h4_protocol.h"
+
+#define LOG_TAG "android.hardware.bluetooth.hci-h4"
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/uio.h>
+
+#include "log/log.h"
+
+namespace android::hardware::bluetooth::hci {
+
+H4Protocol::H4Protocol(int fd, PacketReadCallback cmd_cb,
+ PacketReadCallback acl_cb, PacketReadCallback sco_cb,
+ PacketReadCallback event_cb, PacketReadCallback iso_cb,
+ DisconnectCallback disconnect_cb)
+ : uart_fd_(fd),
+ cmd_cb_(std::move(cmd_cb)),
+ acl_cb_(std::move(acl_cb)),
+ sco_cb_(std::move(sco_cb)),
+ event_cb_(std::move(event_cb)),
+ iso_cb_(std::move(iso_cb)),
+ disconnect_cb_(std::move(disconnect_cb)) {}
+
+size_t H4Protocol::Send(PacketType type, const std::vector<uint8_t>& vector) {
+ return Send(type, vector.data(), vector.size());
+}
+
+size_t H4Protocol::Send(PacketType type, const uint8_t* data, size_t length) {
+ /* For HCI communication over USB dongle, multiple write results in
+ * response timeout as driver expect type + data at once to process
+ * the command, so using "writev"(for atomicity) here.
+ */
+ struct iovec iov[2];
+ ssize_t ret = 0;
+ iov[0].iov_base = &type;
+ iov[0].iov_len = sizeof(type);
+ iov[1].iov_base = (void*)data;
+ iov[1].iov_len = length;
+ while (1) {
+ ret = TEMP_FAILURE_RETRY(writev(uart_fd_, iov, 2));
+ if (ret == -1) {
+ if (errno == EAGAIN) {
+ ALOGE("%s error writing to UART (%s)", __func__, strerror(errno));
+ continue;
+ }
+ } else if (ret == 0) {
+ // Nothing written :(
+ ALOGE("%s zero bytes written - something went wrong...", __func__);
+ break;
+ }
+ break;
+ }
+ return ret;
+}
+
+size_t H4Protocol::OnPacketReady(const std::vector<uint8_t>& packet) {
+ switch (hci_packet_type_) {
+ case PacketType::COMMAND:
+ cmd_cb_(packet);
+ break;
+ case PacketType::ACL_DATA:
+ acl_cb_(packet);
+ break;
+ case PacketType::SCO_DATA:
+ sco_cb_(packet);
+ break;
+ case PacketType::EVENT:
+ event_cb_(packet);
+ break;
+ case PacketType::ISO_DATA:
+ iso_cb_(packet);
+ break;
+ default: {
+ LOG_ALWAYS_FATAL("Bad packet type 0x%x",
+ static_cast<int>(hci_packet_type_));
+ }
+ }
+ return packet.size();
+}
+
+void H4Protocol::SendDataToPacketizer(uint8_t* buffer, size_t length) {
+ std::vector<uint8_t> input_buffer{buffer, buffer + length};
+ size_t buffer_offset = 0;
+ while (buffer_offset < input_buffer.size()) {
+ if (hci_packet_type_ == PacketType::UNKNOWN) {
+ hci_packet_type_ =
+ static_cast<PacketType>(input_buffer.data()[buffer_offset]);
+ buffer_offset += 1;
+ } else {
+ bool packet_ready = hci_packetizer_.OnDataReady(
+ hci_packet_type_, input_buffer, buffer_offset);
+ if (packet_ready) {
+ // Call packet callback and move offset.
+ buffer_offset += OnPacketReady(hci_packetizer_.GetPacket());
+ // Get ready for the next type byte.
+ hci_packet_type_ = PacketType::UNKNOWN;
+ } else {
+ // The data was consumed, but there wasn't a packet.
+ buffer_offset = input_buffer.size();
+ }
+ }
+ }
+}
+
+void H4Protocol::OnDataReady() {
+ if (disconnected_) {
+ return;
+ }
+ uint8_t buffer[kMaxPacketLength];
+ ssize_t bytes_read =
+ TEMP_FAILURE_RETRY(read(uart_fd_, buffer, kMaxPacketLength));
+ if (bytes_read == 0) {
+ ALOGI("No bytes read, calling the disconnect callback");
+ disconnected_ = true;
+ disconnect_cb_();
+ return;
+ }
+ if (bytes_read < 0) {
+ ALOGW("error reading from UART (%s)", strerror(errno));
+ return;
+ }
+ SendDataToPacketizer(buffer, bytes_read);
+}
+
+} // namespace android::hardware::bluetooth::hci
diff --git a/bluetooth/hci/h4_protocol.h b/bluetooth/hci/h4_protocol.h
new file mode 100644
index 0000000..5daee83
--- /dev/null
+++ b/bluetooth/hci/h4_protocol.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <memory>
+#include <vector>
+
+#include "hci_internals.h"
+#include "hci_packetizer.h"
+
+namespace android::hardware::bluetooth::hci {
+
+using PacketReadCallback = std::function<void(const std::vector<uint8_t>&)>;
+using DisconnectCallback = std::function<void(void)>;
+
+class H4Protocol {
+ public:
+ H4Protocol(int fd, PacketReadCallback cmd_cb, PacketReadCallback acl_cb,
+ PacketReadCallback sco_cb, PacketReadCallback event_cb,
+ PacketReadCallback iso_cb, DisconnectCallback disconnect_cb);
+
+ size_t Send(PacketType type, const uint8_t* data, size_t length);
+ size_t Send(PacketType type, const std::vector<uint8_t>& data);
+
+ void OnDataReady();
+
+ protected:
+ size_t OnPacketReady(const std::vector<uint8_t>& packet);
+ void SendDataToPacketizer(uint8_t* buffer, size_t length);
+
+ private:
+ int uart_fd_;
+ bool disconnected_{false};
+
+ PacketReadCallback cmd_cb_;
+ PacketReadCallback acl_cb_;
+ PacketReadCallback sco_cb_;
+ PacketReadCallback event_cb_;
+ PacketReadCallback iso_cb_;
+ DisconnectCallback disconnect_cb_;
+
+ PacketType hci_packet_type_{PacketType::UNKNOWN};
+ HciPacketizer hci_packetizer_;
+
+ /**
+ * Question : Why read in single chunk rather than multiple reads?
+ * Answer: Using multiple reads does not work with some BT USB dongles.
+ * Reading in single shot gives expected response.
+ * ACL max length is 2 bytes, so using 64K as the buffer length.
+ */
+ static constexpr size_t kMaxPacketLength = 64 * 1024;
+};
+
+} // namespace android::hardware::bluetooth::hci
diff --git a/bluetooth/hci/hci_internals.h b/bluetooth/hci/hci_internals.h
new file mode 100644
index 0000000..71b6191
--- /dev/null
+++ b/bluetooth/hci/hci_internals.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cstdlib>
+
+namespace android::hardware::bluetooth::hci {
+
+// HCI UART transport packet types (Volume 4, Part A, 2)
+enum class PacketType : uint8_t {
+ UNKNOWN = 0,
+ COMMAND = 1,
+ ACL_DATA = 2,
+ SCO_DATA = 3,
+ EVENT = 4,
+ ISO_DATA = 5,
+};
+
+// 2 bytes for opcode, 1 byte for parameter length (Volume 4, Part E, 5.4.1)
+static constexpr size_t kCommandHeaderSize = 3;
+static constexpr size_t kCommandLengthOffset = 2;
+
+// 2 bytes for handle, 2 bytes for data length (Volume 4, Part E, 5.4.2)
+static constexpr size_t kAclHeaderSize = 4;
+static constexpr size_t kAclLengthOffset = 2;
+
+// 2 bytes for handle, 1 byte for data length (Volume 4, Part E, 5.4.3)
+static constexpr size_t kScoHeaderSize = 3;
+static constexpr size_t kScoLengthOffset = 2;
+
+// 1 byte for event code, 1 byte for parameter length (Volume 4, Part E, 5.4.4)
+static constexpr size_t kEventHeaderSize = 2;
+static constexpr size_t kEventLengthOffset = 1;
+
+// 2 bytes for handle, 2 bytes for data length (Volume 4, Part E, 5.4.5)
+static constexpr size_t kIsoHeaderSize = 4;
+static constexpr size_t kIsoLengthOffset = 2;
+
+static constexpr size_t kMaxHeaderSize = kAclHeaderSize;
+
+} // namespace android::hardware::bluetooth::hci
diff --git a/bluetooth/hci/hci_packetizer.cc b/bluetooth/hci/hci_packetizer.cc
new file mode 100644
index 0000000..5b6c443
--- /dev/null
+++ b/bluetooth/hci/hci_packetizer.cc
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "hci_packetizer.h"
+
+#define LOG_TAG "android.hardware.bluetooth.hci-packetizer"
+#include "log/log.h"
+
+namespace android::hardware::bluetooth::hci {
+
+namespace {
+
+const size_t header_size_for_type[] = {0,
+ kCommandHeaderSize,
+ kAclHeaderSize,
+ kScoHeaderSize,
+ kEventHeaderSize,
+ kIsoHeaderSize};
+const size_t packet_length_offset_for_type[] = {0,
+ kCommandLengthOffset,
+ kAclLengthOffset,
+ kScoLengthOffset,
+ kEventLengthOffset,
+ kIsoLengthOffset};
+
+size_t HciGetPacketLengthForType(PacketType type,
+ const std::vector<uint8_t>& header) {
+ size_t offset = packet_length_offset_for_type[static_cast<uint8_t>(type)];
+ if (type != PacketType::ACL_DATA && type != PacketType::ISO_DATA) {
+ return header[offset];
+ }
+ return (((header[offset + 1]) << 8) | header[offset]);
+}
+
+} // namespace
+
+const std::vector<uint8_t>& HciPacketizer::GetPacket() const { return packet_; }
+
+bool HciPacketizer::OnDataReady(PacketType packet_type,
+ const std::vector<uint8_t>& buffer,
+ size_t offset) {
+ bool packet_completed = false;
+ size_t bytes_available = buffer.size() - offset;
+ switch (state_) {
+ case HCI_HEADER: {
+ size_t header_size =
+ header_size_for_type[static_cast<size_t>(packet_type)];
+ if (bytes_remaining_ == 0) {
+ bytes_remaining_ = header_size;
+ packet_.clear();
+ }
+ size_t bytes_to_copy = std::min(bytes_remaining_, bytes_available);
+ packet_.insert(packet_.end(), buffer.begin() + offset,
+ buffer.begin() + offset + bytes_to_copy);
+ bytes_remaining_ -= bytes_to_copy;
+ bytes_available -= bytes_to_copy;
+ if (bytes_remaining_ == 0) {
+ bytes_remaining_ = HciGetPacketLengthForType(packet_type, packet_);
+ if (bytes_remaining_ > 0) {
+ state_ = HCI_PAYLOAD;
+ if (bytes_available > 0) {
+ packet_completed =
+ OnDataReady(packet_type, buffer, offset + bytes_to_copy);
+ }
+ } else {
+ packet_completed = true;
+ }
+ }
+ break;
+ }
+
+ case HCI_PAYLOAD: {
+ size_t bytes_to_copy = std::min(bytes_remaining_, bytes_available);
+ packet_.insert(packet_.end(), buffer.begin() + offset,
+ buffer.begin() + offset + bytes_to_copy);
+ bytes_remaining_ -= bytes_to_copy;
+ if (bytes_remaining_ == 0) {
+ state_ = HCI_HEADER;
+ packet_completed = true;
+ }
+ break;
+ }
+ }
+ return packet_completed;
+}
+
+} // namespace android::hardware::bluetooth::hci
diff --git a/bluetooth/hci/hci_packetizer.h b/bluetooth/hci/hci_packetizer.h
new file mode 100644
index 0000000..ba3e841
--- /dev/null
+++ b/bluetooth/hci/hci_packetizer.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <functional>
+#include <memory>
+#include <vector>
+
+#include "hci_internals.h"
+
+namespace android::hardware::bluetooth::hci {
+
+class HciPacketizer {
+ public:
+ HciPacketizer() = default;
+ bool OnDataReady(PacketType packet_type, const std::vector<uint8_t>& data,
+ size_t offset);
+ const std::vector<uint8_t>& GetPacket() const;
+
+ protected:
+ enum State { HCI_HEADER, HCI_PAYLOAD };
+ State state_{HCI_HEADER};
+ std::vector<uint8_t> packet_;
+ size_t bytes_remaining_{0};
+};
+
+} // namespace android::hardware::bluetooth::hci
diff --git a/bluetooth/hci/test/h4_protocol_unittest.cc b/bluetooth/hci/test/h4_protocol_unittest.cc
new file mode 100644
index 0000000..d6f74fc
--- /dev/null
+++ b/bluetooth/hci/test/h4_protocol_unittest.cc
@@ -0,0 +1,441 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "bt_h4_unittest"
+
+#include "h4_protocol.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <log/log.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <cstdint>
+#include <cstring>
+#include <future>
+#include <vector>
+
+#include "async_fd_watcher.h"
+#include "log/log.h"
+
+using android::hardware::bluetooth::async::AsyncFdWatcher;
+using namespace android::hardware::bluetooth::hci;
+using ::testing::Eq;
+
+static char sample_data1[100] = "A point is that which has no part.";
+static char sample_data2[100] = "A line is breadthless length.";
+static char sample_data3[100] = "The ends of a line are points.";
+static char sample_data4[100] =
+ "A plane surface is a surface which lies evenly with the straight ...";
+static char acl_data[100] =
+ "A straight line is a line which lies evenly with the points on itself.";
+static char sco_data[100] =
+ "A surface is that which has length and breadth only.";
+static char event_data[100] = "The edges of a surface are lines.";
+static char iso_data[100] =
+ "A plane angle is the inclination to one another of two lines in a ...";
+
+MATCHER_P3(PacketMatches, header_, header_length, payload,
+ "Match header_length bytes of header and then the payload") {
+ size_t payload_length = strlen(payload);
+ if (header_length + payload_length != arg.size()) {
+ return false;
+ }
+
+ if (memcmp(header_, arg.data(), header_length) != 0) {
+ return false;
+ }
+
+ return memcmp(payload, arg.data() + header_length, payload_length) == 0;
+};
+
+ACTION_P(Notify, barrier) {
+ ALOGD("%s", __func__);
+ barrier->set_value();
+}
+
+class H4ProtocolTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ ALOGD("%s", __func__);
+
+ int sockfd[2];
+ socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd);
+ chip_uart_fd_ = sockfd[1];
+ stack_uart_fd_ = sockfd[0];
+ h4_hci_ = std::make_shared<H4Protocol>(
+ stack_uart_fd_, cmd_cb_.AsStdFunction(), acl_cb_.AsStdFunction(),
+ sco_cb_.AsStdFunction(), event_cb_.AsStdFunction(),
+ iso_cb_.AsStdFunction(), disconnect_cb_.AsStdFunction());
+ }
+
+ void TearDown() override {
+ close(stack_uart_fd_);
+ close(chip_uart_fd_);
+ }
+
+ virtual void CallDataReady() { h4_hci_->OnDataReady(); }
+
+ void SendAndReadUartOutbound(PacketType type, char* data) {
+ ALOGD("%s sending", __func__);
+ int data_length = strlen(data);
+ h4_hci_->Send(type, (uint8_t*)data, data_length);
+
+ int uart_length = data_length + 1; // + 1 for data type code
+ int i;
+
+ ALOGD("%s reading", __func__);
+ for (i = 0; i < uart_length; i++) {
+ fd_set read_fds;
+ FD_ZERO(&read_fds);
+ FD_SET(chip_uart_fd_, &read_fds);
+ TEMP_FAILURE_RETRY(
+ select(chip_uart_fd_ + 1, &read_fds, nullptr, nullptr, nullptr));
+
+ char byte;
+ TEMP_FAILURE_RETRY(read(chip_uart_fd_, &byte, 1));
+
+ EXPECT_EQ(i == 0 ? static_cast<uint8_t>(type) : data[i - 1], byte);
+ }
+
+ EXPECT_EQ(i, uart_length);
+ }
+
+ void ExpectInboundAclData(char* payload, std::promise<void>* promise) {
+ // h4 type[1] + handle[2] + size[2]
+ header_[0] = static_cast<uint8_t>(PacketType::ACL_DATA);
+ header_[1] = 19;
+ header_[2] = 92;
+ int length = strlen(payload);
+ header_[3] = length & 0xFF;
+ header_[4] = (length >> 8) & 0xFF;
+ ALOGD("(%d bytes) %s", length, payload);
+
+ EXPECT_CALL(acl_cb_,
+ Call(PacketMatches(header_ + 1, kAclHeaderSize, payload)))
+ .WillOnce(Notify(promise));
+ }
+
+ void WaitForTimeout(size_t timeout_ms, std::promise<void>* promise) {
+ auto future = promise->get_future();
+ auto status = future.wait_for(std::chrono::milliseconds(timeout_ms));
+ EXPECT_EQ(status, std::future_status::ready);
+ }
+
+ void WriteInboundAclData(char* payload) {
+ // Use the header_ computed in ExpectInboundAclData
+ TEMP_FAILURE_RETRY(write(chip_uart_fd_, header_, kAclHeaderSize + 1));
+ TEMP_FAILURE_RETRY(write(chip_uart_fd_, payload, strlen(payload)));
+ }
+
+ void ExpectInboundScoData(char* payload, std::promise<void>* promise) {
+ // h4 type[1] + handle[2] + size[1]
+ header_[0] = static_cast<uint8_t>(PacketType::SCO_DATA);
+ header_[1] = 20;
+ header_[2] = 17;
+ header_[3] = strlen(payload) & 0xFF;
+ EXPECT_CALL(sco_cb_,
+ Call(PacketMatches(header_ + 1, kScoHeaderSize, payload)))
+ .WillOnce(Notify(promise));
+ }
+
+ void WriteInboundScoData(char* payload) {
+ // Use the header_ computed in ExpectInboundScoData
+ ALOGD("%s writing", __func__);
+ TEMP_FAILURE_RETRY(write(chip_uart_fd_, header_, kScoHeaderSize + 1));
+ TEMP_FAILURE_RETRY(write(chip_uart_fd_, payload, strlen(payload)));
+ }
+
+ void ExpectInboundEvent(char* payload, std::promise<void>* promise) {
+ // h4 type[1] + event_code[1] + size[1]
+ header_[0] = static_cast<uint8_t>(PacketType::EVENT);
+ header_[1] = 9;
+ header_[2] = strlen(payload) & 0xFF;
+ EXPECT_CALL(event_cb_,
+ Call(PacketMatches(header_ + 1, kEventHeaderSize, payload)))
+ .WillOnce(Notify(promise));
+ }
+
+ void WriteInboundEvent(char* payload) {
+ // Use the header_ computed in ExpectInboundEvent
+ char preamble[3] = {static_cast<uint8_t>(PacketType::EVENT), 9, 0};
+ preamble[2] = strlen(payload) & 0xFF;
+ ALOGD("%s writing", __func__);
+ TEMP_FAILURE_RETRY(write(chip_uart_fd_, header_, kEventHeaderSize + 1));
+ TEMP_FAILURE_RETRY(write(chip_uart_fd_, payload, strlen(payload)));
+ }
+
+ void ExpectInboundIsoData(char* payload, std::promise<void>* promise) {
+ // h4 type[1] + handle[2] + size[1]
+ header_[0] = static_cast<uint8_t>(PacketType::ISO_DATA);
+ header_[1] = 19;
+ header_[2] = 92;
+ int length = strlen(payload);
+ header_[3] = length & 0xFF;
+ header_[4] = (length >> 8) & 0x3F;
+
+ EXPECT_CALL(iso_cb_,
+ Call(PacketMatches(header_ + 1, kIsoHeaderSize, payload)))
+ .WillOnce(Notify(promise));
+ }
+
+ void WriteInboundIsoData(char* payload) {
+ // Use the header_ computed in ExpectInboundIsoData
+ ALOGD("%s writing", __func__);
+ TEMP_FAILURE_RETRY(write(chip_uart_fd_, header_, kIsoHeaderSize + 1));
+ TEMP_FAILURE_RETRY(write(chip_uart_fd_, payload, strlen(payload)));
+ }
+
+ void WriteAndExpectManyInboundAclDataPackets(char* payload) {
+ size_t kNumPackets = 20;
+ // h4 type[1] + handle[2] + size[2]
+ char preamble[5] = {static_cast<uint8_t>(PacketType::ACL_DATA), 19, 92, 0,
+ 0};
+ int length = strlen(payload);
+ preamble[3] = length & 0xFF;
+ preamble[4] = (length >> 8) & 0xFF;
+
+ EXPECT_CALL(acl_cb_, Call(PacketMatches(preamble + 1, sizeof(preamble) - 1,
+ payload)))
+ .Times(kNumPackets);
+
+ for (size_t i = 0; i < kNumPackets; i++) {
+ TEMP_FAILURE_RETRY(write(chip_uart_fd_, preamble, sizeof(preamble)));
+ TEMP_FAILURE_RETRY(write(chip_uart_fd_, payload, strlen(payload)));
+ }
+
+ CallDataReady();
+ }
+
+ testing::MockFunction<void(const std::vector<uint8_t>&)> cmd_cb_;
+ testing::MockFunction<void(const std::vector<uint8_t>&)> event_cb_;
+ testing::MockFunction<void(const std::vector<uint8_t>&)> acl_cb_;
+ testing::MockFunction<void(const std::vector<uint8_t>&)> sco_cb_;
+ testing::MockFunction<void(const std::vector<uint8_t>&)> iso_cb_;
+ testing::MockFunction<void(void)> disconnect_cb_;
+ std::shared_ptr<H4Protocol> h4_hci_;
+ int chip_uart_fd_;
+ int stack_uart_fd_;
+
+ char header_[5];
+};
+
+// Test sending data sends correct data onto the UART
+TEST_F(H4ProtocolTest, TestSends) {
+ SendAndReadUartOutbound(PacketType::COMMAND, sample_data1);
+ SendAndReadUartOutbound(PacketType::ACL_DATA, sample_data2);
+ SendAndReadUartOutbound(PacketType::SCO_DATA, sample_data3);
+ SendAndReadUartOutbound(PacketType::ISO_DATA, sample_data4);
+}
+
+// Ensure we properly parse data coming from the UART
+TEST_F(H4ProtocolTest, TestReads) {
+ std::promise<void> acl_promise;
+ std::promise<void> sco_promise;
+ std::promise<void> event_promise;
+ std::promise<void> iso_promise;
+
+ ExpectInboundAclData(acl_data, &acl_promise);
+ WriteInboundAclData(acl_data);
+ CallDataReady();
+ ExpectInboundScoData(sco_data, &sco_promise);
+ WriteInboundScoData(sco_data);
+ CallDataReady();
+ ExpectInboundEvent(event_data, &event_promise);
+ WriteInboundEvent(event_data);
+ CallDataReady();
+ ExpectInboundIsoData(iso_data, &iso_promise);
+ WriteInboundIsoData(iso_data);
+ CallDataReady();
+
+ WaitForTimeout(100, &acl_promise);
+ WaitForTimeout(100, &sco_promise);
+ WaitForTimeout(100, &event_promise);
+ WaitForTimeout(100, &iso_promise);
+}
+
+TEST_F(H4ProtocolTest, TestMultiplePackets) {
+ WriteAndExpectManyInboundAclDataPackets(sco_data);
+}
+
+TEST_F(H4ProtocolTest, TestDisconnect) {
+ EXPECT_CALL(disconnect_cb_, Call());
+ close(chip_uart_fd_);
+ CallDataReady();
+}
+
+TEST_F(H4ProtocolTest, TestPartialWrites) {
+ size_t payload_len = strlen(acl_data);
+ const size_t kNumIntervals = payload_len + 1;
+ // h4 type[1] + handle[2] + size[2]
+ header_[0] = static_cast<uint8_t>(PacketType::ACL_DATA);
+ header_[1] = 19;
+ header_[2] = 92;
+ header_[3] = payload_len & 0xFF;
+ header_[4] = (payload_len >> 8) & 0xFF;
+
+ EXPECT_CALL(acl_cb_,
+ Call(PacketMatches(header_ + 1, sizeof(header_) - 1, acl_data)))
+ .Times(kNumIntervals);
+
+ for (size_t interval = 1; interval < kNumIntervals + 1; interval++) {
+ // Use the header_ data that expect already set up.
+ if (interval < kAclHeaderSize) {
+ TEMP_FAILURE_RETRY(write(chip_uart_fd_, header_, interval));
+ CallDataReady();
+ TEMP_FAILURE_RETRY(write(chip_uart_fd_, header_ + interval,
+ kAclHeaderSize + 1 - interval));
+ CallDataReady();
+ } else {
+ TEMP_FAILURE_RETRY(write(chip_uart_fd_, header_, kAclHeaderSize + 1));
+ CallDataReady();
+ }
+
+ for (size_t bytes = 0; bytes + interval <= payload_len; bytes += interval) {
+ TEMP_FAILURE_RETRY(write(chip_uart_fd_, acl_data + bytes, interval));
+ CallDataReady();
+ }
+ size_t extra_bytes = payload_len % interval;
+ if (extra_bytes) {
+ TEMP_FAILURE_RETRY(write(
+ chip_uart_fd_, acl_data + payload_len - extra_bytes, extra_bytes));
+ CallDataReady();
+ }
+ }
+}
+
+class H4ProtocolAsyncTest : public H4ProtocolTest {
+ protected:
+ void SetUp() override {
+ H4ProtocolTest::SetUp();
+ fd_watcher_.WatchFdForNonBlockingReads(
+ stack_uart_fd_, [this](int) { h4_hci_->OnDataReady(); });
+ }
+
+ void TearDown() override { fd_watcher_.StopWatchingFileDescriptors(); }
+
+ void CallDataReady() override {
+ // The Async test can't call data ready.
+ FAIL();
+ }
+
+ void SendAndReadUartOutbound(PacketType type, char* data) {
+ ALOGD("%s sending", __func__);
+ int data_length = strlen(data);
+ h4_hci_->Send(type, (uint8_t*)data, data_length);
+
+ int uart_length = data_length + 1; // + 1 for data type code
+ int i;
+
+ ALOGD("%s reading", __func__);
+ for (i = 0; i < uart_length; i++) {
+ fd_set read_fds;
+ FD_ZERO(&read_fds);
+ FD_SET(chip_uart_fd_, &read_fds);
+ TEMP_FAILURE_RETRY(
+ select(chip_uart_fd_ + 1, &read_fds, nullptr, nullptr, nullptr));
+
+ char byte;
+ TEMP_FAILURE_RETRY(read(chip_uart_fd_, &byte, 1));
+
+ EXPECT_EQ(i == 0 ? static_cast<uint8_t>(type) : data[i - 1], byte);
+ }
+
+ EXPECT_EQ(i, uart_length);
+ }
+
+ void WriteAndExpectInboundAclData(char* payload) {
+ std::promise<void> promise;
+ ExpectInboundAclData(payload, &promise);
+ WriteInboundAclData(payload);
+ WaitForTimeout(100, &promise);
+ }
+
+ void WriteAndExpectInboundScoData(char* payload) {
+ std::promise<void> promise;
+ ExpectInboundScoData(payload, &promise);
+ WriteInboundScoData(payload);
+ WaitForTimeout(100, &promise);
+ }
+
+ void WriteAndExpectInboundEvent(char* payload) {
+ std::promise<void> promise;
+ ExpectInboundEvent(payload, &promise);
+ WriteInboundEvent(payload);
+ WaitForTimeout(100, &promise);
+ }
+
+ void WriteAndExpectInboundIsoData(char* payload) {
+ std::promise<void> promise;
+ ExpectInboundIsoData(payload, &promise);
+ WriteInboundIsoData(payload);
+ WaitForTimeout(100, &promise);
+ }
+
+ void WriteAndExpectManyInboundAclDataPackets(char* payload) {
+ const size_t kNumPackets = 20;
+ // h4 type[1] + handle[2] + size[2]
+ char preamble[5] = {static_cast<uint8_t>(PacketType::ACL_DATA), 19, 92, 0,
+ 0};
+ int length = strlen(payload);
+ preamble[3] = length & 0xFF;
+ preamble[4] = (length >> 8) & 0xFF;
+
+ EXPECT_CALL(acl_cb_, Call(PacketMatches(preamble + 1, sizeof(preamble) - 1,
+ payload)))
+ .Times(kNumPackets);
+
+ for (size_t i = 0; i < kNumPackets; i++) {
+ TEMP_FAILURE_RETRY(write(chip_uart_fd_, preamble, sizeof(preamble)));
+ TEMP_FAILURE_RETRY(write(chip_uart_fd_, payload, strlen(payload)));
+ }
+
+ WriteAndExpectInboundEvent(event_data);
+ }
+
+ AsyncFdWatcher fd_watcher_;
+};
+
+// Test sending data sends correct data onto the UART
+TEST_F(H4ProtocolAsyncTest, TestSends) {
+ SendAndReadUartOutbound(PacketType::COMMAND, sample_data1);
+ SendAndReadUartOutbound(PacketType::ACL_DATA, sample_data2);
+ SendAndReadUartOutbound(PacketType::SCO_DATA, sample_data3);
+ SendAndReadUartOutbound(PacketType::ISO_DATA, sample_data4);
+}
+
+// Ensure we properly parse data coming from the UART
+TEST_F(H4ProtocolAsyncTest, TestReads) {
+ WriteAndExpectInboundAclData(acl_data);
+ WriteAndExpectInboundScoData(sco_data);
+ WriteAndExpectInboundEvent(event_data);
+ WriteAndExpectInboundIsoData(iso_data);
+}
+
+TEST_F(H4ProtocolAsyncTest, TestMultiplePackets) {
+ WriteAndExpectManyInboundAclDataPackets(sco_data);
+}
+
+TEST_F(H4ProtocolAsyncTest, TestDisconnect) {
+ std::promise<void> promise;
+ EXPECT_CALL(disconnect_cb_, Call()).WillOnce(Notify(&promise));
+ close(chip_uart_fd_);
+
+ // Fail if it takes longer than 100 ms.
+ WaitForTimeout(100, &promise);
+}
diff --git a/boot/1.1/default/boot_control/Android.bp b/boot/1.1/default/boot_control/Android.bp
index ad71700..6aa30c2 100644
--- a/boot/1.1/default/boot_control/Android.bp
+++ b/boot/1.1/default/boot_control/Android.bp
@@ -25,8 +25,6 @@
cc_defaults {
name: "libboot_control_defaults",
- vendor: true,
- recovery_available: true,
relative_install_path: "hw",
cflags: [
@@ -42,7 +40,7 @@
"liblog",
],
static_libs: [
- "libbootloader_message_vendor",
+ "libbootloader_message",
"libfstab",
],
}
@@ -51,6 +49,8 @@
name: "libboot_control",
defaults: ["libboot_control_defaults"],
export_include_dirs: ["include"],
+ recovery_available: true,
+ vendor_available: true,
srcs: ["libboot_control.cpp"],
}
@@ -58,6 +58,8 @@
cc_library_shared {
name: "bootctrl.default",
defaults: ["libboot_control_defaults"],
+ recovery_available: true,
+ vendor_available: true,
srcs: ["legacy_boot_control.cpp"],
diff --git a/boot/1.1/default/boot_control/include/libboot_control/libboot_control.h b/boot/1.1/default/boot_control/include/libboot_control/libboot_control.h
index ac17d6d..572a8b6 100644
--- a/boot/1.1/default/boot_control/include/libboot_control/libboot_control.h
+++ b/boot/1.1/default/boot_control/include/libboot_control/libboot_control.h
@@ -25,9 +25,8 @@
// Helper library to implement the IBootControl HAL using the misc partition.
class BootControl {
- using MergeStatus = ::android::hardware::boot::V1_1::MergeStatus;
-
public:
+ using MergeStatus = ::android::hardware::boot::V1_1::MergeStatus;
bool Init();
unsigned int GetNumberSlots();
unsigned int GetCurrentSlot();
diff --git a/boot/1.1/default/boot_control/include/private/boot_control_definition.h b/boot/1.1/default/boot_control/include/private/boot_control_definition.h
index 8f02111..57c2f73 100644
--- a/boot/1.1/default/boot_control/include/private/boot_control_definition.h
+++ b/boot/1.1/default/boot_control/include/private/boot_control_definition.h
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+#include <stdint.h>
+
+#include <bootloader_message/bootloader_message.h>
/**
* The A/B-specific bootloader message structure (4-KiB).
diff --git a/boot/1.1/vts/functional/VtsHalBootV1_1TargetTest.cpp b/boot/1.1/vts/functional/VtsHalBootV1_1TargetTest.cpp
index c38f257..05f136e 100644
--- a/boot/1.1/vts/functional/VtsHalBootV1_1TargetTest.cpp
+++ b/boot/1.1/vts/functional/VtsHalBootV1_1TargetTest.cpp
@@ -1,4 +1,5 @@
/*
+
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,6 +20,7 @@
#include <vector>
#include <android-base/logging.h>
+#include <android-base/properties.h>
#include <android/hardware/boot/1.1/IBootControl.h>
#include <android/hardware/boot/1.1/types.h>
#include <gmock/gmock.h>
@@ -37,9 +39,21 @@
using ::android::hardware::boot::V1_1::MergeStatus;
using ::testing::Contains;
+bool IsVirtualAbEnabled();
+
+#define SKIP_IF_NON_VIRTUAL_AB() \
+ do { \
+ if (!IsVirtualAbEnabled()) GTEST_SKIP() << "Test for Virtual A/B devices only"; \
+ } while (0)
+
+bool IsVirtualAbEnabled() {
+ return android::base::GetBoolProperty("ro.virtual_ab.enabled", false);
+}
+
class BootHidlTest : public testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
+ SKIP_IF_NON_VIRTUAL_AB();
boot = IBootControl::getService(GetParam());
ASSERT_NE(boot, nullptr);
diff --git a/boot/aidl/Android.bp b/boot/aidl/Android.bp
new file mode 100644
index 0000000..be38245
--- /dev/null
+++ b/boot/aidl/Android.bp
@@ -0,0 +1,40 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+aidl_interface {
+ name: "android.hardware.boot",
+ vendor_available: true,
+ srcs: ["android/hardware/boot/*.aidl"],
+ stability: "vintf",
+ recovery_available: true,
+ backend: {
+ java: {
+ sdk_version: "module_current",
+ },
+ cpp: {
+ enabled: false,
+ },
+ },
+}
diff --git a/boot/aidl/aidl_api/android.hardware.boot/current/android/hardware/boot/IBootControl.aidl b/boot/aidl/aidl_api/android.hardware.boot/current/android/hardware/boot/IBootControl.aidl
new file mode 100644
index 0000000..c8ab51e
--- /dev/null
+++ b/boot/aidl/aidl_api/android.hardware.boot/current/android/hardware/boot/IBootControl.aidl
@@ -0,0 +1,50 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.boot;
+@VintfStability
+interface IBootControl {
+ int getActiveBootSlot();
+ int getCurrentSlot();
+ int getNumberSlots();
+ android.hardware.boot.MergeStatus getSnapshotMergeStatus();
+ String getSuffix(in int slot);
+ boolean isSlotBootable(in int slot);
+ boolean isSlotMarkedSuccessful(in int slot);
+ void markBootSuccessful();
+ void setActiveBootSlot(in int slot);
+ void setSlotAsUnbootable(in int slot);
+ void setSnapshotMergeStatus(in android.hardware.boot.MergeStatus status);
+ const int INVALID_SLOT = -1;
+ const int COMMAND_FAILED = -2;
+}
diff --git a/boot/aidl/aidl_api/android.hardware.boot/current/android/hardware/boot/MergeStatus.aidl b/boot/aidl/aidl_api/android.hardware.boot/current/android/hardware/boot/MergeStatus.aidl
new file mode 100644
index 0000000..53c6204
--- /dev/null
+++ b/boot/aidl/aidl_api/android.hardware.boot/current/android/hardware/boot/MergeStatus.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.boot;
+@Backing(type="int") @VintfStability
+enum MergeStatus {
+ NONE = 0,
+ UNKNOWN = 1,
+ SNAPSHOTTED = 2,
+ MERGING = 3,
+ CANCELLED = 4,
+}
diff --git a/boot/aidl/android/hardware/boot/IBootControl.aidl b/boot/aidl/android/hardware/boot/IBootControl.aidl
new file mode 100644
index 0000000..6c9e8ce
--- /dev/null
+++ b/boot/aidl/android/hardware/boot/IBootControl.aidl
@@ -0,0 +1,158 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package android.hardware.boot;
+
+import android.hardware.boot.MergeStatus;
+
+@VintfStability
+interface IBootControl {
+ const int INVALID_SLOT = -1;
+ const int COMMAND_FAILED = -2;
+ /**
+ * Returns the active slot to boot into on the next boot. If
+ * setActiveBootSlot() has been called, the getter function should return the
+ * same slot as the one provided in the last setActiveBootSlot() call.
+ * The returned value is always guaranteed to be strictly less than the
+ * value returned by getNumberSlots. Slots start at 0 and finish at
+ * getNumberSlots() - 1. For instance, a system with A/B must return 0 or 1.
+ * @return the active slot to boot into on the next boot.
+ */
+ int getActiveBootSlot();
+
+ /**
+ * getCurrentSlot() returns the slot number of that the current boot is booted
+ * from, for example slot number 0 (Slot A). It is assumed that if the current
+ * slot is A, then the block devices underlying B can be accessed directly
+ * without any risk of corruption.
+ * The returned value is always guaranteed to be strictly less than the
+ * value returned by getNumberSlots. Slots start at 0 and finish at
+ * getNumberSlots() - 1. The value returned here must match the suffix passed
+ * from the bootloader, regardless of which slot is active or successful.
+ * @return the slot number of that the current boot is booted
+ */
+ int getCurrentSlot();
+
+ /**
+ * getNumberSlots() returns the number of available slots.
+ * For instance, a system with a single set of partitions must return
+ * 1, a system with A/B must return 2, A/B/C -> 3 and so on. A system with
+ * less than two slots doesn't support background updates, for example if
+ * running from a virtual machine with only one copy of each partition for the
+ * purpose of testing.
+ * @return number of available slots
+ */
+ int getNumberSlots();
+
+ /**
+ * Returns whether a snapshot-merge of any dynamic partition is in progress.
+ *
+ * This function must return the merge status set by the last setSnapshotMergeStatus call and
+ * recorded by the bootloader with one exception. If the partitions are being flashed from the
+ * bootloader such that the pending merge must be canceled (for example, if the super partition
+ * is being flashed), this function must return CANCELLED.
+ *
+ * @param out success True if the merge status is read successfully, false otherwise.
+ * @return Merge status.
+ */
+ MergeStatus getSnapshotMergeStatus();
+
+ /**
+ * getSuffix() returns the string suffix used by partitions that correspond to
+ * the slot number passed in as a parameter. The bootloader must pass the
+ * suffix of the currently active slot either through a kernel command line
+ * property at androidboot.slot_suffix, or the device tree at
+ * /firmware/android/slot_suffix.
+ * @return suffix for the input slot, or the empty string "" if slot
+ * does not match an existing slot.
+ */
+ String getSuffix(in int slot);
+
+ /**
+ * isSlotBootable() returns if the slot passed in parameter is bootable. Note
+ * that slots can be made unbootable by both the bootloader and by the OS
+ * using setSlotAsUnbootable.
+ * @return true if the slot is bootable, false if it's not.
+ * @throws service specific error INVALID_SLOT if slot is invalid.
+ */
+ boolean isSlotBootable(in int slot);
+
+ /**
+ * isSlotMarkedSuccessful() returns if the slot passed in parameter has been
+ * marked as successful using markBootSuccessful. Note that only the current
+ * slot can be marked as successful but any slot can be queried.
+ * @return true if the slot has been marked as successful, false if it has
+ * not.
+ * @throws service specific error INVALID_SLOT if slot is invalid.
+ */
+ boolean isSlotMarkedSuccessful(in int slot);
+
+ /**
+ * markBootSuccessful() marks the current slot as having booted successfully.
+ *
+ * @throws Service specific error COMMAND_FAILED if command failed.
+ */
+ void markBootSuccessful();
+
+ /**
+ * setActiveBootSlot() marks the slot passed in parameter as the active boot
+ * slot (see getCurrentSlot for an explanation of the "slot" parameter). This
+ * overrides any previous call to setSlotAsUnbootable.
+ * @throws Service specific error INVALID_SLOT if slot is invalid, or COMMAND_FAILED if
+ * operation failed.
+ */
+ void setActiveBootSlot(in int slot);
+
+ /**
+ * setSlotAsUnbootable() marks the slot passed in parameter as
+ * an unbootable. This can be used while updating the contents of the slot's
+ * partitions, so that the system must not attempt to boot a known bad set up.
+ * @throws Service specific error INVALID_SLOT if slot is invalid, or COMMAND_FAILED if
+ * operation failed.
+ */
+ void setSlotAsUnbootable(in int slot);
+
+ /**
+ * Sets whether a snapshot-merge of any dynamic partition is in progress.
+ *
+ * After the merge status is set to a given value, subsequent calls to
+ * getSnapshotMergeStatus must return the set value.
+ *
+ * The merge status must be persistent across reboots. That is, getSnapshotMergeStatus
+ * must return the same value after a reboot if the merge status is not altered in any way
+ * (e.g. set by setSnapshotMergeStatus or set to CANCELLED by bootloader).
+ *
+ * Read/write access to the merge status must be atomic. When the HAL is processing a
+ * setSnapshotMergeStatus call, all subsequent calls to getSnapshotMergeStatus must block until
+ * setSnapshotMergeStatus has returned.
+ *
+ * A MERGING state indicates that dynamic partitions are partially comprised by blocks in the
+ * userdata partition.
+ *
+ * When the merge status is set to MERGING, the following operations must be prohibited from the
+ * bootloader:
+ * - Flashing or erasing "userdata" or "metadata".
+ *
+ * The following operations may be prohibited when the status is set to MERGING. If not
+ * prohibited, it is recommended that the user receive a warning.
+ * - Changing the active slot (e.g. via "fastboot set_active")
+ *
+ * @param status Merge status.
+ *
+ * @throws service specific error COMMAND_FAILED if operation failed.
+ */
+ void setSnapshotMergeStatus(in MergeStatus status);
+}
diff --git a/boot/aidl/android/hardware/boot/MergeStatus.aidl b/boot/aidl/android/hardware/boot/MergeStatus.aidl
new file mode 100644
index 0000000..16ac85f
--- /dev/null
+++ b/boot/aidl/android/hardware/boot/MergeStatus.aidl
@@ -0,0 +1,42 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package android.hardware.boot;
+
+@VintfStability
+@Backing(type="int")
+enum MergeStatus {
+ /**
+ * No snapshot or merge is in progress.
+ */
+ NONE = 0,
+ /**
+ * The merge status could not be determined.
+ */
+ UNKNOWN,
+ /**
+ * Partitions are being snapshotted, but no merge has been started.
+ */
+ SNAPSHOTTED,
+ /**
+ * At least one partition has merge is in progress.
+ */
+ MERGING,
+ /**
+ * A merge was in progress, but it was canceled by the bootloader.
+ */
+ CANCELLED,
+}
diff --git a/boot/aidl/client/Android.bp b/boot/aidl/client/Android.bp
new file mode 100644
index 0000000..db4a7ea
--- /dev/null
+++ b/boot/aidl/client/Android.bp
@@ -0,0 +1,31 @@
+
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library {
+ name: "libboot_control_client",
+ srcs: [
+ "BootControlClient.cpp"
+ ],
+ export_include_dirs: ["include"],
+ export_shared_lib_headers: ["android.hardware.boot-V1-ndk"],
+ recovery_available: true,
+ shared_libs: [
+ "android.hardware.boot-V1-ndk",
+ "android.hardware.boot@1.0",
+ "android.hardware.boot@1.1",
+ "android.hardware.boot@1.2",
+ "libhidlbase",
+ "libbinder_ndk",
+ "libbase",
+ "libcutils",
+ "libutils",
+ ],
+}
diff --git a/boot/aidl/client/BootControlClient.cpp b/boot/aidl/client/BootControlClient.cpp
new file mode 100644
index 0000000..89258d2
--- /dev/null
+++ b/boot/aidl/client/BootControlClient.cpp
@@ -0,0 +1,364 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <BootControlClient.h>
+
+#include <aidl/android/hardware/boot/IBootControl.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/hardware/boot/1.0/IBootControl.h>
+#include <android/hardware/boot/1.1/IBootControl.h>
+#include <android/hardware/boot/1.2/IBootControl.h>
+#include "utils/StrongPointer.h"
+
+#define CONCAT(x, y) x##y
+
+#define LOG_NDK_STATUS(x) \
+ do { \
+ const auto CONCAT(status, __COUNTER__) = x; \
+ if (!CONCAT(status, __COUNTER__).isOk()) { \
+ LOG(ERROR) << #x << " failed " << CONCAT(status, __COUNTER__).getDescription(); \
+ } \
+ } while (0)
+
+using aidl::android::hardware::boot::MergeStatus;
+
+std::ostream& operator<<(std::ostream& os, MergeStatus status) {
+ switch (status) {
+ case MergeStatus::NONE:
+ os << "MergeStatus::NONE";
+ break;
+ case MergeStatus::UNKNOWN:
+ os << "MergeStatus::UNKNOWN";
+ break;
+ case MergeStatus::SNAPSHOTTED:
+ os << "MergeStatus::SNAPSHOTTED";
+ break;
+ case MergeStatus::MERGING:
+ os << "MergeStatus::MERGING";
+ break;
+ case MergeStatus::CANCELLED:
+ os << "MergeStatus::CANCELLED";
+ break;
+ default:
+ os << static_cast<int>(status);
+ break;
+ }
+ return os;
+}
+
+namespace android::hal {
+class BootControlClientAidl final : public BootControlClient {
+ using IBootControl = ::aidl::android::hardware::boot::IBootControl;
+
+ public:
+ BootControlClientAidl(std::shared_ptr<IBootControl> module) : module_(module) {}
+
+ BootControlVersion GetVersion() const override { return BootControlVersion::BOOTCTL_AIDL; }
+
+ ~BootControlClientAidl() = default;
+ virtual int32_t GetNumSlots() const {
+ int32_t ret = -1;
+ LOG_NDK_STATUS(module_->getNumberSlots(&ret));
+ return ret;
+ }
+
+ int32_t GetCurrentSlot() const {
+ int32_t ret = -1;
+ LOG_NDK_STATUS(module_->getCurrentSlot(&ret));
+ return ret;
+ }
+ MergeStatus getSnapshotMergeStatus() const {
+ MergeStatus status = MergeStatus::UNKNOWN;
+ LOG_NDK_STATUS(module_->getSnapshotMergeStatus(&status));
+ return status;
+ }
+ std::string GetSuffix(int32_t slot) const {
+ std::string ret;
+ const auto status = module_->getSuffix(slot, &ret);
+ if (!status.isOk()) {
+ LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
+ << " failed " << status.getDescription();
+ return {};
+ }
+ return ret;
+ }
+
+ std::optional<bool> IsSlotBootable(int32_t slot) const {
+ bool ret = false;
+ const auto status = module_->isSlotBootable(slot, &ret);
+ if (!status.isOk()) {
+ LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
+ << " failed " << status.getDescription();
+ return {};
+ }
+ return ret;
+ }
+
+ CommandResult MarkSlotUnbootable(int32_t slot) {
+ const auto status = module_->setSlotAsUnbootable(slot);
+ if (!status.isOk()) {
+ LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
+ << " failed " << status.getDescription();
+ }
+ return {.success = status.isOk(), .errMsg = status.getDescription()};
+ }
+
+ CommandResult SetActiveBootSlot(int slot) {
+ const auto status = module_->setActiveBootSlot(slot);
+ if (!status.isOk()) {
+ LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
+ << " failed " << status.getDescription();
+ }
+ return {.success = status.isOk(), .errMsg = status.getDescription()};
+ }
+ int GetActiveBootSlot() const {
+ int ret = -1;
+ LOG_NDK_STATUS(module_->getActiveBootSlot(&ret));
+ return ret;
+ }
+
+ // Check if |slot| is marked boot successfully.
+ std::optional<bool> IsSlotMarkedSuccessful(int slot) const {
+ bool ret = false;
+ const auto status = module_->isSlotMarkedSuccessful(slot, &ret);
+ if (!status.isOk()) {
+ LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
+ << " failed " << status.getDescription();
+ return {};
+ }
+ return ret;
+ }
+
+ CommandResult MarkBootSuccessful() {
+ const auto status = module_->markBootSuccessful();
+ if (!status.isOk()) {
+ LOG(ERROR) << __FUNCTION__ << " failed " << status.getDescription();
+ }
+ return {.success = status.isOk(), .errMsg = status.getDescription()};
+ }
+
+ CommandResult SetSnapshotMergeStatus(aidl::android::hardware::boot::MergeStatus merge_status) {
+ const auto status = module_->setSnapshotMergeStatus(merge_status);
+ if (!status.isOk()) {
+ LOG(ERROR) << __FUNCTION__ << "(" << merge_status << ")"
+ << " failed " << status.getDescription();
+ }
+ return {.success = status.isOk(), .errMsg = status.getDescription()};
+ }
+
+ private:
+ const std::shared_ptr<IBootControl> module_;
+};
+
+using namespace android::hardware::boot;
+
+class BootControlClientHIDL final : public BootControlClient {
+ public:
+ BootControlClientHIDL(android::sp<V1_0::IBootControl> module_v1,
+ android::sp<V1_1::IBootControl> module_v1_1,
+ android::sp<V1_2::IBootControl> module_v1_2)
+ : module_v1_(module_v1), module_v1_1_(module_v1_1), module_v1_2_(module_v1_2) {
+ CHECK(module_v1_ != nullptr);
+ }
+ BootControlVersion GetVersion() const override {
+ if (module_v1_2_ != nullptr) {
+ return BootControlVersion::BOOTCTL_V1_2;
+ } else if (module_v1_1_ != nullptr) {
+ return BootControlVersion::BOOTCTL_V1_1;
+ } else {
+ return BootControlVersion::BOOTCTL_V1_0;
+ }
+ }
+ int32_t GetNumSlots() const {
+ const auto ret = module_v1_->getNumberSlots();
+ if (!ret.isOk()) {
+ LOG(ERROR) << __FUNCTION__ << " failed " << ret.description();
+ }
+ return ret.withDefault(-1);
+ }
+
+ int32_t GetCurrentSlot() const {
+ const auto ret = module_v1_->getCurrentSlot();
+ if (!ret.isOk()) {
+ LOG(ERROR) << __FUNCTION__ << " failed " << ret.description();
+ }
+ return ret.withDefault(-1);
+ }
+
+ std::string GetSuffix(int32_t slot) const {
+ std::string suffix;
+ const auto ret = module_v1_->getSuffix(
+ slot,
+ [&](const ::android::hardware::hidl_string& slotSuffix) { suffix = slotSuffix; });
+ if (!ret.isOk()) {
+ LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
+ << " failed " << ret.description();
+ }
+ return suffix;
+ }
+
+ std::optional<bool> IsSlotBootable(int32_t slot) const {
+ const auto ret = module_v1_->isSlotBootable(slot);
+ if (!ret.isOk()) {
+ LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
+ << " failed " << ret.description();
+ return {};
+ }
+ const auto bool_result = ret.withDefault(V1_0::BoolResult::INVALID_SLOT);
+ if (bool_result == V1_0::BoolResult::INVALID_SLOT) {
+ return {};
+ }
+ return bool_result == V1_0::BoolResult::TRUE;
+ }
+
+ CommandResult MarkSlotUnbootable(int32_t slot) {
+ CommandResult result;
+ const auto ret =
+ module_v1_->setSlotAsUnbootable(slot, [&](const V1_0::CommandResult& error) {
+ result.success = error.success;
+ result.errMsg = error.errMsg;
+ });
+ if (!ret.isOk()) {
+ LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
+ << " failed " << ret.description();
+ }
+ return result;
+ }
+
+ CommandResult SetActiveBootSlot(int32_t slot) {
+ CommandResult result;
+ const auto ret = module_v1_->setActiveBootSlot(slot, [&](const V1_0::CommandResult& error) {
+ result.success = error.success;
+ result.errMsg = error.errMsg;
+ });
+ if (!ret.isOk()) {
+ LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
+ << " failed " << ret.description();
+ }
+ return result;
+ }
+
+ CommandResult MarkBootSuccessful() {
+ CommandResult result;
+ const auto ret = module_v1_->markBootSuccessful([&](const V1_0::CommandResult& error) {
+ result.success = error.success;
+ result.errMsg = error.errMsg;
+ });
+ if (!ret.isOk()) {
+ LOG(ERROR) << __FUNCTION__ << " failed " << ret.description();
+ }
+ return result;
+ }
+
+ std::optional<bool> IsSlotMarkedSuccessful(int32_t slot) const {
+ const auto ret = module_v1_->isSlotMarkedSuccessful(slot);
+ if (!ret.isOk()) {
+ LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
+ << " failed " << ret.description();
+ return {};
+ }
+ const auto bool_result = ret.withDefault(V1_0::BoolResult::INVALID_SLOT);
+ if (bool_result == V1_0::BoolResult::INVALID_SLOT) {
+ return {};
+ }
+ return bool_result == V1_0::BoolResult::TRUE;
+ }
+
+ MergeStatus getSnapshotMergeStatus() const {
+ if (module_v1_1_ == nullptr) {
+ LOG(ERROR) << __FUNCTION__ << " is unsupported, requires at least boot v1.1";
+ return MergeStatus::UNKNOWN;
+ }
+ const auto ret = module_v1_1_->getSnapshotMergeStatus();
+ if (!ret.isOk()) {
+ LOG(ERROR) << __FUNCTION__ << " failed " << ret.description();
+ }
+ return static_cast<MergeStatus>(
+ ret.withDefault(static_cast<V1_1::MergeStatus>(MergeStatus::UNKNOWN)));
+ }
+
+ CommandResult SetSnapshotMergeStatus(MergeStatus merge_status) {
+ if (module_v1_1_ == nullptr) {
+ return {.success = false,
+ .errMsg = "setSnapshotMergeStatus is unsupported, requires at least boot v1.1"};
+ }
+ const auto ret =
+ module_v1_1_->setSnapshotMergeStatus(static_cast<V1_1::MergeStatus>(merge_status));
+ if (!ret.isOk()) {
+ LOG(ERROR) << __FUNCTION__ << "(" << merge_status << ")"
+ << " failed " << ret.description();
+ }
+ return {.success = ret.isOk(), .errMsg = ret.description()};
+ }
+
+ int32_t GetActiveBootSlot() const {
+ if (module_v1_2_ == nullptr) {
+ LOG(ERROR) << __FUNCTION__ << " is unsupported, requires at least boot v1.2";
+ return -1;
+ }
+ const auto ret = module_v1_2_->getActiveBootSlot();
+ if (!ret.isOk()) {
+ LOG(ERROR) << __FUNCTION__ << " failed " << ret.description();
+ }
+ return ret.withDefault(-1);
+ }
+
+ private:
+ android::sp<V1_0::IBootControl> module_v1_;
+ android::sp<V1_1::IBootControl> module_v1_1_;
+ android::sp<V1_2::IBootControl> module_v1_2_;
+};
+
+std::unique_ptr<BootControlClient> BootControlClient::WaitForService() {
+ const auto instance_name =
+ std::string(::aidl::android::hardware::boot::IBootControl::descriptor) + "/default";
+
+ if (AServiceManager_isDeclared(instance_name.c_str())) {
+ auto module = ::aidl::android::hardware::boot::IBootControl::fromBinder(
+ ndk::SpAIBinder(AServiceManager_waitForService(instance_name.c_str())));
+ if (module == nullptr) {
+ LOG(ERROR) << "AIDL " << instance_name
+ << " is declared but waitForService returned nullptr.";
+ return nullptr;
+ }
+ LOG(INFO) << "Using AIDL version of IBootControl";
+ return std::make_unique<BootControlClientAidl>(module);
+ }
+ LOG(INFO) << "AIDL IBootControl not available, falling back to HIDL.";
+
+ android::sp<V1_0::IBootControl> v1_0_module;
+ android::sp<V1_1::IBootControl> v1_1_module;
+ android::sp<V1_2::IBootControl> v1_2_module;
+ v1_0_module = V1_0::IBootControl::getService();
+ if (v1_0_module == nullptr) {
+ LOG(ERROR) << "Error getting bootctrl v1.0 module.";
+ return nullptr;
+ }
+ v1_1_module = V1_1::IBootControl::castFrom(v1_0_module);
+ v1_2_module = V1_2::IBootControl::castFrom(v1_0_module);
+ if (v1_2_module != nullptr) {
+ LOG(INFO) << "Using HIDL version 1.2 of IBootControl";
+ } else if (v1_1_module != nullptr) {
+ LOG(INFO) << "Using HIDL version 1.1 of IBootControl";
+ } else {
+ LOG(INFO) << "Using HIDL version 1.0 of IBootControl";
+ }
+
+ return std::make_unique<BootControlClientHIDL>(v1_0_module, v1_1_module, v1_2_module);
+}
+
+} // namespace android::hal
diff --git a/boot/aidl/client/include/BootControlClient.h b/boot/aidl/client/include/BootControlClient.h
new file mode 100644
index 0000000..472e82e
--- /dev/null
+++ b/boot/aidl/client/include/BootControlClient.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __BOOT_CONTROL_CLIENT_H_
+#define __BOOT_CONTROL_CLIENT_H_
+
+#include <aidl/android/hardware/boot/MergeStatus.h>
+
+#include <stdint.h>
+
+#include <memory>
+#include <optional>
+
+namespace android::hal {
+
+struct CommandResult {
+ bool success;
+ std::string errMsg;
+ constexpr bool IsOk() const { return success; }
+};
+
+enum class BootControlVersion { BOOTCTL_V1_0, BOOTCTL_V1_1, BOOTCTL_V1_2, BOOTCTL_AIDL };
+
+class BootControlClient {
+ public:
+ using MergeStatus = aidl::android::hardware::boot::MergeStatus;
+ virtual ~BootControlClient() = default;
+ virtual BootControlVersion GetVersion() const = 0;
+ // Return the number of update slots in the system. A system will normally
+ // have two slots, named "A" and "B" in the documentation, but sometimes
+ // images running from other media can have only one slot, like some USB
+ // image. Systems with only one slot won't be able to update.
+ [[nodiscard]] virtual int32_t GetNumSlots() const = 0;
+
+ // Return the slot where we are running the system from. On success, the
+ // result is a number between 0 and GetNumSlots() - 1. Otherwise, log an error
+ // and return kInvalidSlot.
+ [[nodiscard]] virtual int32_t GetCurrentSlot() const = 0;
+
+ // Return string suffix for input slot. Usually, for slot 0 the suffix is _a, and for slot 1 the
+ // suffix is _b.
+ [[nodiscard]] virtual std::string GetSuffix(int32_t slot) const = 0;
+
+ // Returns whether the passed |slot| is marked as bootable. Returns false if
+ // the slot is invalid.
+ [[nodiscard]] virtual std::optional<bool> IsSlotBootable(int32_t slot) const = 0;
+
+ // Mark the specified slot unbootable. No other slot flags are modified.
+ // Returns true on success.
+ [[nodiscard]] virtual CommandResult MarkSlotUnbootable(int32_t slot) = 0;
+
+ // Set the passed |slot| as the preferred boot slot. Returns whether it
+ // succeeded setting the active slot. If succeeded, on next boot the
+ // bootloader will attempt to load the |slot| marked as active. Note that this
+ // method doesn't change the value of GetCurrentSlot() on the current boot.
+ // Return true if operation succeeded.
+ [[nodiscard]] virtual CommandResult SetActiveBootSlot(int32_t slot) = 0;
+
+ // Check if |slot| is marked boot successfully. Return empty optional if the RPC call failed.
+ [[nodiscard]] virtual std::optional<bool> IsSlotMarkedSuccessful(int32_t slot) const = 0;
+
+ // Mark boot as successful. Return an error message if operation failed.
+ [[nodiscard]] virtual CommandResult MarkBootSuccessful() = 0;
+
+ // Added in IBootControl v1.1
+ // Return the current merge status.
+ [[nodiscard]] virtual MergeStatus getSnapshotMergeStatus() const = 0;
+
+ // Set snapshot merge status, return true if succeeded.
+ [[nodiscard]] virtual CommandResult SetSnapshotMergeStatus(MergeStatus status) = 0;
+
+ // Added in IBootControl v1.2
+ // Get the active slot. In other words, the slot which will be used on
+ // next system reboot. This should match the |slot| parameter of last
+ // successful call to |SetActiveBootSlot|.
+ // Return 0xFFFFFFFF if underlying HAL doesn't support this operation.
+ [[nodiscard]] virtual int32_t GetActiveBootSlot() const = 0;
+
+ [[nodiscard]] static std::unique_ptr<BootControlClient> WaitForService();
+};
+
+} // namespace android::hal
+
+#endif
diff --git a/boot/aidl/default/Android.bp b/boot/aidl/default/Android.bp
new file mode 100644
index 0000000..dcb40db
--- /dev/null
+++ b/boot/aidl/default/Android.bp
@@ -0,0 +1,55 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_defaults {
+ name: "android.hardware.boot-service_common",
+ relative_install_path: "hw",
+ defaults: ["libboot_control_defaults"],
+ vintf_fragments: ["android.hardware.boot-service.default.xml"],
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "android.hardware.boot@1.1",
+ "android.hardware.boot-V1-ndk",
+ ],
+ 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"],
+ vendor: true,
+}
+
+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,
+}
diff --git a/boot/aidl/default/BootControl.cpp b/boot/aidl/default/BootControl.cpp
new file mode 100644
index 0000000..b73c94d
--- /dev/null
+++ b/boot/aidl/default/BootControl.cpp
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BootControl.h"
+#include <cstdint>
+
+#include <android-base/logging.h>
+
+using HIDLMergeStatus = ::android::bootable::BootControl::MergeStatus;
+using ndk::ScopedAStatus;
+
+namespace aidl::android::hardware::boot {
+
+BootControl::BootControl() {
+ CHECK(impl_.Init());
+}
+
+ScopedAStatus BootControl::getActiveBootSlot(int32_t* _aidl_return) {
+ *_aidl_return = impl_.GetActiveBootSlot();
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus BootControl::getCurrentSlot(int32_t* _aidl_return) {
+ *_aidl_return = impl_.GetCurrentSlot();
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus BootControl::getNumberSlots(int32_t* _aidl_return) {
+ *_aidl_return = impl_.GetNumberSlots();
+ return ScopedAStatus::ok();
+}
+
+namespace {
+
+static constexpr MergeStatus ToAIDLMergeStatus(HIDLMergeStatus status) {
+ switch (status) {
+ case HIDLMergeStatus::NONE:
+ return MergeStatus::NONE;
+ case HIDLMergeStatus::UNKNOWN:
+ return MergeStatus::UNKNOWN;
+ case HIDLMergeStatus::SNAPSHOTTED:
+ return MergeStatus::SNAPSHOTTED;
+ case HIDLMergeStatus::MERGING:
+ return MergeStatus::MERGING;
+ case HIDLMergeStatus::CANCELLED:
+ return MergeStatus::CANCELLED;
+ }
+}
+
+static constexpr HIDLMergeStatus ToHIDLMergeStatus(MergeStatus status) {
+ switch (status) {
+ case MergeStatus::NONE:
+ return HIDLMergeStatus::NONE;
+ case MergeStatus::UNKNOWN:
+ return HIDLMergeStatus::UNKNOWN;
+ case MergeStatus::SNAPSHOTTED:
+ return HIDLMergeStatus::SNAPSHOTTED;
+ case MergeStatus::MERGING:
+ return HIDLMergeStatus::MERGING;
+ case MergeStatus::CANCELLED:
+ return HIDLMergeStatus::CANCELLED;
+ }
+}
+
+}
+
+ScopedAStatus BootControl::getSnapshotMergeStatus(MergeStatus* _aidl_return) {
+ *_aidl_return = ToAIDLMergeStatus(impl_.GetSnapshotMergeStatus());
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus BootControl::getSuffix(int32_t in_slot, std::string* _aidl_return) {
+ if (!impl_.IsValidSlot(in_slot)) {
+ // Old HIDL hal returns empty string for invalid slots. We should maintain this behavior in
+ // AIDL for compatibility.
+ _aidl_return->clear();
+ } else {
+ *_aidl_return = impl_.GetSuffix(in_slot);
+ }
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus BootControl::isSlotBootable(int32_t in_slot, bool* _aidl_return) {
+ if (!impl_.IsValidSlot(in_slot)) {
+ return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+ INVALID_SLOT, (std::string("Invalid slot ") + std::to_string(in_slot)).c_str());
+ }
+ *_aidl_return = impl_.IsSlotBootable(in_slot);
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus BootControl::isSlotMarkedSuccessful(int32_t in_slot, bool* _aidl_return) {
+ if (!impl_.IsValidSlot(in_slot)) {
+ return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+ INVALID_SLOT, (std::string("Invalid slot ") + std::to_string(in_slot)).c_str());
+ }
+ *_aidl_return = impl_.IsSlotMarkedSuccessful(in_slot);
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus BootControl::markBootSuccessful() {
+ if (!impl_.MarkBootSuccessful()) {
+ return ScopedAStatus::fromServiceSpecificErrorWithMessage(COMMAND_FAILED,
+ "Operation failed");
+ }
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus BootControl::setActiveBootSlot(int32_t in_slot) {
+ if (!impl_.IsValidSlot(in_slot)) {
+ return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+ INVALID_SLOT, (std::string("Invalid slot ") + std::to_string(in_slot)).c_str());
+ }
+ if (!impl_.SetActiveBootSlot(in_slot)) {
+ return ScopedAStatus::fromServiceSpecificErrorWithMessage(COMMAND_FAILED,
+ "Operation failed");
+ }
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus BootControl::setSlotAsUnbootable(int32_t in_slot) {
+ if (!impl_.IsValidSlot(in_slot)) {
+ return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+ INVALID_SLOT, (std::string("Invalid slot ") + std::to_string(in_slot)).c_str());
+ }
+ if (!impl_.SetSlotAsUnbootable(in_slot)) {
+ return ScopedAStatus::fromServiceSpecificErrorWithMessage(COMMAND_FAILED,
+ "Operation failed");
+ }
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus BootControl::setSnapshotMergeStatus(MergeStatus in_status) {
+ if (!impl_.SetSnapshotMergeStatus(ToHIDLMergeStatus(in_status))) {
+ return ScopedAStatus::fromServiceSpecificErrorWithMessage(COMMAND_FAILED,
+ "Operation failed");
+ }
+ return ScopedAStatus::ok();
+}
+
+} // namespace aidl::android::hardware::boot
diff --git a/boot/aidl/default/BootControl.h b/boot/aidl/default/BootControl.h
new file mode 100644
index 0000000..54cd32d
--- /dev/null
+++ b/boot/aidl/default/BootControl.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/boot/BnBootControl.h>
+#include <libboot_control/libboot_control.h>
+
+namespace aidl::android::hardware::boot {
+
+class BootControl final : public BnBootControl {
+ public:
+ BootControl();
+ ::ndk::ScopedAStatus getActiveBootSlot(int32_t* _aidl_return) override;
+ ::ndk::ScopedAStatus getCurrentSlot(int32_t* _aidl_return) override;
+ ::ndk::ScopedAStatus getNumberSlots(int32_t* _aidl_return) override;
+ ::ndk::ScopedAStatus getSnapshotMergeStatus(
+ ::aidl::android::hardware::boot::MergeStatus* _aidl_return) override;
+ ::ndk::ScopedAStatus getSuffix(int32_t in_slot, std::string* _aidl_return) override;
+ ::ndk::ScopedAStatus isSlotBootable(int32_t in_slot, bool* _aidl_return) override;
+ ::ndk::ScopedAStatus isSlotMarkedSuccessful(int32_t in_slot, bool* _aidl_return) override;
+ ::ndk::ScopedAStatus markBootSuccessful() override;
+ ::ndk::ScopedAStatus setActiveBootSlot(int32_t in_slot) override;
+ ::ndk::ScopedAStatus setSlotAsUnbootable(int32_t in_slot) override;
+ ::ndk::ScopedAStatus setSnapshotMergeStatus(
+ ::aidl::android::hardware::boot::MergeStatus in_status) override;
+
+ private:
+ ::android::bootable::BootControl impl_;
+};
+
+} // namespace aidl::android::hardware::boot
diff --git a/boot/aidl/default/android.hardware.boot-service.default.rc b/boot/aidl/default/android.hardware.boot-service.default.rc
new file mode 100644
index 0000000..589f803
--- /dev/null
+++ b/boot/aidl/default/android.hardware.boot-service.default.rc
@@ -0,0 +1,5 @@
+service vendor.boot-default /vendor/bin/hw/android.hardware.boot-service.default
+ class early_hal
+ user root
+ group root
+
diff --git a/boot/aidl/default/android.hardware.boot-service.default.xml b/boot/aidl/default/android.hardware.boot-service.default.xml
new file mode 100644
index 0000000..23ccc4e
--- /dev/null
+++ b/boot/aidl/default/android.hardware.boot-service.default.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.boot</name>
+ <fqname>IBootControl/default</fqname>
+ </hal>
+</manifest>
diff --git a/boot/aidl/default/android.hardware.boot-service.default_recovery.rc b/boot/aidl/default/android.hardware.boot-service.default_recovery.rc
new file mode 100644
index 0000000..cb08a39
--- /dev/null
+++ b/boot/aidl/default/android.hardware.boot-service.default_recovery.rc
@@ -0,0 +1,7 @@
+service vendor.boot-default /system/bin/hw/android.hardware.boot-service.default_recovery
+ class early_hal
+ user root
+ group root
+ seclabel u:r:hal_bootctl_default:s0
+ interface aidl android.hardware.boot.IBootControl/default
+
diff --git a/boot/aidl/default/main.cpp b/boot/aidl/default/main.cpp
new file mode 100644
index 0000000..70b284e
--- /dev/null
+++ b/boot/aidl/default/main.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BootControl.h"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+using aidl::android::hardware::boot::BootControl;
+using aidl::android::hardware::boot::IBootControl;
+
+int main(int, char* argv[]) {
+ android::base::InitLogging(argv, android::base::KernelLogger);
+ ABinderProcess_setThreadPoolMaxThreadCount(0);
+ std::shared_ptr<IBootControl> service = ndk::SharedRefBase::make<BootControl>();
+
+ const std::string instance = std::string(BootControl::descriptor) + "/default";
+ auto status = AServiceManager_addService(service->asBinder().get(), instance.c_str());
+ CHECK_EQ(status, STATUS_OK) << "Failed to add service " << instance << " " << status;
+ LOG(INFO) << "IBootControl AIDL service running...";
+
+ ABinderProcess_joinThreadPool();
+ return EXIT_FAILURE; // should not reach
+}
diff --git a/boot/aidl/vts/functional/Android.bp b/boot/aidl/vts/functional/Android.bp
new file mode 100644
index 0000000..e46cbef
--- /dev/null
+++ b/boot/aidl/vts/functional/Android.bp
@@ -0,0 +1,41 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ // 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: "VtsHalBootAidlTargetTest",
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "use_libaidlvintf_gtest_helper_static"
+ ],
+ srcs: ["VtsHalBootAidlTargetTest.cpp"],
+ static_libs: [
+ "android.hardware.boot-V1-ndk",
+ ],
+ shared_libs: [
+ "libbinder_ndk",
+ "libvintf",
+ ],
+ test_suites: ["general-tests", "vts"],
+}
diff --git a/boot/aidl/vts/functional/OWNERS b/boot/aidl/vts/functional/OWNERS
new file mode 100644
index 0000000..bc813d8
--- /dev/null
+++ b/boot/aidl/vts/functional/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 30545
+zhangkelvin@google.com
diff --git a/boot/aidl/vts/functional/VtsHalBootAidlTargetTest.cpp b/boot/aidl/vts/functional/VtsHalBootAidlTargetTest.cpp
new file mode 100644
index 0000000..93c8376
--- /dev/null
+++ b/boot/aidl/vts/functional/VtsHalBootAidlTargetTest.cpp
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 <cutils/properties.h>
+
+#include <aidl/android/hardware/boot/IBootControl.h>
+
+#include <aidl/Vintf.h>
+#include <android/binder_manager.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+#include <unordered_set>
+
+using aidl::android::hardware::boot::IBootControl;
+using std::string;
+using std::unordered_set;
+
+// The main test class for the Boot HIDL HAL.
+class BootAidlTest : public ::testing::TestWithParam<std::string> {
+ public:
+ virtual void SetUp() override {
+ const auto instance_name = GetParam();
+ ASSERT_TRUE(AServiceManager_isDeclared(instance_name.c_str()))
+ << " instance " << instance_name << " not declared.";
+ boot = ::aidl::android::hardware::boot::IBootControl::fromBinder(
+ ndk::SpAIBinder(AServiceManager_waitForService(instance_name.c_str())));
+ ASSERT_NE(boot, nullptr);
+ }
+
+ std::shared_ptr<IBootControl> boot;
+};
+
+// validity check Boot::getNumberSlots().
+TEST_P(BootAidlTest, GetNumberSlots) {
+ int32_t slots{};
+ boot->getNumberSlots(&slots);
+ ASSERT_LE(2, slots);
+}
+
+// validity check Boot::getCurrentSlot().
+TEST_P(BootAidlTest, GetCurrentSlot) {
+ int curSlot = -1;
+ boot->getCurrentSlot(&curSlot);
+ int slots = 0;
+ boot->getNumberSlots(&slots);
+ ASSERT_LT(curSlot, slots);
+}
+
+// validity check Boot::markBootSuccessful().
+TEST_P(BootAidlTest, MarkBootSuccessful) {
+ const auto result = boot->markBootSuccessful();
+ ASSERT_TRUE(result.isOk());
+ int curSlot = 0;
+ boot->getCurrentSlot(&curSlot);
+ bool ret = false;
+ boot->isSlotMarkedSuccessful(curSlot, &ret);
+ ASSERT_TRUE(ret);
+}
+
+TEST_P(BootAidlTest, SetActiveBootSlot) {
+ int curSlot = -1;
+ boot->getCurrentSlot(&curSlot);
+ ASSERT_GE(curSlot, 0);
+ int otherSlot = curSlot ? 0 : 1;
+ bool otherBootable = true;
+ boot->isSlotBootable(otherSlot, &otherBootable);
+
+ for (int s = 0; s < 2; s++) {
+ const auto result = boot->setActiveBootSlot(s);
+ ASSERT_TRUE(result.isOk());
+ }
+ {
+ // Restore original flags to avoid problems on reboot
+ auto result = boot->setActiveBootSlot(curSlot);
+ ASSERT_TRUE(result.isOk());
+
+ if (!otherBootable) {
+ const auto result = boot->setSlotAsUnbootable(otherSlot);
+ ASSERT_TRUE(result.isOk());
+ }
+
+ result = boot->markBootSuccessful();
+ ASSERT_TRUE(result.isOk());
+ }
+ {
+ int slots = 0;
+ boot->getNumberSlots(&slots);
+ const auto result = boot->setActiveBootSlot(slots);
+ ASSERT_FALSE(result.isOk()) << "setActiveBootSlot on invalid slot should fail";
+ }
+}
+
+TEST_P(BootAidlTest, SetSlotAsUnbootable) {
+ int curSlot = -1;
+ boot->getCurrentSlot(&curSlot);
+ ASSERT_GE(curSlot, 0);
+ int otherSlot = curSlot ? 0 : 1;
+ bool otherBootable = false;
+ boot->isSlotBootable(otherSlot, &otherBootable);
+ {
+ auto result = boot->setSlotAsUnbootable(otherSlot);
+ ASSERT_TRUE(result.isOk());
+ boot->isSlotBootable(otherSlot, &otherBootable);
+ ASSERT_FALSE(otherBootable);
+
+ // Restore original flags to avoid problems on reboot
+ if (otherBootable) {
+ result = boot->setActiveBootSlot(otherSlot);
+ ASSERT_TRUE(result.isOk());
+ }
+ result = boot->setActiveBootSlot(curSlot);
+ ASSERT_TRUE(result.isOk());
+ result = boot->markBootSuccessful();
+ ASSERT_TRUE(result.isOk());
+ }
+ {
+ int32_t slots = 0;
+ boot->getNumberSlots(&slots);
+ const auto result = boot->setSlotAsUnbootable(slots);
+ ASSERT_FALSE(result.isOk());
+ }
+}
+
+// validity check Boot::isSlotBootable() on good and bad inputs.
+TEST_P(BootAidlTest, IsSlotBootable) {
+ for (int s = 0; s < 2; s++) {
+ bool bootable = false;
+ const auto res = boot->isSlotBootable(s, &bootable);
+ ASSERT_TRUE(res.isOk()) << res.getMessage();
+ }
+ int32_t slots = 0;
+ boot->getNumberSlots(&slots);
+ bool bootable = false;
+ const auto res = boot->isSlotBootable(slots, &bootable);
+ ASSERT_FALSE(res.isOk());
+}
+
+// validity check Boot::isSlotMarkedSuccessful() on good and bad inputs.
+TEST_P(BootAidlTest, IsSlotMarkedSuccessful) {
+ for (int32_t s = 0; s < 2; s++) {
+ bool isSuccess = false;
+ const auto res = boot->isSlotMarkedSuccessful(s, &isSuccess);
+ }
+ int32_t slots = 0;
+ boot->getNumberSlots(&slots);
+ bool isSuccess = false;
+ const auto res = boot->isSlotMarkedSuccessful(slots, &isSuccess);
+ ASSERT_FALSE(res.isOk());
+}
+
+// validity check Boot::getSuffix() on good and bad inputs.
+TEST_P(BootAidlTest, GetSuffix) {
+ string suffixStr;
+ unordered_set<string> suffixes;
+ int numSlots = 0;
+ boot->getNumberSlots(&numSlots);
+ for (int32_t i = 0; i < numSlots; i++) {
+ std::string suffix;
+ const auto result = boot->getSuffix(i, &suffixStr);
+ ASSERT_TRUE(result.isOk());
+ ASSERT_EQ('_', suffixStr[0]);
+ ASSERT_LE((unsigned)2, suffixStr.size());
+ suffixes.insert(suffixStr);
+ }
+ // All suffixes should be unique
+ ASSERT_EQ(numSlots, suffixes.size());
+ {
+ const string emptySuffix = "";
+ const auto result = boot->getSuffix(numSlots, &suffixStr);
+ ASSERT_TRUE(result.isOk());
+ ASSERT_EQ(suffixStr, emptySuffix);
+ }
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, BootAidlTest,
+ testing::ValuesIn(android::getAidlHalInstanceNames(IBootControl::descriptor)));
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BootAidlTest);
diff --git a/broadcastradio/1.0/default/OWNERS b/broadcastradio/1.0/default/OWNERS
index 57e6592..302fdd7 100644
--- a/broadcastradio/1.0/default/OWNERS
+++ b/broadcastradio/1.0/default/OWNERS
@@ -1,3 +1,4 @@
-elaurent@google.com
-mnaganov@google.com
-twasilczyk@google.com
+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
index 778c4a2..aa19d6a 100644
--- a/broadcastradio/1.0/vts/functional/OWNERS
+++ b/broadcastradio/1.0/vts/functional/OWNERS
@@ -1,2 +1,5 @@
# 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
index 136b607..259b91e 100644
--- a/broadcastradio/1.1/default/OWNERS
+++ b/broadcastradio/1.1/default/OWNERS
@@ -1,3 +1,5 @@
# Automotive team
-egranata@google.com
-twasilczyk@google.com
+xuweilin@google.com
+oscarazu@google.com
+ericjeong@google.com
+keunyoung@google.com
diff --git a/broadcastradio/1.1/vts/OWNERS b/broadcastradio/1.1/vts/OWNERS
index 2c21c25..aa19d6a 100644
--- a/broadcastradio/1.1/vts/OWNERS
+++ b/broadcastradio/1.1/vts/OWNERS
@@ -1,3 +1,5 @@
# Bug component: 533946
+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
index 136b607..259b91e 100644
--- a/broadcastradio/2.0/default/OWNERS
+++ b/broadcastradio/2.0/default/OWNERS
@@ -1,3 +1,5 @@
# Automotive team
-egranata@google.com
-twasilczyk@google.com
+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
index 1ff7407..09690ef 100644
--- a/broadcastradio/2.0/vts/OWNERS
+++ b/broadcastradio/2.0/vts/OWNERS
@@ -1,6 +1,8 @@
# Automotive team
-egranata@google.com
-twasilczyk@google.com
+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
index 2c21c25..aa19d6a 100644
--- a/broadcastradio/2.0/vts/functional/OWNERS
+++ b/broadcastradio/2.0/vts/functional/OWNERS
@@ -1,3 +1,5 @@
# Bug component: 533946
+xuweilin@google.com
oscarazu@google.com
+ericjeong@google.com
keunyoung@google.com
diff --git a/broadcastradio/common/OWNERS b/broadcastradio/common/OWNERS
index 136b607..259b91e 100644
--- a/broadcastradio/common/OWNERS
+++ b/broadcastradio/common/OWNERS
@@ -1,3 +1,5 @@
# Automotive team
-egranata@google.com
-twasilczyk@google.com
+xuweilin@google.com
+oscarazu@google.com
+ericjeong@google.com
+keunyoung@google.com
diff --git a/camera/README.md b/camera/README.md
index 8ce3352..25badfd 100644
--- a/camera/README.md
+++ b/camera/README.md
@@ -10,3 +10,8 @@
More complete information about the Android camera HAL and subsystem can be found at
[source.android.com](http://source.android.com/devices/camera/index.html).
+
+### AIDL Camera HAL Interfaces
+
+The AIDL Camera HAL interfaces can be found in the respective <interface>/aidl
+directories.
diff --git a/camera/common/aidl/Android.bp b/camera/common/aidl/Android.bp
index 19de22d..d21ae58 100644
--- a/camera/common/aidl/Android.bp
+++ b/camera/common/aidl/Android.bp
@@ -19,11 +19,6 @@
java: {
enabled: false,
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
versions_with_info: [
{
diff --git a/camera/device/aidl/Android.bp b/camera/device/aidl/Android.bp
index afc6b8d..365a5ff 100644
--- a/camera/device/aidl/Android.bp
+++ b/camera/device/aidl/Android.bp
@@ -27,11 +27,6 @@
sdk_version: "module_current",
enabled: false,
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
versions_with_info: [
{
diff --git a/camera/device/aidl/android/hardware/camera/device/StreamBuffer.aidl b/camera/device/aidl/android/hardware/camera/device/StreamBuffer.aidl
index e487494..29fec68 100644
--- a/camera/device/aidl/android/hardware/camera/device/StreamBuffer.aidl
+++ b/camera/device/aidl/android/hardware/camera/device/StreamBuffer.aidl
@@ -33,8 +33,8 @@
parcelable StreamBuffer {
/**
* The ID of the stream this buffer is associated with. -1 indicates an
- * invalid (empty) StreamBuffer, in which case buffer must also point to
- * null and bufferId must be 0.
+ * invalid (empty) StreamBuffer, in which case buffer must be empty
+ * and bufferId must be 0.
*/
int streamId;
@@ -48,7 +48,7 @@
* corresponding stream is removed from stream configuration or until camera
* device session is closed. After the first time a buffer is introduced to
* HAL, in the future camera service must refer to the same buffer using
- * only bufferId, and keep the buffer handle null.
+ * only bufferId, and keep the buffer handle empty.
*/
long bufferId;
@@ -59,10 +59,10 @@
* is not seen by the HAL before, this buffer handle is guaranteed to be a
* valid handle to a graphics buffer, with dimensions and format matching
* that of the stream. If the bufferId has been sent to the HAL before, this
- * buffer handle must be null and HAL must look up the actual buffer handle
+ * buffer handle must be empty and HAL must look up the actual buffer handle
* to use from its own bufferId to buffer handle map.
*
- * For StreamBuffers returned in a CaptureResult, this must be null, since
+ * For StreamBuffers returned in a CaptureResult, this must be empty, since
* the handle to the buffer is already known to the client (since the client
* sent it in the matching CaptureRequest), and the handle can be identified
* by the combination of frame number and stream ID.
@@ -81,11 +81,11 @@
* The acquire sync fence for this buffer. The HAL must wait on this fence
* fd before attempting to read from or write to this buffer.
*
- * In a buffer included in a CaptureRequest, the client may set this to null
+ * In a buffer included in a CaptureRequest, the client may leave this empty
* to indicate that no waiting is necessary for this buffer.
*
* When the HAL returns an input or output buffer to the framework with
- * processCaptureResult(), the acquireFence must be set to null. If the HAL
+ * processCaptureResult(), the acquireFence must be empty. If the HAL
* never waits on the acquireFence due to an error in filling or reading a
* buffer, when calling processCaptureResult() the HAL must set the
* releaseFence of the buffer to be the acquireFence passed to it by the
@@ -97,17 +97,17 @@
/**
* The release sync fence for this buffer. The HAL must set this to a valid
* fence fd when returning the input buffer or output buffers to the client
- * in a CaptureResult, or set it to null to indicate that no waiting is
+ * in a CaptureResult, or leave it empty to indicate that no waiting is
* required for this buffer.
*
- * The client must set this to be null for all buffers included in a
+ * The client must leave this empty for all buffers included in a
* processCaptureRequest call.
*
* After signaling the releaseFence for this buffer, the HAL
* must not make any further attempts to access this buffer as the
* ownership has been fully transferred back to the client.
*
- * If this is null, then the ownership of this buffer is transferred back
+ * If this is empty, then the ownership of the buffer is transferred back
* immediately upon the call of processCaptureResult.
*/
NativeHandle releaseFence;
diff --git a/camera/metadata/aidl/Android.bp b/camera/metadata/aidl/Android.bp
index 31d4b4d..301a943 100644
--- a/camera/metadata/aidl/Android.bp
+++ b/camera/metadata/aidl/Android.bp
@@ -19,11 +19,6 @@
java: {
enabled: false,
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
versions_with_info: [
{
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index 6866776..b0ae20e 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -7883,6 +7883,7 @@
}
}
+ camera_metadata_t* staticMetadata;
camera_metadata_ro_entry physicalMultiResStreamConfigs;
camera_metadata_ro_entry physicalStreamConfigs;
camera_metadata_ro_entry physicalMaxResolutionStreamConfigs;
@@ -7901,8 +7902,9 @@
ret = subDevice->getCameraCharacteristics([&](auto status, const auto& chars) {
ASSERT_EQ(Status::OK, status);
- const camera_metadata_t* staticMetadata =
- reinterpret_cast<const camera_metadata_t*>(chars.data());
+ staticMetadata = clone_camera_metadata(
+ reinterpret_cast<const camera_metadata_t*>(chars.data()));
+ ASSERT_NE(nullptr, staticMetadata);
rc = getSystemCameraKind(staticMetadata, &physSystemCameraKind);
ASSERT_EQ(rc, Status::OK);
// Make sure that the system camera kind of a non-hidden
@@ -7936,7 +7938,9 @@
verifyCameraCharacteristics(status, chars);
verifyMonochromeCharacteristics(chars, deviceVersion);
- auto staticMetadata = (const camera_metadata_t*)chars.data();
+ staticMetadata = clone_camera_metadata(
+ reinterpret_cast<const camera_metadata_t*>(chars.data()));
+ ASSERT_NE(nullptr, staticMetadata);
retcode = find_camera_metadata_ro_entry(
staticMetadata, ANDROID_CONTROL_ZOOM_RATIO_RANGE, &entry);
bool subCameraHasZoomRatioRange = (0 == retcode && entry.count == 2);
@@ -8064,6 +8068,7 @@
}
}
}
+ free_camera_metadata(staticMetadata);
}
// If a multi-resolution stream is supported, there must be at least one
diff --git a/camera/provider/README.md b/camera/provider/README.md
index 0718fb1..7666a58 100644
--- a/camera/provider/README.md
+++ b/camera/provider/README.md
@@ -35,3 +35,9 @@
First HIDL version of the camara provider HAL callback interface, closely
matching the feature set and operation of the pre-HIDL camera HAL module
callbacks v2.4.
+
+### AIDL Camera HAL Default Implementation ###
+
+The default implementation can be found at
+$ANDROID_BUILD_TOP/hardware/google/camera/common/hal/aidl_service and
+$ANDROID_BUILD_TOP/hardware/google/camera/devices/EmulatedCamera
diff --git a/camera/provider/aidl/Android.bp b/camera/provider/aidl/Android.bp
index f082bce..87a94b2 100644
--- a/camera/provider/aidl/Android.bp
+++ b/camera/provider/aidl/Android.bp
@@ -25,11 +25,6 @@
cpp: {
enabled: false,
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
versions_with_info: [
{
diff --git a/camera/provider/aidl/vts/camera_aidl_test.cpp b/camera/provider/aidl/vts/camera_aidl_test.cpp
index 20f32bf..2c2f1b2 100644
--- a/camera/provider/aidl/vts/camera_aidl_test.cpp
+++ b/camera/provider/aidl/vts/camera_aidl_test.cpp
@@ -1181,6 +1181,7 @@
camera_metadata_ro_entry physicalMultiResStreamConfigs;
camera_metadata_ro_entry physicalStreamConfigs;
camera_metadata_ro_entry physicalMaxResolutionStreamConfigs;
+ CameraMetadata physChars;
bool isUltraHighRes = false;
std::unordered_set<int32_t> subCameraPrivacyTestPatterns;
if (isPublicId) {
@@ -1189,12 +1190,11 @@
ASSERT_TRUE(ret.isOk());
ASSERT_NE(subDevice, nullptr);
- CameraMetadata subDeviceChars;
- ret = subDevice->getCameraCharacteristics(&subDeviceChars);
+ ret = subDevice->getCameraCharacteristics(&physChars);
ASSERT_TRUE(ret.isOk());
const camera_metadata_t* staticMetadata =
- reinterpret_cast<const camera_metadata_t*>(subDeviceChars.metadata.data());
+ reinterpret_cast<const camera_metadata_t*>(physChars.metadata.data());
retStatus = getSystemCameraKind(staticMetadata, &physSystemCameraKind);
ASSERT_EQ(retStatus, Status::OK);
@@ -1215,7 +1215,6 @@
getPrivacyTestPatternModes(staticMetadata, &subCameraPrivacyTestPatterns);
} else {
// Check camera characteristics for hidden camera id
- CameraMetadata physChars;
ndk::ScopedAStatus ret =
device->getPhysicalCameraCharacteristics(physicalId, &physChars);
ASSERT_TRUE(ret.isOk());
diff --git a/cas/aidl/Android.bp b/cas/aidl/Android.bp
new file mode 100644
index 0000000..32f12b1
--- /dev/null
+++ b/cas/aidl/Android.bp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+aidl_interface {
+ name: "android.hardware.cas",
+ vendor_available: true,
+ srcs: ["android/hardware/cas/*.aidl"],
+ stability: "vintf",
+ imports: ["android.hardware.common-V2"],
+ backend: {
+ cpp: {
+ enabled: false,
+ },
+ java: {
+ sdk_version: "module_current",
+ },
+ },
+}
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/AidlCasPluginDescriptor.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/AidlCasPluginDescriptor.aidl
new file mode 100644
index 0000000..7b8099f
--- /dev/null
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/AidlCasPluginDescriptor.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.cas;
+@VintfStability
+parcelable AidlCasPluginDescriptor {
+ int caSystemId;
+ String name;
+}
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/DestinationBuffer.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/DestinationBuffer.aidl
new file mode 100644
index 0000000..dd355af
--- /dev/null
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/DestinationBuffer.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.cas;
+@VintfStability
+union DestinationBuffer {
+ android.hardware.cas.SharedBuffer nonsecureMemory;
+ android.hardware.common.NativeHandle secureMemory;
+}
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ICas.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ICas.aidl
new file mode 100644
index 0000000..e169beb
--- /dev/null
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ICas.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.cas;
+@VintfStability
+interface ICas {
+ void closeSession(in byte[] sessionId);
+ byte[] openSession(in android.hardware.cas.SessionIntent intent, in android.hardware.cas.ScramblingMode mode);
+ void processEcm(in byte[] sessionId, in byte[] ecm);
+ void processEmm(in byte[] emm);
+ void provision(in String provisionString);
+ void refreshEntitlements(in int refreshType, in byte[] refreshData);
+ void release();
+ void sendEvent(in int event, in int arg, in byte[] eventData);
+ void sendSessionEvent(in byte[] sessionId, in int event, in int arg, in byte[] eventData);
+ void setPrivateData(in byte[] pvtData);
+ void setSessionPrivateData(in byte[] sessionId, in byte[] pvtData);
+}
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ICasListener.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ICasListener.aidl
new file mode 100644
index 0000000..ebc13ce
--- /dev/null
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ICasListener.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.cas;
+@VintfStability
+interface ICasListener {
+ void onEvent(in int event, in int arg, in byte[] data);
+ void onSessionEvent(in byte[] sessionId, in int event, in int arg, in byte[] data);
+ void onStatusUpdate(in android.hardware.cas.StatusEvent event, in int number);
+}
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/IDescrambler.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/IDescrambler.aidl
new file mode 100644
index 0000000..9bf7903
--- /dev/null
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/IDescrambler.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.cas;
+@VintfStability
+interface IDescrambler {
+ int descramble(in android.hardware.cas.ScramblingControl scramblingControl, in android.hardware.cas.SubSample[] subSamples, in android.hardware.cas.SharedBuffer srcBuffer, in long srcOffset, in android.hardware.cas.DestinationBuffer dstBuffer, in long dstOffset);
+ void release();
+ boolean requiresSecureDecoderComponent(in String mime);
+ void setMediaCasSession(in byte[] sessionId);
+}
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/IMediaCasService.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/IMediaCasService.aidl
new file mode 100644
index 0000000..f5c8018
--- /dev/null
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/IMediaCasService.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.cas;
+@VintfStability
+interface IMediaCasService {
+ android.hardware.cas.IDescrambler createDescrambler(in int CA_system_id);
+ android.hardware.cas.ICas createPlugin(in int CA_system_id, in android.hardware.cas.ICasListener listener);
+ android.hardware.cas.AidlCasPluginDescriptor[] enumeratePlugins();
+ boolean isDescramblerSupported(in int CA_system_id);
+ boolean isSystemIdSupported(in int CA_system_id);
+}
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ScramblingControl.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ScramblingControl.aidl
new file mode 100644
index 0000000..d71d4be
--- /dev/null
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ScramblingControl.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.cas;
+@Backing(type="int") @VintfStability
+enum ScramblingControl {
+ UNSCRAMBLED = 0,
+ RESERVED = 1,
+ EVENKEY = 2,
+ ODDKEY = 3,
+}
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ScramblingMode.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ScramblingMode.aidl
new file mode 100644
index 0000000..e3923c7
--- /dev/null
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ScramblingMode.aidl
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.cas;
+@Backing(type="int") @VintfStability
+enum ScramblingMode {
+ RESERVED = 0,
+ DVB_CSA1 = 1,
+ DVB_CSA2 = 2,
+ DVB_CSA3_STANDARD = 3,
+ DVB_CSA3_MINIMAL = 4,
+ DVB_CSA3_ENHANCE = 5,
+ DVB_CISSA_V1 = 6,
+ DVB_IDSA = 7,
+ MULTI2 = 8,
+ AES128 = 9,
+ AES_CBC = 10,
+ AES_ECB = 11,
+ AES_SCTE52 = 12,
+ TDES_ECB = 13,
+ TDES_SCTE52 = 14,
+}
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SessionIntent.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SessionIntent.aidl
new file mode 100644
index 0000000..af95f80
--- /dev/null
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SessionIntent.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.cas;
+@Backing(type="int") @VintfStability
+enum SessionIntent {
+ LIVE = 0,
+ PLAYBACK = 1,
+ RECORD = 2,
+ TIMESHIFT = 3,
+}
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SharedBuffer.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SharedBuffer.aidl
new file mode 100644
index 0000000..a18aa57
--- /dev/null
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SharedBuffer.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.cas;
+@VintfStability
+parcelable SharedBuffer {
+ android.hardware.common.Ashmem heapBase;
+ long offset;
+ long size;
+}
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/Status.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/Status.aidl
new file mode 100644
index 0000000..3d3a8a0
--- /dev/null
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/Status.aidl
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.cas;
+@VintfStability
+parcelable Status {
+ const int OK = 0;
+ const int ERROR_CAS_NO_LICENSE = -1;
+ const int ERROR_CAS_LICENSE_EXPIRED = -2;
+ const int ERROR_CAS_SESSION_NOT_OPENED = -3;
+ const int ERROR_CAS_CANNOT_HANDLE = -4;
+ const int ERROR_CAS_INVALID_STATE = -5;
+ const int BAD_VALUE = -6;
+ const int ERROR_CAS_NOT_PROVISIONED = -7;
+ const int ERROR_CAS_RESOURCE_BUSY = -8;
+ const int ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION = -9;
+ const int ERROR_CAS_TAMPER_DETECTED = -10;
+ const int ERROR_CAS_DEVICE_REVOKED = -11;
+ const int ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED = -12;
+ const int ERROR_CAS_DECRYPT = -13;
+ const int ERROR_CAS_UNKNOWN = -14;
+ const int ERROR_CAS_NEED_ACTIVATION = -15;
+ const int ERROR_CAS_NEED_PAIRING = -16;
+ const int ERROR_CAS_NO_CARD = -17;
+ const int ERROR_CAS_CARD_MUTE = -18;
+ const int ERROR_CAS_CARD_INVALID = -19;
+ const int ERROR_CAS_BLACKOUT = -20;
+ const int ERROR_CAS_REBOOTING = -21;
+}
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/StatusEvent.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/StatusEvent.aidl
new file mode 100644
index 0000000..178cabc
--- /dev/null
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/StatusEvent.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.cas;
+@Backing(type="byte") @VintfStability
+enum StatusEvent {
+ PLUGIN_PHYSICAL_MODULE_CHANGED = 0,
+ PLUGIN_SESSION_NUMBER_CHANGED = 1,
+}
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SubSample.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SubSample.aidl
new file mode 100644
index 0000000..d9ee3b4
--- /dev/null
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SubSample.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.cas;
+@VintfStability
+parcelable SubSample {
+ int numBytesOfClearData;
+ int numBytesOfEncryptedData;
+}
diff --git a/cas/aidl/android/hardware/cas/AidlCasPluginDescriptor.aidl b/cas/aidl/android/hardware/cas/AidlCasPluginDescriptor.aidl
new file mode 100644
index 0000000..55b328a
--- /dev/null
+++ b/cas/aidl/android/hardware/cas/AidlCasPluginDescriptor.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.cas;
+
+/**
+ * Describes a CAS plugin with its system ID and name.
+ */
+@VintfStability
+parcelable AidlCasPluginDescriptor {
+ int caSystemId;
+ String name;
+}
diff --git a/cas/aidl/android/hardware/cas/DestinationBuffer.aidl b/cas/aidl/android/hardware/cas/DestinationBuffer.aidl
new file mode 100644
index 0000000..068f29d
--- /dev/null
+++ b/cas/aidl/android/hardware/cas/DestinationBuffer.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.cas;
+
+import android.hardware.cas.SharedBuffer;
+import android.hardware.common.NativeHandle;
+
+@VintfStability
+union DestinationBuffer {
+ /**
+ * If type == SHARED_MEMORY, the descrambled data must be written
+ * to user-space non-secure shared memory.
+ */
+ SharedBuffer nonsecureMemory;
+
+ /**
+ * If type == NATIVE_HANDLE, the descrambled data must be written
+ * to secure memory referenced by the vendor's buffer allocator.
+ */
+ NativeHandle secureMemory;
+}
diff --git a/cas/aidl/android/hardware/cas/ICas.aidl b/cas/aidl/android/hardware/cas/ICas.aidl
new file mode 100644
index 0000000..4c938c7
--- /dev/null
+++ b/cas/aidl/android/hardware/cas/ICas.aidl
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.cas;
+
+import android.hardware.cas.ScramblingMode;
+import android.hardware.cas.SessionIntent;
+
+/**
+ * ICas is the API to control the CAS. It is used to manage sessions, provision/refresh the cas
+ * system, and process the EMM/ECM messages. It also allows bi-directional, scheme-specific
+ * communications between the client and the cas system.
+ */
+@VintfStability
+interface ICas {
+ /**
+ * Close a session.
+ *
+ * @param sessionId The id of the session to be closed.
+ */
+ void closeSession(in byte[] sessionId);
+
+ /**
+ * Open a session to descramble one or more streams by specifying intention
+ * and scrambling mode.
+ *
+ * @param intent the intention of the session to be opened.
+ * @param mode the scrambling mode the session will use.
+ *
+ * @return sessionId The id of the newly opened session.
+ */
+ byte[] openSession(in SessionIntent intent, in ScramblingMode mode);
+
+ /**
+ * Process an ECM from the ECM stream for this session’s elementary stream.
+ *
+ * @param sessionId the id of the session which the ecm data applies to.
+ * @param ecm a byte array containing the ecm data.
+ */
+ void processEcm(in byte[] sessionId, in byte[] ecm);
+
+ /**
+ * Process an in-band EMM from the EMM stream.
+ *
+ * @param emm a byte array containing the emm data.
+ */
+ void processEmm(in byte[] emm);
+
+ /**
+ * Initiate a provisioning operation for a CA system.
+ *
+ * @param provisionString string containing information needed for the
+ * provisioning operation, the format of which is scheme and implementation
+ * specific.
+ */
+ void provision(in String provisionString);
+
+ /**
+ * Notify the CA system to refresh entitlement keys.
+ *
+ * @param refreshType the type of the refreshment.
+ * @param refreshData private data associated with the refreshment.
+ */
+ void refreshEntitlements(in int refreshType, in byte[] refreshData);
+
+ /**
+ * Release the descrambler instance.
+ */
+ void release();
+
+ /**
+ * Send an scheme-specific event to the CasPlugin.
+ *
+ * @param event an integer denoting a scheme-specific event to be sent.
+ * @param arg a scheme-specific integer argument for the event.
+ * @param data a byte array containing scheme-specific data for the event.
+ */
+ void sendEvent(in int event, in int arg, in byte[] eventData);
+
+ /**
+ * Send an scheme-specific session event to the CasPlugin.
+ *
+ * @param sessionId the id of an opened session.
+ * @param event an integer denoting a scheme-specific event to be sent.
+ * @param arg a scheme-specific integer argument for the event.
+ * @param data a byte array containing scheme-specific data for the event.
+ */
+ void sendSessionEvent(in byte[] sessionId, in int event, in int arg, in byte[] eventData);
+
+ /**
+ * Provide the CA private data from a CA_descriptor in the conditional
+ * access table to a CasPlugin.
+ *
+ * @param pvtData a byte array containing the private data, the format of
+ * which is scheme-specific and opaque to the framework.
+ */
+ void setPrivateData(in byte[] pvtData);
+
+ /**
+ * Provide the CA private data from a CA_descriptor in the program map
+ * table to a session.
+ *
+ * @param sessionId the id of the session which the private data applies to.
+ * @param pvtData a byte array containing the private data, the format of
+ * which is scheme-specific and opaque to the framework.
+ */
+ void setSessionPrivateData(in byte[] sessionId, in byte[] pvtData);
+}
diff --git a/cas/aidl/android/hardware/cas/ICasListener.aidl b/cas/aidl/android/hardware/cas/ICasListener.aidl
new file mode 100644
index 0000000..32d843f
--- /dev/null
+++ b/cas/aidl/android/hardware/cas/ICasListener.aidl
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.cas;
+
+import android.hardware.cas.StatusEvent;
+
+@VintfStability
+interface ICasListener {
+ /**
+ * Notify the listener of a scheme-specific event from the CA system.
+ *
+ * @param event an integer whose meaning is scheme-specific.
+ * @param arg an integer whose meaning is scheme-specific.
+ * @param data a byte array of data whose format and meaning are
+ * scheme-specific.
+ */
+ void onEvent(in int event, in int arg, in byte[] data);
+
+ /**
+ * Notify the listener of a scheme-specific session event from CA system.
+ *
+ * @param sessionId the id of an opened session.
+ * @param event an integer whose meaning is scheme-specific.
+ * @param arg an integer whose meaning is scheme-specific.
+ * @param data a byte array of data whose format and meaning are
+ * scheme-specific.
+ */
+ void onSessionEvent(in byte[] sessionId, in int event, in int arg, in byte[] data);
+
+ /**
+ * Notify the listener that the status of CAS system has changed.
+ *
+ * @param event the event type of status change.
+ * @param number value for status event.
+ * For PLUGIN_PHYSICAL_MODULE_CHANGED event:
+ * the positive number presents how many plugins are inserted;
+ * the negative number presents how many plugins are removed.
+ * Client must enumerate plugins after receive the event.
+ * For PLUGIN_SESSION_NUMBER_CHANGED event:
+ * the number presents how many sessions are supported
+ * in the plugin.
+ */
+ void onStatusUpdate(in StatusEvent event, in int number);
+}
diff --git a/cas/aidl/android/hardware/cas/IDescrambler.aidl b/cas/aidl/android/hardware/cas/IDescrambler.aidl
new file mode 100644
index 0000000..33fbe75
--- /dev/null
+++ b/cas/aidl/android/hardware/cas/IDescrambler.aidl
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.cas;
+
+import android.hardware.cas.DestinationBuffer;
+import android.hardware.cas.ScramblingControl;
+import android.hardware.cas.SharedBuffer;
+import android.hardware.cas.SubSample;
+
+/**
+ * IDescrambler is the API to control the descrambling operations.
+ */
+@VintfStability
+interface IDescrambler {
+ /**
+ * Descramble the data in a source SharedBuffer, described by an array of
+ * SubSample structures.
+ *
+ * @param scramblingControl an enumeration indicating the key that the subsamples
+ * were scrambled with.
+ * @param subSamples an array of SubSample structures describing the number of
+ * clear and scrambled bytes within each subsample.
+ * @param srcBuffer the SharedBuffer containing the source scrambled data.
+ * @param srcOffset the position where the source scrambled data starts at.
+ * @param dstBuffer the DestinationBuffer to hold the descrambled data.
+ * @param dstOffset the position where the descrambled data should start at.
+ *
+ * @return bytesWritten Number of bytes that have been successfully written.
+ */
+ int descramble(in ScramblingControl scramblingControl, in SubSample[] subSamples,
+ in SharedBuffer srcBuffer, in long srcOffset, in DestinationBuffer dstBuffer,
+ in long dstOffset);
+
+ /**
+ * Release the descrambler instance.
+ */
+ void release();
+
+ /**
+ * Query if the scrambling scheme requires the use of a secure decoder
+ * to decode data of the given mime type.
+ *
+ * @param mime the mime type of the media data.
+ * @return whether the descrambler requires a secure decoder.
+ */
+ boolean requiresSecureDecoderComponent(in String mime);
+
+ /**
+ * Associate a MediaCas session with this MediaDescrambler instance.
+ *
+ * @param sessionId the id of the session to associate with this descrambler instance.
+ */
+ void setMediaCasSession(in byte[] sessionId);
+}
diff --git a/cas/aidl/android/hardware/cas/IMediaCasService.aidl b/cas/aidl/android/hardware/cas/IMediaCasService.aidl
new file mode 100644
index 0000000..8bc31f6
--- /dev/null
+++ b/cas/aidl/android/hardware/cas/IMediaCasService.aidl
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.cas;
+
+import android.hardware.cas.AidlCasPluginDescriptor;
+import android.hardware.cas.ICas;
+import android.hardware.cas.ICasListener;
+import android.hardware.cas.IDescrambler;
+
+/**
+ * IMediaCasService is the main entry point for interacting with a vendor's
+ * cas HAL to create cas and descrambler plugin instances. A cas plugin instance
+ * opens cas sessions which are used to obtain keys for a descrambler session,
+ * which can in turn be used to descramble protected video content.
+ */
+@VintfStability
+interface IMediaCasService {
+ /**
+ * Construct a new instance of a DescramblerPlugin given a CA_system_id.
+ *
+ * @param CA_system_id the id of the CA system.
+ * @return the newly created plugin interface.
+ */
+ IDescrambler createDescrambler(in int CA_system_id);
+
+ /**
+ * Construct a new instance of a CasPlugin given a CA_system_id.
+ *
+ * @param CA_system_id the id of the CA system.
+ * @param listener the event listener to receive events coming from the CasPlugin.
+ * @return the newly created CasPlugin interface.
+ */
+ ICas createPlugin(in int CA_system_id, in ICasListener listener);
+
+ /**
+ * List all available CA systems on the device.
+ *
+ * @return an array of descriptors for the available CA systems.
+ */
+ AidlCasPluginDescriptor[] enumeratePlugins();
+
+ /**
+ * Query if the descrambling scheme for a CA system is supported on this device.
+ *
+ * @param CA_system_id the id of the CA system.
+ * @return whether the specified descrambling scheme is supported on this device.
+ */
+ boolean isDescramblerSupported(in int CA_system_id);
+
+ /**
+ * Query if a certain CA system is supported on this device.
+ *
+ * @param CA_system_id the id of the CA system.
+ * @return whether the specified CA system is supported on this device.
+ */
+ boolean isSystemIdSupported(in int CA_system_id);
+}
diff --git a/cas/aidl/android/hardware/cas/ScramblingControl.aidl b/cas/aidl/android/hardware/cas/ScramblingControl.aidl
new file mode 100644
index 0000000..b36787c
--- /dev/null
+++ b/cas/aidl/android/hardware/cas/ScramblingControl.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.cas;
+
+/**
+ * Enumerates the keys used to scramble the content.
+ */
+@VintfStability
+@Backing(type="int")
+enum ScramblingControl {
+ UNSCRAMBLED = 0,
+ RESERVED = 1,
+ EVENKEY = 2,
+ ODDKEY = 3,
+}
diff --git a/cas/aidl/android/hardware/cas/ScramblingMode.aidl b/cas/aidl/android/hardware/cas/ScramblingMode.aidl
new file mode 100644
index 0000000..9d73eba
--- /dev/null
+++ b/cas/aidl/android/hardware/cas/ScramblingMode.aidl
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.cas;
+
+/**
+ * The Scrambling Mode.
+ */
+@VintfStability
+@Backing(type="int")
+enum ScramblingMode {
+ RESERVED = 0,
+
+ /**
+ * DVB (Digital Video Broadcasting) CSA1 (Common Scrambling Algorithm 1) is
+ * the default mode and shall be used when the scrambling descriptor
+ * is not present in the program map section. DVB scrambling mode is
+ * specified in ETSI EN 300 468 specification.
+ */
+ DVB_CSA1,
+
+ DVB_CSA2,
+
+ /**
+ * DVB-CSA3 in standard mode.
+ */
+ DVB_CSA3_STANDARD,
+
+ /**
+ * DVB-CSA3 in minimally enhanced mode.
+ */
+ DVB_CSA3_MINIMAL,
+
+ /**
+ * DVB-CSA3 in fully enhanced mode.
+ */
+ DVB_CSA3_ENHANCE,
+
+ /**
+ * DVB-CISSA version 1.
+ */
+ DVB_CISSA_V1,
+
+ /**
+ * ATIS-0800006 IIF Default Scrambling Algorithm (IDSA).
+ */
+ DVB_IDSA,
+
+ /**
+ * a symmetric key algorithm.
+ */
+ MULTI2,
+
+ /**
+ * Advanced Encryption System (AES) 128-bit Encryption mode.
+ */
+ AES128,
+
+ /**
+ * Advanced Encryption System (AES) Cipher Block Chaining (CBC) mode.
+ */
+ AES_CBC,
+
+ /**
+ * Advanced Encryption System (AES) Electronic Code Book (ECB) mode.
+ */
+ AES_ECB,
+
+ /**
+ * Advanced Encryption System (AES) Society of Cable Telecommunications
+ * Engineers (SCTE) 52 mode.
+ */
+ AES_SCTE52,
+
+ /**
+ * Triple Data Encryption Algorithm (TDES) Electronic Code Book (ECB) mode.
+ */
+ TDES_ECB,
+
+ /**
+ * Triple Data Encryption Algorithm (TDES) Society of Cable Telecommunications
+ * Engineers (SCTE) 52 mode.
+ */
+ TDES_SCTE52,
+}
diff --git a/cas/aidl/android/hardware/cas/SessionIntent.aidl b/cas/aidl/android/hardware/cas/SessionIntent.aidl
new file mode 100644
index 0000000..844deab
--- /dev/null
+++ b/cas/aidl/android/hardware/cas/SessionIntent.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.cas;
+
+/**
+ * The intented usage for the session.
+ */
+@VintfStability
+@Backing(type="int")
+enum SessionIntent {
+ /**
+ * Live Stream.
+ */
+ LIVE,
+
+ /**
+ * Playback Recorded Stream.
+ */
+ PLAYBACK,
+
+ /**
+ * Record Live Stream.
+ */
+ RECORD,
+
+ /**
+ * View the content with Time Shift capability
+ */
+ TIMESHIFT,
+}
diff --git a/cas/aidl/android/hardware/cas/SharedBuffer.aidl b/cas/aidl/android/hardware/cas/SharedBuffer.aidl
new file mode 100644
index 0000000..8a94ff7
--- /dev/null
+++ b/cas/aidl/android/hardware/cas/SharedBuffer.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.cas;
+
+import android.hardware.common.Ashmem;
+
+/**
+ * SharedBuffer describes a shared buffer which is defined by a heapBase, an
+ * offset and a size. The offset is relative to the shared memory base for the
+ * memory region identified by heapBase.
+ */
+@VintfStability
+parcelable SharedBuffer {
+ /**
+ * Ashmem shared memory
+ */
+ Ashmem heapBase;
+
+ /**
+ * The offset from the shared memory base
+ */
+ long offset;
+
+ /**
+ * The size of the shared buffer in bytes
+ */
+ long size;
+}
diff --git a/cas/aidl/android/hardware/cas/Status.aidl b/cas/aidl/android/hardware/cas/Status.aidl
new file mode 100644
index 0000000..b2be34b
--- /dev/null
+++ b/cas/aidl/android/hardware/cas/Status.aidl
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.cas;
+
+@VintfStability
+parcelable Status {
+ /**
+ * The CAS plugin must return OK when an operation completes without any
+ * errors.
+ */
+ const int OK = 0;
+
+ /**
+ * The CAS plugin must return ERROR_CAS_NO_LICENSE, when descrambling is
+ * attempted and no license keys have been provided.
+ */
+ const int ERROR_CAS_NO_LICENSE = -1;
+
+ /**
+ * ERROR_CAS_LICENSE_EXPIRED must be returned when an attempt is made
+ * to use a license and the keys in that license have expired.
+ */
+ const int ERROR_CAS_LICENSE_EXPIRED = -2;
+
+ /**
+ * The CAS plugin must return ERROR_CAS_SESSION_NOT_OPENED when an
+ * attempt is made to use a session that has not been opened.
+ */
+ const int ERROR_CAS_SESSION_NOT_OPENED = -3;
+
+ /**
+ * The CAS plugin must return ERROR_CAS_CANNOT_HANDLE when an unsupported
+ * data format or operation is attempted.
+ */
+ const int ERROR_CAS_CANNOT_HANDLE = -4;
+
+ /**
+ * ERROR_CAS_INVALID_STATE must be returned when the device is in a state
+ * where it is not able to perform descrambling.
+ */
+ const int ERROR_CAS_INVALID_STATE = -5;
+
+ /**
+ * The CAS plugin must return BAD_VALUE whenever an illegal parameter is
+ * passed to one of the interface functions.
+ */
+ const int BAD_VALUE = -6;
+
+ /**
+ * The CAS plugin must return ERROR_CAS_NOT_PROVISIONED when the device
+ * has not yet been provisioned.
+ */
+ const int ERROR_CAS_NOT_PROVISIONED = -7;
+
+ /**
+ * ERROR_CAS_RESOURCE_BUSY must be returned when resources, such as CAS
+ * sessions or secure buffers are not available to perform a requested
+ * operation because they are already in use.
+ */
+ const int ERROR_CAS_RESOURCE_BUSY = -8;
+
+ /**
+ * The CAS Plugin must return ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION
+ * when the output protection level enabled on the device is not
+ * sufficient to meet the requirements in the license policy. HDCP is an
+ * example of a form of output protection.
+ */
+ const int ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION = -9;
+
+ /**
+ * The CAS Plugin must return ERROR_CAS_TAMPER_DETECTED if an attempt to
+ * tamper with the CAS system is detected.
+ */
+ const int ERROR_CAS_TAMPER_DETECTED = -10;
+
+ /**
+ * The CAS Plugin must return ERROR_CAS_DEVICE_REVOKED if the response
+ * indicates that the device has been revoked. Device revocation means
+ * that the device is no longer permitted to play content.
+ */
+ const int ERROR_CAS_DEVICE_REVOKED = -11;
+
+ /**
+ * The CAS plugin must return ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED when
+ * descrambling is failing because the session is not initialized properly.
+ */
+ const int ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED = -12;
+
+ /**
+ * The CAS Plugin must return ERROR_CAS_DECRYPT if the DescramblerPlugin's
+ * descramble operation fails.
+ */
+ const int ERROR_CAS_DECRYPT = -13;
+
+ /**
+ * ERROR_CAS_UNKNOWN must be returned when a fatal failure occurs and no
+ * other defined error is appropriate.
+ */
+ const int ERROR_CAS_UNKNOWN = -14;
+
+ /**
+ * ERROR_CAS_NEED_ACTIVATION is used to trigger device activation process.
+ */
+ const int ERROR_CAS_NEED_ACTIVATION = -15;
+
+ /**
+ * ERROR_CAS_NEED_PAIRING is used to trigger pairing process.
+ */
+ const int ERROR_CAS_NEED_PAIRING = -16;
+
+ /**
+ * ERROR_CAS_NO_CARD is used to report no smart card for descrambling.
+ */
+ const int ERROR_CAS_NO_CARD = -17;
+
+ /**
+ * ERROR_CAS_CARD_MUTE is used to report smart card is muted for
+ * descrambling.
+ */
+ const int ERROR_CAS_CARD_MUTE = -18;
+
+ /**
+ * ERROR_CAS_CARD_INVALID is used to report smart card isn't valid.
+ */
+ const int ERROR_CAS_CARD_INVALID = -19;
+
+ /**
+ * ERROR_CAS_BLACKOUT is used to report geographical blackout.
+ */
+ const int ERROR_CAS_BLACKOUT = -20;
+
+ /**
+ * ERROR_CAS_REBOOTING is used to report CAS is during rebooting.
+ */
+ const int ERROR_CAS_REBOOTING = -21;
+}
diff --git a/cas/aidl/android/hardware/cas/StatusEvent.aidl b/cas/aidl/android/hardware/cas/StatusEvent.aidl
new file mode 100644
index 0000000..0f62634
--- /dev/null
+++ b/cas/aidl/android/hardware/cas/StatusEvent.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.cas;
+
+/**
+ * The Event Type for status change.
+ */
+@VintfStability
+@Backing(type="byte")
+enum StatusEvent {
+ /**
+ * The status of CAS plugin was changed due to physical module insertion or
+ * removal. Client must call enumeratePlugins to update plugins' status.
+ */
+ PLUGIN_PHYSICAL_MODULE_CHANGED,
+
+ /**
+ * The status of supported session number was changed due to physical module
+ * insertion or removal. Client must update session resource according to
+ * latest StatusMessage from the StatusEvent. The plugin supports unlimited
+ * session by default.
+ */
+ PLUGIN_SESSION_NUMBER_CHANGED,
+}
diff --git a/cas/aidl/android/hardware/cas/SubSample.aidl b/cas/aidl/android/hardware/cas/SubSample.aidl
new file mode 100644
index 0000000..c1353cb
--- /dev/null
+++ b/cas/aidl/android/hardware/cas/SubSample.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.cas;
+
+/**
+ * A subsample consists of some number of bytes of clear (unscrambled)
+ * data followed by a number of bytes of scrambled data.
+ */
+@VintfStability
+parcelable SubSample {
+ int numBytesOfClearData;
+ int numBytesOfEncryptedData;
+}
diff --git a/cas/aidl/default/Android.bp b/cas/aidl/default/Android.bp
new file mode 100755
index 0000000..3c16d57
--- /dev/null
+++ b/cas/aidl/default/Android.bp
@@ -0,0 +1,93 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_static {
+ name: "libcasexampleimpl",
+ vendor_available: true,
+
+ srcs: [
+ "CasImpl.cpp",
+ "DescramblerImpl.cpp",
+ "MediaCasService.cpp",
+ "SharedLibrary.cpp",
+ "TypeConvert.cpp",
+ ],
+
+ shared_libs: [
+ "android.hardware.cas-V1-ndk",
+ "libbinder_ndk",
+ "liblog",
+ "libutils",
+ "libcutils",
+ ],
+ static_libs: [
+ "libaidlcommonsupport",
+ ],
+ header_libs: [
+ "libstagefright_foundation_headers",
+ "media_plugin_headers",
+ ],
+}
+
+cc_defaults {
+ name: "cas_service_example_defaults",
+ vendor: true,
+ relative_install_path: "hw",
+
+ srcs: ["service.cpp"],
+
+ static_libs: [
+ "libaidlcommonsupport",
+ "libcasexampleimpl",
+ ],
+ shared_libs: [
+ "android.hardware.cas-V1-ndk",
+ "libbinder_ndk",
+ "liblog",
+ "libutils",
+ "libcutils",
+ ],
+ header_libs: ["media_plugin_headers"],
+ vintf_fragments: ["android.hardware.cas-service.xml"],
+}
+
+cc_binary {
+ name: "android.hardware.cas-service.example",
+ defaults: ["cas_service_example_defaults"],
+ init_rc: ["cas-default.rc"],
+}
+
+cc_binary {
+ name: "android.hardware.cas-service.example-lazy",
+ defaults: ["cas_service_example_defaults"],
+ init_rc: ["cas-default-lazy.rc"],
+ cflags: ["-DLAZY_SERVICE"],
+}
+
+cc_fuzz {
+ name: "android.hardware.cas-service_fuzzer",
+ vendor: true,
+
+ defaults: ["service_fuzzer_defaults"],
+ srcs: ["fuzzer.cpp"],
+
+ shared_libs: [
+ "android.hardware.cas-V1-ndk",
+ "libcutils",
+ "liblog",
+ ],
+ static_libs: [
+ "libaidlcommonsupport",
+ "libcasexampleimpl",
+ ],
+ header_libs: ["media_plugin_headers"],
+ fuzz_config: {
+ componentid: 1344,
+ },
+}
diff --git a/cas/aidl/default/CasImpl.cpp b/cas/aidl/default/CasImpl.cpp
new file mode 100755
index 0000000..2d31b35
--- /dev/null
+++ b/cas/aidl/default/CasImpl.cpp
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ icensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.cas-CasImpl"
+
+#include <media/cas/CasAPI.h>
+#include <utils/Log.h>
+
+#include "CasImpl.h"
+#include "TypeConvert.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace cas {
+
+CasImpl::CasImpl(const shared_ptr<ICasListener>& listener) : mListener(listener) {
+ ALOGV("CTOR");
+}
+
+CasImpl::~CasImpl() {
+ ALOGV("DTOR");
+ release();
+}
+
+// static
+void CasImpl::OnEvent(void* appData, int32_t event, int32_t arg, uint8_t* data, size_t size) {
+ if (appData == NULL) {
+ ALOGE("Invalid appData!");
+ return;
+ }
+ CasImpl* casImpl = static_cast<CasImpl*>(appData);
+ casImpl->onEvent(event, arg, data, size);
+}
+
+// static
+void CasImpl::CallBackExt(void* appData, int32_t event, int32_t arg, uint8_t* data, size_t size,
+ const CasSessionId* sessionId) {
+ if (appData == NULL) {
+ ALOGE("Invalid appData!");
+ return;
+ }
+ CasImpl* casImpl = static_cast<CasImpl*>(appData);
+ casImpl->onEvent(sessionId, event, arg, data, size);
+}
+
+// static
+void CasImpl::StatusUpdate(void* appData, int32_t event, int32_t arg) {
+ if (appData == NULL) {
+ ALOGE("Invalid appData!");
+ return;
+ }
+ CasImpl* casImpl = static_cast<CasImpl*>(appData);
+ casImpl->onStatusUpdate(event, arg);
+}
+
+void CasImpl::init(CasPlugin* plugin) {
+ shared_ptr<CasPlugin> holder(plugin);
+ atomic_store(&mPluginHolder, holder);
+}
+
+void CasImpl::onEvent(int32_t event, int32_t arg, uint8_t* data, size_t size) {
+ if (mListener == NULL) {
+ return;
+ }
+
+ vector<uint8_t> eventData;
+ if (data != NULL) {
+ eventData.assign(data, data + size);
+ }
+
+ mListener->onEvent(event, arg, eventData);
+}
+
+void CasImpl::onEvent(const CasSessionId* sessionId, int32_t event, int32_t arg, uint8_t* data,
+ size_t size) {
+ if (mListener == NULL) {
+ return;
+ }
+
+ vector<uint8_t> eventData;
+ if (data != NULL) {
+ eventData.assign(data, data + size);
+ }
+
+ if (sessionId != NULL) {
+ mListener->onSessionEvent(*sessionId, event, arg, eventData);
+ } else {
+ mListener->onEvent(event, arg, eventData);
+ }
+}
+
+void CasImpl::onStatusUpdate(int32_t event, int32_t arg) {
+ if (mListener == NULL) {
+ return;
+ }
+ mListener->onStatusUpdate(static_cast<StatusEvent>(event), arg);
+}
+
+ScopedAStatus CasImpl::setPluginStatusUpdateCallback() {
+ ALOGV("%s", __FUNCTION__);
+ shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
+ return toStatus(INVALID_OPERATION);
+ }
+ return toStatus(holder->setStatusCallback(&CasImpl::StatusUpdate));
+}
+
+ScopedAStatus CasImpl::setPrivateData(const vector<uint8_t>& pvtData) {
+ ALOGV("%s", __FUNCTION__);
+ shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
+ return toStatus(INVALID_OPERATION);
+ }
+ return toStatus(holder->setPrivateData(pvtData));
+}
+
+ScopedAStatus CasImpl::openSession(SessionIntent intent, ScramblingMode mode,
+ vector<uint8_t>* sessionId) {
+ ALOGV("%s", __FUNCTION__);
+
+ shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
+ status_t err = INVALID_OPERATION;
+ if (holder.get() != nullptr) {
+ err = holder->openSession(static_cast<uint32_t>(intent), static_cast<uint32_t>(mode),
+ sessionId);
+ holder.reset();
+ }
+
+ return toStatus(err);
+}
+
+ScopedAStatus CasImpl::setSessionPrivateData(const vector<uint8_t>& sessionId,
+ const vector<uint8_t>& pvtData) {
+ ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string());
+ shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
+ return toStatus(INVALID_OPERATION);
+ }
+ return toStatus(holder->setSessionPrivateData(sessionId, pvtData));
+}
+
+ScopedAStatus CasImpl::closeSession(const vector<uint8_t>& sessionId) {
+ ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string());
+ shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
+ return toStatus(INVALID_OPERATION);
+ }
+ return toStatus(holder->closeSession(sessionId));
+}
+
+ScopedAStatus CasImpl::processEcm(const vector<uint8_t>& sessionId, const vector<uint8_t>& ecm) {
+ ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string());
+ shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
+ return toStatus(INVALID_OPERATION);
+ }
+
+ return toStatus(holder->processEcm(sessionId, ecm));
+}
+
+ScopedAStatus CasImpl::processEmm(const vector<uint8_t>& emm) {
+ ALOGV("%s", __FUNCTION__);
+ shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
+ return toStatus(INVALID_OPERATION);
+ }
+
+ return toStatus(holder->processEmm(emm));
+}
+
+ScopedAStatus CasImpl::sendEvent(int32_t event, int32_t arg, const vector<uint8_t>& eventData) {
+ ALOGV("%s", __FUNCTION__);
+ shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
+ return toStatus(INVALID_OPERATION);
+ }
+
+ status_t err = holder->sendEvent(event, arg, eventData);
+ return toStatus(err);
+}
+
+ScopedAStatus CasImpl::sendSessionEvent(const vector<uint8_t>& sessionId, int32_t event,
+ int32_t arg, const vector<uint8_t>& eventData) {
+ ALOGV("%s", __FUNCTION__);
+ shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
+ return toStatus(INVALID_OPERATION);
+ }
+
+ status_t err = holder->sendSessionEvent(sessionId, event, arg, eventData);
+ return toStatus(err);
+}
+
+ScopedAStatus CasImpl::provision(const string& provisionString) {
+ ALOGV("%s: provisionString=%s", __FUNCTION__, provisionString.c_str());
+ shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
+ return toStatus(INVALID_OPERATION);
+ }
+
+ return toStatus(holder->provision(String8(provisionString.c_str())));
+}
+
+ScopedAStatus CasImpl::refreshEntitlements(int32_t refreshType,
+ const vector<uint8_t>& refreshData) {
+ ALOGV("%s", __FUNCTION__);
+ shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
+ return toStatus(INVALID_OPERATION);
+ }
+
+ status_t err = holder->refreshEntitlements(refreshType, refreshData);
+ return toStatus(err);
+}
+
+ScopedAStatus CasImpl::release() {
+ ALOGV("%s: plugin=%p", __FUNCTION__, mPluginHolder.get());
+
+ shared_ptr<CasPlugin> holder(nullptr);
+ atomic_store(&mPluginHolder, holder);
+
+ return ScopedAStatus::ok();
+}
+
+} // namespace cas
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/cas/aidl/default/CasImpl.h b/cas/aidl/default/CasImpl.h
new file mode 100755
index 0000000..84a8115
--- /dev/null
+++ b/cas/aidl/default/CasImpl.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/android/hardware/cas/BnCas.h>
+#include <aidl/android/hardware/cas/ICasListener.h>
+#include <media/stagefright/foundation/ABase.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace cas {
+
+using namespace ::android;
+using namespace std;
+using ndk::ScopedAStatus;
+
+class CasImpl : public BnCas {
+ public:
+ CasImpl(const shared_ptr<ICasListener>& listener);
+ virtual ~CasImpl();
+
+ static void OnEvent(void* appData, int32_t event, int32_t arg, uint8_t* data, size_t size);
+
+ static void CallBackExt(void* appData, int32_t event, int32_t arg, uint8_t* data, size_t size,
+ const CasSessionId* sessionId);
+
+ static void StatusUpdate(void* appData, int32_t event, int32_t arg);
+
+ void init(CasPlugin* plugin);
+ void onEvent(int32_t event, int32_t arg, uint8_t* data, size_t size);
+
+ void onEvent(const CasSessionId* sessionId, int32_t event, int32_t arg, uint8_t* data,
+ size_t size);
+
+ void onStatusUpdate(int32_t event, int32_t arg);
+
+ // ICas inherits
+
+ ScopedAStatus setPluginStatusUpdateCallback();
+
+ virtual ScopedAStatus setPrivateData(const vector<uint8_t>& pvtData) override;
+
+ virtual ScopedAStatus openSession(SessionIntent intent, ScramblingMode mode,
+ vector<uint8_t>* sessionId) override;
+
+ virtual ScopedAStatus closeSession(const vector<uint8_t>& sessionId) override;
+
+ virtual ScopedAStatus setSessionPrivateData(const vector<uint8_t>& sessionId,
+ const vector<uint8_t>& pvtData) override;
+
+ virtual ScopedAStatus processEcm(const vector<uint8_t>& sessionId,
+ const vector<uint8_t>& ecm) override;
+
+ virtual ScopedAStatus processEmm(const vector<uint8_t>& emm) override;
+
+ virtual ScopedAStatus sendEvent(int32_t event, int32_t arg,
+ const vector<uint8_t>& eventData) override;
+
+ virtual ScopedAStatus sendSessionEvent(const vector<uint8_t>& sessionId, int32_t event,
+ int32_t arg, const vector<uint8_t>& eventData) override;
+
+ virtual ScopedAStatus provision(const string& provisionString) override;
+
+ virtual ScopedAStatus refreshEntitlements(int32_t refreshType,
+ const vector<uint8_t>& refreshData) override;
+
+ virtual ScopedAStatus release() override;
+
+ private:
+ struct PluginHolder;
+ shared_ptr<CasPlugin> mPluginHolder;
+ shared_ptr<ICasListener> mListener;
+
+ DISALLOW_EVIL_CONSTRUCTORS(CasImpl);
+};
+
+} // namespace cas
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/cas/aidl/default/DescramblerImpl.cpp b/cas/aidl/default/DescramblerImpl.cpp
new file mode 100755
index 0000000..a96fd46
--- /dev/null
+++ b/cas/aidl/default/DescramblerImpl.cpp
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.cas-DescramblerImpl"
+
+#include <aidlcommonsupport/NativeHandle.h>
+#include <inttypes.h>
+#include <media/cas/DescramblerAPI.h>
+#include <media/hardware/CryptoAPI.h>
+#include <media/stagefright/foundation/AUtils.h>
+#include <sys/mman.h>
+#include <utils/Log.h>
+
+#include "DescramblerImpl.h"
+#include "TypeConvert.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace cas {
+
+#define CHECK_SUBSAMPLE_DEF(type) \
+ static_assert(sizeof(SubSample) == sizeof(type::SubSample), "SubSample: size doesn't match"); \
+ static_assert(offsetof(SubSample, numBytesOfClearData) == \
+ offsetof(type::SubSample, mNumBytesOfClearData), \
+ "SubSample: numBytesOfClearData offset doesn't match"); \
+ static_assert(offsetof(SubSample, numBytesOfEncryptedData) == \
+ offsetof(type::SubSample, mNumBytesOfEncryptedData), \
+ "SubSample: numBytesOfEncryptedData offset doesn't match")
+
+CHECK_SUBSAMPLE_DEF(DescramblerPlugin);
+CHECK_SUBSAMPLE_DEF(CryptoPlugin);
+
+DescramblerImpl::DescramblerImpl(DescramblerPlugin* plugin) : mPluginHolder(plugin) {
+ ALOGV("CTOR: plugin=%p", mPluginHolder.get());
+}
+
+DescramblerImpl::~DescramblerImpl() {
+ ALOGV("DTOR: plugin=%p", mPluginHolder.get());
+ release();
+}
+
+ScopedAStatus DescramblerImpl::setMediaCasSession(const vector<uint8_t>& in_sessionId) {
+ ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(in_sessionId).string());
+
+ shared_ptr<DescramblerPlugin> holder = atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
+ return toStatus(INVALID_OPERATION);
+ }
+
+ return toStatus(holder->setMediaCasSession(in_sessionId));
+}
+
+ScopedAStatus DescramblerImpl::requiresSecureDecoderComponent(const string& in_mime,
+ bool* _aidl_return) {
+ shared_ptr<DescramblerPlugin> holder = atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
+ *_aidl_return = false;
+ }
+
+ *_aidl_return = holder->requiresSecureDecoderComponent(String8(in_mime.c_str()));
+ return ScopedAStatus::ok();
+}
+
+static inline bool validateRangeForSize(int64_t offset, int64_t length, int64_t size) {
+ return isInRange<int64_t, uint64_t>(0, (uint64_t)size, offset, (uint64_t)length);
+}
+
+ScopedAStatus DescramblerImpl::descramble(ScramblingControl scramblingControl,
+ const vector<SubSample>& subSamples,
+ const SharedBuffer& srcBuffer, int64_t srcOffset,
+ const DestinationBuffer& dstBuffer, int64_t dstOffset,
+ int32_t* _aidl_return) {
+ ALOGV("%s", __FUNCTION__);
+
+ // heapbase's size is stored in int64_t, but mapMemory's mmap will map size in
+ // size_t. If size is over SIZE_MAX, mapMemory mapMemory could succeed but the
+ // mapped memory's actual size will be smaller than the reported size.
+ if (srcBuffer.heapBase.size > SIZE_MAX) {
+ ALOGE("Invalid memory size: %" PRIu64 "", srcBuffer.heapBase.size);
+ android_errorWriteLog(0x534e4554, "79376389");
+ return toStatus(BAD_VALUE);
+ }
+
+ void* srcPtr = mmap(NULL, srcBuffer.heapBase.size, PROT_READ | PROT_WRITE, MAP_SHARED,
+ srcBuffer.heapBase.fd.get(), 0);
+
+ // Validate if the offset and size in the SharedBuffer is consistent with the
+ // mapped heapbase, since the offset and size is controlled by client.
+ if (srcPtr == NULL) {
+ ALOGE("Failed to map src buffer.");
+ return toStatus(BAD_VALUE);
+ }
+ if (!validateRangeForSize(srcBuffer.offset, srcBuffer.size, srcBuffer.heapBase.size)) {
+ ALOGE("Invalid src buffer range: offset %" PRIu64 ", size %" PRIu64
+ ", srcMem"
+ "size %" PRIu64 "",
+ srcBuffer.offset, srcBuffer.size, srcBuffer.heapBase.size);
+ android_errorWriteLog(0x534e4554, "67962232");
+ return toStatus(BAD_VALUE);
+ }
+
+ // use 64-bit here to catch bad subsample size that might be overflowing.
+ uint64_t totalBytesInSubSamples = 0;
+ for (size_t i = 0; i < subSamples.size(); i++) {
+ uint32_t numBytesOfClearData = subSamples[i].numBytesOfClearData;
+ uint32_t numBytesOfEncryptedData = subSamples[i].numBytesOfEncryptedData;
+ totalBytesInSubSamples += (uint64_t)numBytesOfClearData + numBytesOfEncryptedData;
+ }
+ // Further validate if the specified srcOffset and requested total subsample size
+ // is consistent with the source shared buffer size.
+ if (!validateRangeForSize(srcOffset, totalBytesInSubSamples, srcBuffer.size)) {
+ ALOGE("Invalid srcOffset and subsample size: "
+ "srcOffset %" PRIu64 ", totalBytesInSubSamples %" PRIu64
+ ", srcBuffer"
+ "size %" PRIu64 "",
+ srcOffset, totalBytesInSubSamples, srcBuffer.size);
+ android_errorWriteLog(0x534e4554, "67962232");
+ return toStatus(BAD_VALUE);
+ }
+ srcPtr = (uint8_t*)srcPtr + srcBuffer.offset;
+
+ void* dstPtr = NULL;
+ if (dstBuffer.getTag() == DestinationBuffer::Tag::nonsecureMemory) {
+ // When using shared memory, src buffer is also used as dst,
+ // we don't map it again here.
+ dstPtr = srcPtr;
+
+ // In this case the dst and src would be the same buffer, need to validate
+ // dstOffset against the buffer size too.
+ if (!validateRangeForSize(dstOffset, totalBytesInSubSamples, srcBuffer.size)) {
+ ALOGE("Invalid dstOffset and subsample size: "
+ "dstOffset %" PRIu64 ", totalBytesInSubSamples %" PRIu64
+ ", srcBuffer"
+ "size %" PRIu64 "",
+ dstOffset, totalBytesInSubSamples, srcBuffer.size);
+ android_errorWriteLog(0x534e4554, "67962232");
+ return toStatus(BAD_VALUE);
+ }
+ } else {
+ native_handle_t* handle = makeFromAidl(dstBuffer.get<DestinationBuffer::secureMemory>());
+ dstPtr = static_cast<void*>(handle);
+ }
+
+ // Get a local copy of the shared_ptr for the plugin. Note that before
+ // calling the callback, this shared_ptr must be manually reset, since
+ // the client side could proceed as soon as the callback is called
+ // without waiting for this method to go out of scope.
+ shared_ptr<DescramblerPlugin> holder = atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
+ return toStatus(INVALID_OPERATION);
+ }
+
+ // Casting SubSample to DescramblerPlugin::SubSample, but need to ensure
+ // structs are actually identical
+
+ auto returnStatus =
+ holder->descramble(dstBuffer.getTag() != DestinationBuffer::Tag::nonsecureMemory,
+ (DescramblerPlugin::ScramblingControl)scramblingControl,
+ subSamples.size(), (DescramblerPlugin::SubSample*)subSamples.data(),
+ srcPtr, srcOffset, dstPtr, dstOffset, NULL);
+
+ holder.reset();
+ *_aidl_return = returnStatus;
+ return toStatus(returnStatus >= 0 ? OK : returnStatus);
+}
+
+ScopedAStatus DescramblerImpl::release() {
+ ALOGV("%s: plugin=%p", __FUNCTION__, mPluginHolder.get());
+
+ shared_ptr<DescramblerPlugin> holder(nullptr);
+ atomic_store(&mPluginHolder, holder);
+
+ return ScopedAStatus::ok();
+}
+
+} // namespace cas
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/cas/aidl/default/DescramblerImpl.h b/cas/aidl/default/DescramblerImpl.h
new file mode 100755
index 0000000..2efc1a0
--- /dev/null
+++ b/cas/aidl/default/DescramblerImpl.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/android/hardware/cas/BnDescrambler.h>
+#include <media/stagefright/foundation/ABase.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace cas {
+
+using namespace ::android;
+using namespace std;
+using ndk::ScopedAStatus;
+
+class DescramblerImpl : public BnDescrambler {
+ public:
+ DescramblerImpl(DescramblerPlugin* plugin);
+ virtual ~DescramblerImpl();
+
+ virtual ScopedAStatus setMediaCasSession(const vector<uint8_t>& in_sessionId) override;
+
+ virtual ScopedAStatus requiresSecureDecoderComponent(const string& in_mime,
+ bool* _aidl_return) override;
+
+ virtual ScopedAStatus descramble(ScramblingControl in_scramblingControl,
+ const vector<SubSample>& in_subSamples,
+ const SharedBuffer& in_srcBuffer, int64_t in_srcOffset,
+ const DestinationBuffer& in_dstBuffer, int64_t in_dstOffset,
+ int32_t* _aidl_return) override;
+
+ virtual ScopedAStatus release() override;
+
+ private:
+ shared_ptr<DescramblerPlugin> mPluginHolder;
+
+ DISALLOW_EVIL_CONSTRUCTORS(DescramblerImpl);
+};
+
+} // namespace cas
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/cas/aidl/default/FactoryLoader.h b/cas/aidl/default/FactoryLoader.h
new file mode 100755
index 0000000..f90b109
--- /dev/null
+++ b/cas/aidl/default/FactoryLoader.h
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dirent.h>
+#include <dlfcn.h>
+#include <media/cas/CasAPI.h>
+#include <utils/KeyedVector.h>
+#include <utils/Mutex.h>
+#include "SharedLibrary.h"
+
+using namespace std;
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace cas {
+
+using namespace ::android;
+
+template <class T>
+class FactoryLoader {
+ public:
+ FactoryLoader(const char* name) : mFactory(NULL), mCreateFactoryFuncName(name) {}
+
+ virtual ~FactoryLoader() { closeFactory(); }
+
+ bool findFactoryForScheme(int32_t CA_system_id, shared_ptr<SharedLibrary>* library = NULL,
+ T** factory = NULL);
+
+ bool enumeratePlugins(vector<AidlCasPluginDescriptor>* results);
+
+ private:
+ typedef T* (*CreateFactoryFunc)();
+
+ Mutex mMapLock;
+ T* mFactory;
+ const char* mCreateFactoryFuncName;
+ shared_ptr<SharedLibrary> mLibrary;
+ KeyedVector<int32_t, String8> mCASystemIdToLibraryPathMap;
+ KeyedVector<String8, shared_ptr<SharedLibrary>> mLibraryPathToOpenLibraryMap;
+
+ bool loadFactoryForSchemeFromPath(const String8& path, int32_t CA_system_id,
+ shared_ptr<SharedLibrary>* library, T** factory);
+
+ bool queryPluginsFromPath(const String8& path, vector<AidlCasPluginDescriptor>* results);
+
+ bool openFactory(const String8& path);
+ void closeFactory();
+};
+
+template <class T>
+bool FactoryLoader<T>::findFactoryForScheme(int32_t CA_system_id,
+ shared_ptr<SharedLibrary>* library, T** factory) {
+ if (library != NULL) {
+ library->reset();
+ }
+ if (factory != NULL) {
+ *factory = NULL;
+ }
+
+ Mutex::Autolock autoLock(mMapLock);
+
+ // first check cache
+ ssize_t index = mCASystemIdToLibraryPathMap.indexOfKey(CA_system_id);
+ if (index >= 0) {
+ return loadFactoryForSchemeFromPath(mCASystemIdToLibraryPathMap[index], CA_system_id,
+ library, factory);
+ }
+
+ // no luck, have to search
+#ifdef __LP64__
+ String8 dirPath("/vendor/lib64/mediacas");
+#else
+ String8 dirPath("/vendor/lib/mediacas");
+#endif
+ DIR* pDir = opendir(dirPath.string());
+
+ if (pDir == NULL) {
+ ALOGE("Failed to open plugin directory %s", dirPath.string());
+ return false;
+ }
+
+ struct dirent* pEntry;
+ while ((pEntry = readdir(pDir))) {
+ String8 pluginPath = dirPath + "/" + pEntry->d_name;
+ if (pluginPath.getPathExtension() == ".so") {
+ if (loadFactoryForSchemeFromPath(pluginPath, CA_system_id, library, factory)) {
+ mCASystemIdToLibraryPathMap.add(CA_system_id, pluginPath);
+ closedir(pDir);
+
+ return true;
+ }
+ }
+ }
+
+ closedir(pDir);
+
+ ALOGE("Failed to find plugin");
+ return false;
+}
+
+template <class T>
+bool FactoryLoader<T>::enumeratePlugins(vector<AidlCasPluginDescriptor>* results) {
+ ALOGI("enumeratePlugins");
+
+ results->clear();
+
+#ifdef __LP64__
+ String8 dirPath("/vendor/lib64/mediacas");
+#else
+ String8 dirPath("/vendor/lib/mediacas");
+#endif
+ DIR* pDir = opendir(dirPath.string());
+
+ if (pDir == NULL) {
+ ALOGE("Failed to open plugin directory %s", dirPath.string());
+ return false;
+ }
+
+ Mutex::Autolock autoLock(mMapLock);
+
+ struct dirent* pEntry;
+ while ((pEntry = readdir(pDir))) {
+ String8 pluginPath = dirPath + "/" + pEntry->d_name;
+ if (pluginPath.getPathExtension() == ".so") {
+ queryPluginsFromPath(pluginPath, results);
+ }
+ }
+ return true;
+}
+
+template <class T>
+bool FactoryLoader<T>::loadFactoryForSchemeFromPath(const String8& path, int32_t CA_system_id,
+ shared_ptr<SharedLibrary>* library,
+ T** factory) {
+ closeFactory();
+
+ if (!openFactory(path) || !mFactory->isSystemIdSupported(CA_system_id)) {
+ closeFactory();
+ return false;
+ }
+
+ if (library != NULL) {
+ *library = mLibrary;
+ }
+ if (factory != NULL) {
+ *factory = mFactory;
+ }
+ return true;
+}
+
+template <class T>
+bool FactoryLoader<T>::queryPluginsFromPath(const String8& path,
+ vector<AidlCasPluginDescriptor>* results) {
+ closeFactory();
+
+ vector<CasPluginDescriptor> descriptors;
+ if (!openFactory(path) || mFactory->queryPlugins(&descriptors) != OK) {
+ closeFactory();
+ return false;
+ }
+
+ for (auto it = descriptors.begin(); it != descriptors.end(); it++) {
+ results->push_back(
+ AidlCasPluginDescriptor{.caSystemId = it->CA_system_id, .name = it->name.c_str()});
+ }
+ return true;
+}
+
+template <class T>
+bool FactoryLoader<T>::openFactory(const String8& path) {
+ // get strong pointer to open shared library
+ ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path);
+ if (index >= 0) {
+ mLibrary = mLibraryPathToOpenLibraryMap[index];
+ } else {
+ index = mLibraryPathToOpenLibraryMap.add(path, NULL);
+ }
+
+ if (!mLibrary.get()) {
+ mLibrary = ::ndk::SharedRefBase::make<SharedLibrary>(path);
+ if (!*mLibrary) {
+ return false;
+ }
+
+ mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary);
+ }
+
+ CreateFactoryFunc createFactory = (CreateFactoryFunc)mLibrary->lookup(mCreateFactoryFuncName);
+ if (createFactory == NULL || (mFactory = createFactory()) == NULL) {
+ return false;
+ }
+ return true;
+}
+
+template <class T>
+void FactoryLoader<T>::closeFactory() {
+ delete mFactory;
+ mFactory = NULL;
+ mLibrary.reset();
+}
+
+} // namespace cas
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/cas/aidl/default/MediaCasService.cpp b/cas/aidl/default/MediaCasService.cpp
new file mode 100755
index 0000000..8285613
--- /dev/null
+++ b/cas/aidl/default/MediaCasService.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.cas-MediaCasService"
+
+#include <media/cas/CasAPI.h>
+#include <media/cas/DescramblerAPI.h>
+#include <utils/Log.h>
+
+#include "CasImpl.h"
+#include "DescramblerImpl.h"
+#include "MediaCasService.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace cas {
+
+MediaCasService::MediaCasService()
+ : mCasLoader("createCasFactory"), mDescramblerLoader("createDescramblerFactory") {}
+
+MediaCasService::~MediaCasService() {}
+
+ScopedAStatus MediaCasService::enumeratePlugins(
+ vector<AidlCasPluginDescriptor>* aidlCasPluginDescriptors) {
+ ALOGV("%s", __FUNCTION__);
+
+ mCasLoader.enumeratePlugins(aidlCasPluginDescriptors);
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus MediaCasService::isSystemIdSupported(int32_t CA_system_id, bool* _aidl_return) {
+ ALOGV("isSystemIdSupported: CA_system_id=%d", CA_system_id);
+
+ *_aidl_return = mCasLoader.findFactoryForScheme(CA_system_id);
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus MediaCasService::createPlugin(int32_t CA_system_id,
+ const shared_ptr<ICasListener>& listener,
+ shared_ptr<ICas>* _aidl_return) {
+ ALOGV("%s: CA_system_id=%d", __FUNCTION__, CA_system_id);
+ if (listener == NULL) ALOGV("%s: Listener is NULL", __FUNCTION__);
+
+ CasFactory* factory;
+ shared_ptr<SharedLibrary> library;
+ if (mCasLoader.findFactoryForScheme(CA_system_id, &library, &factory)) {
+ CasPlugin* plugin = NULL;
+ shared_ptr<CasImpl> casImpl = ::ndk::SharedRefBase::make<CasImpl>(listener);
+ if (factory->createPlugin(CA_system_id, casImpl.get(), &CasImpl::CallBackExt, &plugin) ==
+ OK &&
+ plugin != NULL) {
+ casImpl->init(plugin);
+ *_aidl_return = casImpl;
+ casImpl->setPluginStatusUpdateCallback();
+ }
+ }
+
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus MediaCasService::isDescramblerSupported(int32_t CA_system_id, bool* _aidl_return) {
+ ALOGV("%s: CA_system_id=%d", __FUNCTION__, CA_system_id);
+
+ *_aidl_return = mDescramblerLoader.findFactoryForScheme(CA_system_id);
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus MediaCasService::createDescrambler(int32_t CA_system_id,
+ shared_ptr<IDescrambler>* _aidl_return) {
+ ALOGV("%s: CA_system_id=%d", __FUNCTION__, CA_system_id);
+
+ DescramblerFactory* factory;
+ shared_ptr<SharedLibrary> library;
+ if (mDescramblerLoader.findFactoryForScheme(CA_system_id, &library, &factory)) {
+ DescramblerPlugin* plugin = NULL;
+ if (factory->createPlugin(CA_system_id, &plugin) == OK && plugin != NULL) {
+ *_aidl_return = ::ndk::SharedRefBase::make<DescramblerImpl>(plugin);
+ }
+ }
+
+ return ScopedAStatus::ok();
+}
+
+} // namespace cas
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/cas/aidl/default/MediaCasService.h b/cas/aidl/default/MediaCasService.h
new file mode 100755
index 0000000..9662313
--- /dev/null
+++ b/cas/aidl/default/MediaCasService.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <aidl/android/hardware/cas/BnMediaCasService.h>
+#include <media/cas/DescramblerAPI.h>
+
+#include "FactoryLoader.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace cas {
+
+using namespace ::android;
+using namespace std;
+using ndk::ScopedAStatus;
+
+class MediaCasService : public BnMediaCasService {
+ public:
+ MediaCasService();
+
+ virtual ScopedAStatus enumeratePlugins(
+ vector<AidlCasPluginDescriptor>* aidlCasPluginDescriptors) override;
+
+ virtual ScopedAStatus isSystemIdSupported(int32_t in_CA_system_id, bool* _aidl_return) override;
+
+ virtual ScopedAStatus createPlugin(int32_t in_CA_system_id,
+ const shared_ptr<ICasListener>& in_listener,
+ shared_ptr<ICas>* _aidl_return) override;
+
+ virtual ScopedAStatus isDescramblerSupported(int32_t in_CA_system_id,
+ bool* _aidl_return) override;
+
+ virtual ScopedAStatus createDescrambler(int32_t in_CA_system_id,
+ shared_ptr<IDescrambler>* _aidl_return) override;
+
+ private:
+ FactoryLoader<CasFactory> mCasLoader;
+ FactoryLoader<DescramblerFactory> mDescramblerLoader;
+
+ virtual ~MediaCasService();
+};
+
+} // namespace cas
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/cas/aidl/default/OWNERS b/cas/aidl/default/OWNERS
new file mode 100755
index 0000000..4c55752
--- /dev/null
+++ b/cas/aidl/default/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 1344
+quxiangfang@google.com
+hgchen@google.com
diff --git a/cas/aidl/default/SharedLibrary.cpp b/cas/aidl/default/SharedLibrary.cpp
new file mode 100755
index 0000000..e79f383
--- /dev/null
+++ b/cas/aidl/default/SharedLibrary.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.cas-SharedLibrary"
+
+#include "SharedLibrary.h"
+#include <dlfcn.h>
+#include <utils/Log.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace cas {
+
+SharedLibrary::SharedLibrary(const String8& path) {
+ mLibHandle = dlopen(path.string(), RTLD_NOW);
+}
+
+SharedLibrary::~SharedLibrary() {
+ if (mLibHandle != NULL) {
+ dlclose(mLibHandle);
+ mLibHandle = NULL;
+ }
+}
+
+bool SharedLibrary::operator!() const {
+ return mLibHandle == NULL;
+}
+
+void* SharedLibrary::lookup(const char* symbol) const {
+ if (!mLibHandle) {
+ return NULL;
+ }
+ // Clear last error before we load the symbol again,
+ // in case the caller didn't retrieve it.
+ (void)dlerror();
+ return dlsym(mLibHandle, symbol);
+}
+
+const char* SharedLibrary::lastError() const {
+ const char* error = dlerror();
+ return error ? error : "No errors or unknown error";
+}
+
+} // namespace cas
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/cas/aidl/default/SharedLibrary.h b/cas/aidl/default/SharedLibrary.h
new file mode 100755
index 0000000..d367866
--- /dev/null
+++ b/cas/aidl/default/SharedLibrary.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/binder_interface_utils.h>
+#include <media/stagefright/foundation/ABase.h>
+#include <utils/String8.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace cas {
+
+using namespace ::android;
+
+class SharedLibrary : public ndk::SharedRefBase {
+ public:
+ explicit SharedLibrary(const String8& path);
+ ~SharedLibrary();
+
+ bool operator!() const;
+ void* lookup(const char* symbol) const;
+ const char* lastError() const;
+
+ private:
+ void* mLibHandle;
+ DISALLOW_EVIL_CONSTRUCTORS(SharedLibrary);
+};
+
+} // namespace cas
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/cas/aidl/default/TypeConvert.cpp b/cas/aidl/default/TypeConvert.cpp
new file mode 100755
index 0000000..4f7005f
--- /dev/null
+++ b/cas/aidl/default/TypeConvert.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.cas-TypeConvert"
+
+#include <aidl/android/hardware/cas/Status.h>
+#include <utils/Log.h>
+
+#include "TypeConvert.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace cas {
+
+ScopedAStatus toStatus(status_t legacyStatus) {
+ int status;
+ switch (legacyStatus) {
+ case OK:
+ return ndk::ScopedAStatus::ok();
+ case ERROR_CAS_NO_LICENSE:
+ status = Status::ERROR_CAS_NO_LICENSE;
+ break;
+ case ERROR_CAS_LICENSE_EXPIRED:
+ status = Status::ERROR_CAS_LICENSE_EXPIRED;
+ break;
+ case ERROR_CAS_SESSION_NOT_OPENED:
+ status = Status::ERROR_CAS_SESSION_NOT_OPENED;
+ break;
+ case ERROR_CAS_CANNOT_HANDLE:
+ status = Status::ERROR_CAS_CANNOT_HANDLE;
+ break;
+ case ERROR_CAS_TAMPER_DETECTED:
+ status = Status::ERROR_CAS_INVALID_STATE;
+ break;
+ case BAD_VALUE:
+ status = Status::BAD_VALUE;
+ break;
+ case ERROR_CAS_NOT_PROVISIONED:
+ status = Status::ERROR_CAS_NOT_PROVISIONED;
+ break;
+ case ERROR_CAS_RESOURCE_BUSY:
+ status = Status::ERROR_CAS_RESOURCE_BUSY;
+ break;
+ case ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION:
+ status = Status::ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION;
+ break;
+ case ERROR_CAS_DEVICE_REVOKED:
+ status = Status::ERROR_CAS_DEVICE_REVOKED;
+ break;
+ case ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED:
+ status = Status::ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED;
+ break;
+ case ERROR_CAS_DECRYPT:
+ status = Status::ERROR_CAS_DECRYPT;
+ break;
+ case ERROR_CAS_NEED_ACTIVATION:
+ status = Status::ERROR_CAS_NEED_ACTIVATION;
+ break;
+ case ERROR_CAS_NEED_PAIRING:
+ status = Status::ERROR_CAS_NEED_PAIRING;
+ break;
+ case ERROR_CAS_NO_CARD:
+ status = Status::ERROR_CAS_NO_CARD;
+ break;
+ case ERROR_CAS_CARD_MUTE:
+ status = Status::ERROR_CAS_CARD_MUTE;
+ break;
+ case ERROR_CAS_CARD_INVALID:
+ status = Status::ERROR_CAS_CARD_INVALID;
+ break;
+ case ERROR_CAS_BLACKOUT:
+ status = Status::ERROR_CAS_BLACKOUT;
+ break;
+ default:
+ ALOGW("Unable to convert legacy status: %d, defaulting to UNKNOWN", legacyStatus);
+ status = Status::ERROR_CAS_UNKNOWN;
+ break;
+ }
+ return ScopedAStatus::fromServiceSpecificError(status);
+}
+
+String8 sessionIdToString(const std::vector<uint8_t>& sessionId) {
+ String8 result;
+ for (auto it = sessionId.begin(); it != sessionId.end(); it++) {
+ result.appendFormat("%02x ", *it);
+ }
+ if (result.isEmpty()) {
+ result.append("(null)");
+ }
+ return result;
+}
+
+} // namespace cas
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/cas/aidl/default/TypeConvert.h b/cas/aidl/default/TypeConvert.h
new file mode 100755
index 0000000..ebfa286
--- /dev/null
+++ b/cas/aidl/default/TypeConvert.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/binder_interface_utils.h>
+#include <media/stagefright/MediaErrors.h>
+#include <utils/String8.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace cas {
+
+using namespace ::android;
+using ndk::ScopedAStatus;
+
+ScopedAStatus toStatus(status_t legacyStatus);
+
+String8 sessionIdToString(const std::vector<uint8_t>& sessionId);
+
+} // namespace cas
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/cas/aidl/default/android.hardware.cas-service.xml b/cas/aidl/default/android.hardware.cas-service.xml
new file mode 100755
index 0000000..6389fe2
--- /dev/null
+++ b/cas/aidl/default/android.hardware.cas-service.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.cas</name>
+ <fqname>IMediaCasService/default</fqname>
+ </hal>
+</manifest>
diff --git a/cas/aidl/default/cas-default-lazy.rc b/cas/aidl/default/cas-default-lazy.rc
new file mode 100755
index 0000000..60b59ca
--- /dev/null
+++ b/cas/aidl/default/cas-default-lazy.rc
@@ -0,0 +1,9 @@
+service vendor.cas-default-lazy /vendor/bin/hw/android.hardware.cas-service.example-lazy
+ interface aidl android.hardware.cas.IMediaCasService/default
+ class hal
+ user media
+ group mediadrm drmrpc
+ ioprio rt 4
+ task_profiles ProcessCapacityHigh
+ oneshot
+ disabled
diff --git a/cas/aidl/default/cas-default.rc b/cas/aidl/default/cas-default.rc
new file mode 100755
index 0000000..e00b9c5
--- /dev/null
+++ b/cas/aidl/default/cas-default.rc
@@ -0,0 +1,7 @@
+service vendor.cas-default /vendor/bin/hw/android.hardware.cas-service.example
+ interface aidl android.hardware.cas.IMediaCasService/default
+ class hal
+ user media
+ group mediadrm drmrpc
+ ioprio rt 4
+ task_profiles ProcessCapacityHigh
diff --git a/cas/aidl/default/fuzzer.cpp b/cas/aidl/default/fuzzer.cpp
new file mode 100755
index 0000000..db1369e
--- /dev/null
+++ b/cas/aidl/default/fuzzer.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <MediaCasService.h>
+#include <fuzzbinder/libbinder_ndk_driver.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+using aidl::android::hardware::cas::MediaCasService;
+using android::fuzzService;
+using ndk::SharedRefBase;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ auto mediaCasServiceAidl = SharedRefBase::make<MediaCasService>();
+
+ fuzzService(mediaCasServiceAidl->asBinder().get(), FuzzedDataProvider(data, size));
+
+ return 0;
+}
\ No newline at end of file
diff --git a/cas/aidl/default/service.cpp b/cas/aidl/default/service.cpp
new file mode 100755
index 0000000..bed2f01
--- /dev/null
+++ b/cas/aidl/default/service.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifdef LAZY_SERVICE
+const bool kLazyService = true;
+#define LOG_TAG "android.hardware.cas-service.example-lazy"
+#else
+const bool kLazyService = false;
+#define LOG_TAG "android.hardware.cas-service.example"
+#endif
+
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+#include "MediaCasService.h"
+
+using aidl::android::hardware::cas::MediaCasService;
+
+int main() {
+ ABinderProcess_setThreadPoolMaxThreadCount(8);
+
+ // Setup hwbinder service
+ std::shared_ptr<MediaCasService> service = ::ndk::SharedRefBase::make<MediaCasService>();
+
+ const std::string instance = std::string() + MediaCasService::descriptor + "/default";
+ binder_status_t status;
+
+ if (kLazyService) {
+ status = AServiceManager_registerLazyService(service->asBinder().get(), instance.c_str());
+ } else {
+ status = AServiceManager_addService(service->asBinder().get(), instance.c_str());
+ }
+ LOG_ALWAYS_FATAL_IF(status != STATUS_OK, "Error while registering cas service: %d", status);
+
+ ABinderProcess_joinThreadPool();
+ return 0;
+}
diff --git a/cas/aidl/vts/functional/Android.bp b/cas/aidl/vts/functional/Android.bp
new file mode 100644
index 0000000..295ae7c
--- /dev/null
+++ b/cas/aidl/vts/functional/Android.bp
@@ -0,0 +1,45 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_test {
+ name: "VtsHalCasAidlTargetTest",
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "use_libaidlvintf_gtest_helper_static",
+ ],
+ srcs: ["VtsHalCasAidlTargetTest.cpp"],
+ static_libs: [
+ "android.hardware.cas-V1-ndk",
+ "android.hardware.common-V2-ndk",
+ ],
+ shared_libs: [
+ "libbinder_ndk",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+ disable_framework: true,
+}
diff --git a/cas/aidl/vts/functional/OWNERS b/cas/aidl/vts/functional/OWNERS
new file mode 100644
index 0000000..4c55752
--- /dev/null
+++ b/cas/aidl/vts/functional/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 1344
+quxiangfang@google.com
+hgchen@google.com
diff --git a/cas/aidl/vts/functional/VtsHalCasAidlTargetTest.cpp b/cas/aidl/vts/functional/VtsHalCasAidlTargetTest.cpp
new file mode 100644
index 0000000..266b55d
--- /dev/null
+++ b/cas/aidl/vts/functional/VtsHalCasAidlTargetTest.cpp
@@ -0,0 +1,809 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "mediacas_aidl_hal_test"
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/cas/BnCasListener.h>
+#include <aidl/android/hardware/cas/IMediaCasService.h>
+#include <aidl/android/hardware/cas/Status.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <binder/ParcelFileDescriptor.h>
+#include <cutils/ashmem.h>
+#include <utils/Condition.h>
+#include <utils/Mutex.h>
+
+#define CLEAR_KEY_SYSTEM_ID 0xF6D8
+#define INVALID_SYSTEM_ID 0
+#define WAIT_TIMEOUT 3000000000
+
+#define PROVISION_STR \
+ "{ " \
+ " \"id\": 21140844, " \
+ " \"name\": \"Test Title\", " \
+ " \"lowercase_organization_name\": \"Android\", " \
+ " \"asset_key\": { " \
+ " \"encryption_key\": \"nezAr3CHFrmBR9R8Tedotw==\" " \
+ " }, " \
+ " \"cas_type\": 1, " \
+ " \"track_types\": [ ] " \
+ "} "
+
+using aidl::android::hardware::common::Ashmem;
+using android::Mutex;
+using namespace aidl::android::hardware::cas;
+using namespace ndk;
+using namespace std;
+using namespace testing;
+
+const uint8_t kEcmBinaryBuffer[] = {
+ 0x00, 0x00, 0x01, 0xf0, 0x00, 0x50, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x46, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x27, 0x10, 0x02, 0x00,
+ 0x01, 0x77, 0x01, 0x42, 0x95, 0x6c, 0x0e, 0xe3, 0x91, 0xbc, 0xfd, 0x05, 0xb1, 0x60, 0x4f,
+ 0x17, 0x82, 0xa4, 0x86, 0x9b, 0x23, 0x56, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x27, 0x10, 0x02, 0x00, 0x01, 0x77, 0x01, 0x42, 0x95, 0x6c, 0xd7, 0x43, 0x62, 0xf8, 0x1c,
+ 0x62, 0x19, 0x05, 0xc7, 0x3a, 0x42, 0xcd, 0xfd, 0xd9, 0x13, 0x48,
+};
+
+const SubSample kSubSamples[] = {{162, 0}, {0, 184}, {0, 184}};
+
+const uint8_t kInBinaryBuffer[] = {
+ 0x00, 0x00, 0x00, 0x01, 0x09, 0xf0, 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0xc0, 0x1e, 0xdb,
+ 0x01, 0x40, 0x16, 0xec, 0x04, 0x40, 0x00, 0x00, 0x03, 0x00, 0x40, 0x00, 0x00, 0x0f, 0x03,
+ 0xc5, 0x8b, 0xb8, 0x00, 0x00, 0x00, 0x01, 0x68, 0xca, 0x8c, 0xb2, 0x00, 0x00, 0x01, 0x06,
+ 0x05, 0xff, 0xff, 0x70, 0xdc, 0x45, 0xe9, 0xbd, 0xe6, 0xd9, 0x48, 0xb7, 0x96, 0x2c, 0xd8,
+ 0x20, 0xd9, 0x23, 0xee, 0xef, 0x78, 0x32, 0x36, 0x34, 0x20, 0x2d, 0x20, 0x63, 0x6f, 0x72,
+ 0x65, 0x20, 0x31, 0x34, 0x32, 0x20, 0x2d, 0x20, 0x48, 0x2e, 0x32, 0x36, 0x34, 0x2f, 0x4d,
+ 0x50, 0x45, 0x47, 0x2d, 0x34, 0x20, 0x41, 0x56, 0x43, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x63,
+ 0x20, 0x2d, 0x20, 0x43, 0x6f, 0x70, 0x79, 0x6c, 0x65, 0x66, 0x74, 0x20, 0x32, 0x30, 0x30,
+ 0x33, 0x2d, 0x32, 0x30, 0x31, 0x34, 0x20, 0x2d, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
+ 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x6c, 0x61, 0x6e, 0x2e, 0x6f,
+ 0x72, 0x67, 0x2f, 0x78, 0x32, 0x36, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x6e, 0x45, 0x21,
+ 0x82, 0x38, 0xf0, 0x9d, 0x7d, 0x96, 0xe6, 0x94, 0xae, 0xe2, 0x87, 0x8f, 0x04, 0x49, 0xe5,
+ 0xf6, 0x8c, 0x8b, 0x9a, 0x10, 0x18, 0xba, 0x94, 0xe9, 0x22, 0x31, 0x04, 0x7e, 0x60, 0x5b,
+ 0xc4, 0x24, 0x00, 0x90, 0x62, 0x0d, 0xdc, 0x85, 0x74, 0x75, 0x78, 0xd0, 0x14, 0x08, 0xcb,
+ 0x02, 0x1d, 0x7d, 0x9d, 0x34, 0xe8, 0x81, 0xb9, 0xf7, 0x09, 0x28, 0x79, 0x29, 0x8d, 0xe3,
+ 0x14, 0xed, 0x5f, 0xca, 0xaf, 0xf4, 0x1c, 0x49, 0x15, 0xe1, 0x80, 0x29, 0x61, 0x76, 0x80,
+ 0x43, 0xf8, 0x58, 0x53, 0x40, 0xd7, 0x31, 0x6d, 0x61, 0x81, 0x41, 0xe9, 0x77, 0x9f, 0x9c,
+ 0xe1, 0x6d, 0xf2, 0xee, 0xd9, 0xc8, 0x67, 0xd2, 0x5f, 0x48, 0x73, 0xe3, 0x5c, 0xcd, 0xa7,
+ 0x45, 0x58, 0xbb, 0xdd, 0x28, 0x1d, 0x68, 0xfc, 0xb4, 0xc6, 0xf6, 0x92, 0xf6, 0x30, 0x03,
+ 0xaa, 0xe4, 0x32, 0xf6, 0x34, 0x51, 0x4b, 0x0f, 0x8c, 0xf9, 0xac, 0x98, 0x22, 0xfb, 0x49,
+ 0xc8, 0xbf, 0xca, 0x8c, 0x80, 0x86, 0x5d, 0xd7, 0xa4, 0x52, 0xb1, 0xd9, 0xa6, 0x04, 0x4e,
+ 0xb3, 0x2d, 0x1f, 0xb8, 0x35, 0xcc, 0x45, 0x6d, 0x9c, 0x20, 0xa7, 0xa4, 0x34, 0x59, 0x72,
+ 0xe3, 0xae, 0xba, 0x49, 0xde, 0xd1, 0xaa, 0xee, 0x3d, 0x77, 0xfc, 0x5d, 0xc6, 0x1f, 0x9d,
+ 0xac, 0xc2, 0x15, 0x66, 0xb8, 0xe1, 0x54, 0x4e, 0x74, 0x93, 0xdb, 0x9a, 0x24, 0x15, 0x6e,
+ 0x20, 0xa3, 0x67, 0x3e, 0x5a, 0x24, 0x41, 0x5e, 0xb0, 0xe6, 0x35, 0x87, 0x1b, 0xc8, 0x7a,
+ 0xf9, 0x77, 0x65, 0xe0, 0x01, 0xf2, 0x4c, 0xe4, 0x2b, 0xa9, 0x64, 0x96, 0x96, 0x0b, 0x46,
+ 0xca, 0xea, 0x79, 0x0e, 0x78, 0xa3, 0x5f, 0x43, 0xfc, 0x47, 0x6a, 0x12, 0xfa, 0xc4, 0x33,
+ 0x0e, 0x88, 0x1c, 0x19, 0x3a, 0x00, 0xc3, 0x4e, 0xb5, 0xd8, 0xfa, 0x8e, 0xf1, 0xbc, 0x3d,
+ 0xb2, 0x7e, 0x50, 0x8d, 0x67, 0xc3, 0x6b, 0xed, 0xe2, 0xea, 0xa6, 0x1f, 0x25, 0x24, 0x7c,
+ 0x94, 0x74, 0x50, 0x49, 0xe3, 0xc6, 0x58, 0x2e, 0xfd, 0x28, 0xb4, 0xc6, 0x73, 0xb1, 0x53,
+ 0x74, 0x27, 0x94, 0x5c, 0xdf, 0x69, 0xb7, 0xa1, 0xd7, 0xf5, 0xd3, 0x8a, 0x2c, 0x2d, 0xb4,
+ 0x5e, 0x8a, 0x16, 0x14, 0x54, 0x64, 0x6e, 0x00, 0x6b, 0x11, 0x59, 0x8a, 0x63, 0x38, 0x80,
+ 0x76, 0xc3, 0xd5, 0x59, 0xf7, 0x3f, 0xd2, 0xfa, 0xa5, 0xca, 0x82, 0xff, 0x4a, 0x62, 0xf0,
+ 0xe3, 0x42, 0xf9, 0x3b, 0x38, 0x27, 0x8a, 0x89, 0xaa, 0x50, 0x55, 0x4b, 0x29, 0xf1, 0x46,
+ 0x7c, 0x75, 0xef, 0x65, 0xaf, 0x9b, 0x0d, 0x6d, 0xda, 0x25, 0x94, 0x14, 0xc1, 0x1b, 0xf0,
+ 0xc5, 0x4c, 0x24, 0x0e, 0x65,
+};
+
+const uint8_t kOutRefBinaryBuffer[] = {
+ 0x00, 0x00, 0x00, 0x01, 0x09, 0xf0, 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0xc0, 0x1e, 0xdb,
+ 0x01, 0x40, 0x16, 0xec, 0x04, 0x40, 0x00, 0x00, 0x03, 0x00, 0x40, 0x00, 0x00, 0x0f, 0x03,
+ 0xc5, 0x8b, 0xb8, 0x00, 0x00, 0x00, 0x01, 0x68, 0xca, 0x8c, 0xb2, 0x00, 0x00, 0x01, 0x06,
+ 0x05, 0xff, 0xff, 0x70, 0xdc, 0x45, 0xe9, 0xbd, 0xe6, 0xd9, 0x48, 0xb7, 0x96, 0x2c, 0xd8,
+ 0x20, 0xd9, 0x23, 0xee, 0xef, 0x78, 0x32, 0x36, 0x34, 0x20, 0x2d, 0x20, 0x63, 0x6f, 0x72,
+ 0x65, 0x20, 0x31, 0x34, 0x32, 0x20, 0x2d, 0x20, 0x48, 0x2e, 0x32, 0x36, 0x34, 0x2f, 0x4d,
+ 0x50, 0x45, 0x47, 0x2d, 0x34, 0x20, 0x41, 0x56, 0x43, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x63,
+ 0x20, 0x2d, 0x20, 0x43, 0x6f, 0x70, 0x79, 0x6c, 0x65, 0x66, 0x74, 0x20, 0x32, 0x30, 0x30,
+ 0x33, 0x2d, 0x32, 0x30, 0x31, 0x34, 0x20, 0x2d, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
+ 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x6c, 0x61, 0x6e, 0x2e, 0x6f,
+ 0x72, 0x67, 0x2f, 0x78, 0x32, 0x36, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20, 0x2d, 0x20,
+ 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3a, 0x20, 0x63, 0x61, 0x62, 0x61, 0x63, 0x3d,
+ 0x30, 0x20, 0x72, 0x65, 0x66, 0x3d, 0x32, 0x20, 0x64, 0x65, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
+ 0x3d, 0x31, 0x3a, 0x30, 0x3a, 0x30, 0x20, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x65, 0x3d,
+ 0x30, 0x78, 0x31, 0x3a, 0x30, 0x78, 0x31, 0x31, 0x31, 0x20, 0x6d, 0x65, 0x3d, 0x68, 0x65,
+ 0x78, 0x20, 0x73, 0x75, 0x62, 0x6d, 0x65, 0x3d, 0x37, 0x20, 0x70, 0x73, 0x79, 0x3d, 0x31,
+ 0x20, 0x70, 0x73, 0x79, 0x5f, 0x72, 0x64, 0x3d, 0x31, 0x2e, 0x30, 0x30, 0x3a, 0x30, 0x2e,
+ 0x30, 0x30, 0x20, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x66, 0x3d, 0x31, 0x20,
+ 0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x3d, 0x31, 0x36, 0x20, 0x63, 0x68, 0x72,
+ 0x6f, 0x6d, 0x61, 0x5f, 0x6d, 0x65, 0x3d, 0x31, 0x20, 0x74, 0x72, 0x65, 0x6c, 0x6c, 0x69,
+ 0x73, 0x3d, 0x31, 0x20, 0x38, 0x78, 0x38, 0x64, 0x63, 0x74, 0x3d, 0x30, 0x20, 0x63, 0x71,
+ 0x6d, 0x3d, 0x30, 0x20, 0x64, 0x65, 0x61, 0x64, 0x7a, 0x6f, 0x6e, 0x65, 0x3d, 0x32, 0x31,
+ 0x2c, 0x31, 0x31, 0x20, 0x66, 0x61, 0x73, 0x74, 0x5f, 0x70, 0x73, 0x6b, 0x69, 0x70, 0x3d,
+ 0x31, 0x20, 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x61, 0x5f, 0x71, 0x70, 0x5f, 0x6f, 0x66, 0x66,
+ 0x73, 0x65, 0x74, 0x3d, 0x2d, 0x32, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d,
+ 0x36, 0x30, 0x20, 0x6c, 0x6f, 0x6f, 0x6b, 0x61, 0x68, 0x65, 0x61, 0x64, 0x5f, 0x74, 0x68,
+ 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x35, 0x20, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x64, 0x5f,
+ 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x30, 0x20, 0x6e, 0x72, 0x3d, 0x30, 0x20,
+ 0x64, 0x65, 0x63, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x3d, 0x31, 0x20, 0x69, 0x6e, 0x74, 0x65,
+ 0x72, 0x6c, 0x61, 0x63, 0x65, 0x64, 0x3d, 0x30, 0x20, 0x62, 0x6c, 0x75, 0x72, 0x61, 0x79,
+ 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x3d, 0x30, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74,
+ 0x72, 0x61, 0x69, 0x6e, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x74, 0x72, 0x61, 0x3d, 0x30, 0x20,
+ 0x62, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x3d, 0x30, 0x20, 0x77, 0x65, 0x69, 0x67, 0x68,
+ 0x74, 0x70, 0x3d, 0x30, 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x3d, 0x32, 0x35, 0x30,
+ 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x3d, 0x32, 0x35, 0x20,
+ 0x73, 0x63, 0x65, 0x6e, 0x65,
+};
+
+class MediaCasListener : public BnCasListener {
+ public:
+ virtual ScopedAStatus onEvent(int32_t event, int32_t arg,
+ const vector<uint8_t>& data) override {
+ Mutex::Autolock autoLock(mMsgLock);
+ mEvent = event;
+ mEventArg = arg;
+ mEventData = data;
+
+ mEventReceived = true;
+ mMsgCondition.signal();
+ return ScopedAStatus::ok();
+ }
+
+ virtual ScopedAStatus onSessionEvent(const vector<uint8_t>& sessionId, int32_t event,
+ int32_t arg, const vector<uint8_t>& data) override {
+ Mutex::Autolock autoLock(mMsgLock);
+ mSessionId = sessionId;
+ mEvent = event;
+ mEventArg = arg;
+ mEventData = data;
+
+ mEventReceived = true;
+ mMsgCondition.signal();
+ return ScopedAStatus::ok();
+ }
+
+ virtual ScopedAStatus onStatusUpdate(StatusEvent event, int32_t arg) override {
+ Mutex::Autolock autoLock(mMsgLock);
+ mStatusEvent = event;
+ mEventArg = arg;
+
+ mEventReceived = true;
+ mMsgCondition.signal();
+ return ScopedAStatus::ok();
+ }
+
+ void testEventEcho(shared_ptr<ICas>& mediaCas, int32_t& event, int32_t& eventArg,
+ vector<uint8_t>& eventData);
+
+ void testSessionEventEcho(shared_ptr<ICas>& mediaCas, const vector<uint8_t>& sessionId,
+ int32_t& event, int32_t& eventArg, vector<uint8_t>& eventData);
+
+ void testStatusUpdate(shared_ptr<ICas>& mediaCas, vector<uint8_t>* sessionId,
+ SessionIntent intent, ScramblingMode mode);
+
+ private:
+ int32_t mEvent = -1;
+ int32_t mEventArg = -1;
+ StatusEvent mStatusEvent;
+ bool mEventReceived = false;
+ vector<uint8_t> mEventData;
+ vector<uint8_t> mSessionId;
+ Mutex mMsgLock;
+ android::Condition mMsgCondition;
+};
+
+void MediaCasListener::testEventEcho(shared_ptr<ICas>& mediaCas, int32_t& event, int32_t& eventArg,
+ vector<uint8_t>& eventData) {
+ mEventReceived = false;
+ auto returnStatus = mediaCas->sendEvent(event, eventArg, eventData);
+ EXPECT_TRUE(returnStatus.isOk());
+
+ Mutex::Autolock autoLock(mMsgLock);
+ while (!mEventReceived) {
+ if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+ ADD_FAILURE() << "event not received within timeout";
+ return;
+ }
+ }
+
+ EXPECT_EQ(mEvent, event);
+ EXPECT_EQ(mEventArg, eventArg);
+ EXPECT_TRUE(mEventData == eventData);
+}
+
+void MediaCasListener::testSessionEventEcho(shared_ptr<ICas>& mediaCas,
+ const vector<uint8_t>& sessionId, int32_t& event,
+ int32_t& eventArg, vector<uint8_t>& eventData) {
+ mEventReceived = false;
+ EXPECT_TRUE(mediaCas->sendSessionEvent(sessionId, event, eventArg, eventData).isOk());
+
+ Mutex::Autolock autoLock(mMsgLock);
+ while (!mEventReceived) {
+ if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+ ADD_FAILURE() << "event not received within timeout";
+ return;
+ }
+ }
+
+ EXPECT_TRUE(mSessionId == sessionId);
+ EXPECT_EQ(mEvent, event);
+ EXPECT_EQ(mEventArg, eventArg);
+ EXPECT_TRUE(mEventData == eventData);
+}
+
+void MediaCasListener::testStatusUpdate(shared_ptr<ICas>& mediaCas, vector<uint8_t>* sessionId,
+ SessionIntent intent, ScramblingMode mode) {
+ mEventReceived = false;
+ EXPECT_TRUE(mediaCas->openSession(intent, mode, sessionId).isOk());
+
+ Mutex::Autolock autoLock(mMsgLock);
+ while (!mEventReceived) {
+ if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+ ADD_FAILURE() << "event not received within timeout";
+ return;
+ }
+ }
+ EXPECT_EQ(mStatusEvent, static_cast<StatusEvent>(intent));
+ EXPECT_EQ(mEventArg, static_cast<int32_t>(mode));
+}
+
+class MediaCasAidlTest : public testing::TestWithParam<string> {
+ public:
+ virtual void SetUp() override {
+ if (AServiceManager_isDeclared(GetParam().c_str())) {
+ SpAIBinder binder(AServiceManager_waitForService(GetParam().c_str()));
+ mService = IMediaCasService::fromBinder(binder);
+ } else {
+ mService = nullptr;
+ }
+ ASSERT_NE(mService, nullptr);
+ }
+
+ shared_ptr<IMediaCasService> mService = nullptr;
+
+ protected:
+ static void description(const string& description) {
+ RecordProperty("description", description);
+ }
+
+ shared_ptr<ICas> mMediaCas;
+ shared_ptr<IDescrambler> mDescrambler;
+ shared_ptr<MediaCasListener> mCasListener;
+ typedef struct _OobInputTestParams {
+ const SubSample* subSamples;
+ int32_t numSubSamples;
+ int64_t imemSizeActual;
+ int64_t imemOffset;
+ int64_t imemSize;
+ int64_t srcOffset;
+ int64_t dstOffset;
+ } OobInputTestParams;
+
+ AssertionResult createCasPlugin(int32_t caSystemId);
+ AssertionResult openCasSession(vector<uint8_t>* sessionId, SessionIntent intent,
+ ScramblingMode mode);
+ AssertionResult descrambleTestInputBuffer(const shared_ptr<IDescrambler>& descrambler,
+ ScopedAStatus& descrambleStatus, uint8_t*& inMemory);
+ AssertionResult descrambleTestOobInput(const shared_ptr<IDescrambler>& descrambler,
+ ScopedAStatus& descrambleStatus,
+ const OobInputTestParams& params);
+};
+
+AssertionResult MediaCasAidlTest::createCasPlugin(int32_t caSystemId) {
+ bool isSystemIdSupported;
+ auto status = mService->isSystemIdSupported(caSystemId, &isSystemIdSupported);
+ bool skipDescrambler = false;
+ if (!status.isOk() || !isSystemIdSupported) {
+ return AssertionFailure();
+ }
+ bool isDescramblerSupported;
+ status = mService->isDescramblerSupported(caSystemId, &isDescramblerSupported);
+ if (!status.isOk() || !isDescramblerSupported) {
+ ALOGI("Skip Descrambler test since it's not required in cas.");
+ mDescrambler = nullptr;
+ skipDescrambler = true;
+ }
+
+ mCasListener = SharedRefBase::make<MediaCasListener>();
+ status = mService->createPlugin(caSystemId, mCasListener, &mMediaCas);
+ if (!status.isOk()) {
+ return AssertionFailure();
+ }
+ if (mMediaCas == nullptr) {
+ return AssertionFailure();
+ }
+
+ if (skipDescrambler) {
+ return AssertionSuccess();
+ }
+
+ status = mService->createDescrambler(caSystemId, &mDescrambler);
+ if (!status.isOk()) {
+ return AssertionFailure();
+ }
+
+ return AssertionResult(mDescrambler != nullptr);
+}
+
+AssertionResult MediaCasAidlTest::openCasSession(vector<uint8_t>* sessionId, SessionIntent intent,
+ ScramblingMode mode) {
+ return AssertionResult(mMediaCas->openSession(intent, mode, sessionId).isOk());
+}
+
+AssertionResult MediaCasAidlTest::descrambleTestInputBuffer(
+ const shared_ptr<IDescrambler>& descrambler, ScopedAStatus& descrambleStatus,
+ uint8_t*& sharedMemory) {
+ vector<SubSample> subSample(kSubSamples,
+ kSubSamples + (sizeof(kSubSamples) / sizeof(SubSample)));
+
+ int size = sizeof(kInBinaryBuffer);
+ auto fd = ashmem_create_region("vts-cas", size);
+ if (fd < 0) {
+ ALOGE("ashmem_create_region failed");
+ return AssertionFailure();
+ }
+
+ sharedMemory =
+ static_cast<uint8_t*>(mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
+ if (sharedMemory == reinterpret_cast<uint8_t*>(MAP_FAILED)) {
+ ALOGE("mmap failed");
+ return AssertionFailure();
+ }
+
+ memcpy(sharedMemory, kInBinaryBuffer, size);
+
+ auto dupFd = dup(fd);
+
+ SharedBuffer srcBuffer = {.heapBase.fd = ScopedFileDescriptor(std::move(fd)),
+ .heapBase.size = size,
+ .offset = 0,
+ .size = size};
+
+ SharedBuffer dupBuffer = {.heapBase.fd = ScopedFileDescriptor(dupFd),
+ .heapBase.size = size,
+ .offset = 0,
+ .size = size};
+
+ DestinationBuffer dstBuffer;
+ dstBuffer.set<DestinationBuffer::nonsecureMemory>(std::move(dupBuffer));
+
+ int32_t outBytes;
+ descrambleStatus = descrambler->descramble(ScramblingControl::EVENKEY /*2*/, subSample,
+ srcBuffer, 0, dstBuffer, 0, &outBytes);
+ if (!descrambleStatus.isOk()) {
+ ALOGI("descramble failed, status=%d, outBytes=%u, error=%s", descrambleStatus.getStatus(),
+ outBytes, descrambleStatus.getDescription().c_str());
+ }
+ return AssertionResult(descrambleStatus.isOk());
+}
+
+AssertionResult MediaCasAidlTest::descrambleTestOobInput(
+ const shared_ptr<IDescrambler>& descrambler, ScopedAStatus& descrambleStatus,
+ const OobInputTestParams& params) {
+ vector<SubSample> subSample(params.subSamples, params.subSamples + params.numSubSamples);
+
+ auto fd = ashmem_create_region("vts-cas", params.imemSizeActual);
+ if (fd < 0) {
+ ALOGE("ashmem_create_region failed");
+ return AssertionFailure();
+ }
+
+ auto dupFd = dup(fd);
+
+ SharedBuffer srcBuffer = {.heapBase.fd = ScopedFileDescriptor(std::move(fd)),
+ .heapBase.size = params.imemSizeActual,
+ .offset = params.imemOffset,
+ .size = params.imemSize};
+
+ SharedBuffer dupBuffer = {.heapBase.fd = ScopedFileDescriptor(dupFd),
+ .heapBase.size = params.imemSizeActual,
+ .offset = params.imemOffset,
+ .size = params.imemSize};
+
+ DestinationBuffer dstBuffer;
+ dstBuffer.set<DestinationBuffer::nonsecureMemory>(std::move(dupBuffer));
+
+ int32_t outBytes;
+ descrambleStatus =
+ descrambler->descramble(ScramblingControl::EVENKEY /*2*/, subSample, srcBuffer,
+ params.srcOffset, dstBuffer, params.dstOffset, &outBytes);
+ if (!descrambleStatus.isOk()) {
+ ALOGI("descramble failed, status=%d, outBytes=%u, error=%s", descrambleStatus.getStatus(),
+ outBytes, descrambleStatus.getDescription().c_str());
+ }
+ return AssertionResult(descrambleStatus.isOk());
+}
+
+TEST_P(MediaCasAidlTest, EnumeratePlugins) {
+ description("Test enumerate plugins");
+
+ vector<AidlCasPluginDescriptor> descriptors;
+ EXPECT_TRUE(mService->enumeratePlugins(&descriptors).isOk());
+
+ if (descriptors.size() == 0) {
+ ALOGW("[ WARN ] enumeratePlugins list empty");
+ return;
+ }
+
+ for (size_t i = 0; i < descriptors.size(); i++) {
+ int32_t caSystemId = descriptors[i].caSystemId;
+
+ ASSERT_TRUE(createCasPlugin(caSystemId));
+ }
+}
+
+TEST_P(MediaCasAidlTest, TestInvalidSystemIdFails) {
+ description("Test failure for invalid system ID");
+
+ bool isSystemIdSupported;
+ auto status = mService->isSystemIdSupported(INVALID_SYSTEM_ID, &isSystemIdSupported);
+
+ EXPECT_TRUE(status.isOk());
+ ASSERT_FALSE(isSystemIdSupported);
+
+ bool isDescramblerSupported;
+ status = mService->isDescramblerSupported(INVALID_SYSTEM_ID, &isDescramblerSupported);
+
+ EXPECT_TRUE(status.isOk());
+ ASSERT_FALSE(isDescramblerSupported);
+
+ shared_ptr<ICas> mediaCas;
+ shared_ptr<MediaCasListener> casListener = SharedRefBase::make<MediaCasListener>();
+ status = mService->createPlugin(INVALID_SYSTEM_ID, casListener, &mediaCas);
+ ASSERT_TRUE(status.isOk());
+ EXPECT_EQ(mediaCas, nullptr);
+
+ shared_ptr<IDescrambler> descrambler;
+ status = mService->createDescrambler(INVALID_SYSTEM_ID, &descrambler);
+ ASSERT_TRUE(status.isOk());
+ EXPECT_EQ(descrambler, nullptr);
+}
+
+TEST_P(MediaCasAidlTest, TestClearKeyPluginInstalled) {
+ description("Test if ClearKey plugin is installed");
+
+ vector<AidlCasPluginDescriptor> descriptors;
+ EXPECT_TRUE(mService->enumeratePlugins(&descriptors).isOk());
+
+ if (descriptors.size() == 0) {
+ ALOGW("[ WARN ] enumeratePlugins list empty");
+ }
+
+ for (size_t i = 0; i < descriptors.size(); i++) {
+ int32_t caSystemId = descriptors[i].caSystemId;
+ if (CLEAR_KEY_SYSTEM_ID == caSystemId) {
+ return;
+ }
+ }
+
+ ADD_FAILURE() << "ClearKey plugin not installed";
+}
+
+TEST_P(MediaCasAidlTest, TestClearKeySessionClosedAfterRelease) {
+ description("Test that all sessions are closed after a MediaCas object is released");
+
+ ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID));
+
+ EXPECT_TRUE(mMediaCas->provision(PROVISION_STR).isOk());
+
+ SessionIntent intent = SessionIntent::LIVE;
+ ScramblingMode mode = ScramblingMode::DVB_CSA1;
+
+ vector<uint8_t> sessionId;
+ ASSERT_TRUE(openCasSession(&sessionId, intent, mode));
+
+ vector<uint8_t> streamSessionId;
+ ASSERT_TRUE(openCasSession(&streamSessionId, intent, mode));
+
+ EXPECT_TRUE(mMediaCas->release().isOk());
+
+ if (mDescrambler != nullptr) {
+ auto status = mDescrambler->setMediaCasSession(sessionId);
+ EXPECT_FALSE(status.isOk());
+ EXPECT_EQ(Status::ERROR_CAS_SESSION_NOT_OPENED, status.getServiceSpecificError());
+
+ status = mDescrambler->setMediaCasSession(streamSessionId);
+ EXPECT_FALSE(status.isOk());
+ EXPECT_EQ(Status::ERROR_CAS_SESSION_NOT_OPENED, status.getServiceSpecificError());
+ }
+}
+
+TEST_P(MediaCasAidlTest, TestClearKeyErrors) {
+ description("Test that invalid call sequences fail with expected error codes");
+
+ ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID));
+
+ /*
+ * Test MediaCas error codes
+ */
+ // Provision should fail with an invalid asset string
+ auto returnStatus = mMediaCas->provision("invalid asset string");
+ EXPECT_FALSE(returnStatus.isOk());
+ EXPECT_EQ(Status::ERROR_CAS_NO_LICENSE, returnStatus.getServiceSpecificError());
+
+ SessionIntent intent = SessionIntent::LIVE;
+ ScramblingMode mode = ScramblingMode::DVB_CSA1;
+
+ // Open a session, then close it so that it should become invalid
+ vector<uint8_t> invalidSessionId;
+ ASSERT_TRUE(openCasSession(&invalidSessionId, intent, mode));
+ EXPECT_TRUE(mMediaCas->closeSession(invalidSessionId).isOk());
+
+ // processEcm should fail with an invalid session id
+ vector<uint8_t> ecm(kEcmBinaryBuffer, kEcmBinaryBuffer + sizeof(kEcmBinaryBuffer));
+ returnStatus = mMediaCas->processEcm(invalidSessionId, ecm);
+ EXPECT_FALSE(returnStatus.isOk());
+ EXPECT_EQ(Status::ERROR_CAS_SESSION_NOT_OPENED, returnStatus.getServiceSpecificError());
+
+ vector<uint8_t> sessionId;
+ ASSERT_TRUE(openCasSession(&sessionId, intent, mode));
+
+ // processEcm should fail without provisioning
+ returnStatus = mMediaCas->processEcm(sessionId, ecm);
+ EXPECT_FALSE(returnStatus.isOk());
+ EXPECT_EQ(Status::ERROR_CAS_NOT_PROVISIONED, returnStatus.getServiceSpecificError());
+
+ EXPECT_TRUE(mMediaCas->provision(PROVISION_STR).isOk());
+
+ // processEcm should fail with ecm with bad descriptor count
+ ecm[17] = 0x03; // change the descriptor count field to 3 (invalid)
+ returnStatus = mMediaCas->processEcm(sessionId, ecm);
+ EXPECT_FALSE(returnStatus.isOk());
+ EXPECT_EQ(Status::ERROR_CAS_UNKNOWN, returnStatus.getServiceSpecificError());
+
+ // processEcm should fail with ecm buffer that's too short
+ ecm.resize(8);
+ returnStatus = mMediaCas->processEcm(sessionId, ecm);
+ EXPECT_FALSE(returnStatus.isOk());
+ EXPECT_EQ(Status::BAD_VALUE, returnStatus.getServiceSpecificError());
+
+ if (mDescrambler != nullptr) {
+ /*
+ * Test MediaDescrambler error codes
+ */
+ // setMediaCasSession should fail with an invalid session id
+ returnStatus = mDescrambler->setMediaCasSession(invalidSessionId);
+ EXPECT_FALSE(returnStatus.isOk());
+ EXPECT_EQ(Status::ERROR_CAS_SESSION_NOT_OPENED, returnStatus.getServiceSpecificError());
+
+ // descramble should fail without a valid session
+ ScopedAStatus descrambleStatus = ScopedAStatus::ok();
+ uint8_t* sharedBuffer = nullptr;
+
+ ASSERT_FALSE(descrambleTestInputBuffer(mDescrambler, descrambleStatus, sharedBuffer));
+ EXPECT_EQ(Status::ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED,
+ descrambleStatus.getServiceSpecificError());
+
+ // Now set a valid session, should still fail because no valid ecm is processed
+ EXPECT_TRUE(mDescrambler->setMediaCasSession(sessionId).isOk());
+ ASSERT_FALSE(descrambleTestInputBuffer(mDescrambler, descrambleStatus, sharedBuffer));
+ EXPECT_EQ(Status::ERROR_CAS_DECRYPT, descrambleStatus.getServiceSpecificError());
+
+ // Verify that requiresSecureDecoderComponent handles empty mime
+ bool requiresSecureDecoderComponent = true;
+ EXPECT_TRUE(
+ mDescrambler->requiresSecureDecoderComponent("", &requiresSecureDecoderComponent)
+ .isOk());
+ EXPECT_FALSE(requiresSecureDecoderComponent);
+
+ // Verify that requiresSecureDecoderComponent handles invalid mime
+ requiresSecureDecoderComponent = true;
+ EXPECT_TRUE(
+ mDescrambler->requiresSecureDecoderComponent("bad", &requiresSecureDecoderComponent)
+ .isOk());
+ EXPECT_FALSE(requiresSecureDecoderComponent);
+ }
+}
+
+TEST_P(MediaCasAidlTest, TestClearKeyApisWithSession) {
+ description("Test that valid call sequences with SessionEvent send and receive");
+
+ ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID));
+
+ EXPECT_TRUE(mMediaCas->provision(PROVISION_STR).isOk());
+
+ vector<uint8_t> pvtData;
+ pvtData.resize(256);
+ EXPECT_TRUE(mMediaCas->setPrivateData(pvtData).isOk());
+
+ SessionIntent intent = SessionIntent::LIVE;
+ ScramblingMode mode = ScramblingMode::DVB_CSA1;
+
+ vector<uint8_t> sessionId;
+ ASSERT_TRUE(openCasSession(&sessionId, intent, mode));
+ EXPECT_TRUE(mMediaCas->setSessionPrivateData(sessionId, pvtData).isOk());
+
+ vector<uint8_t> streamSessionId;
+ ASSERT_TRUE(openCasSession(&streamSessionId, intent, mode));
+ EXPECT_TRUE(mMediaCas->setSessionPrivateData(streamSessionId, pvtData).isOk());
+
+ if (mDescrambler != nullptr) {
+ EXPECT_TRUE(mDescrambler->setMediaCasSession(sessionId).isOk());
+ EXPECT_TRUE(mDescrambler->setMediaCasSession(streamSessionId).isOk());
+ }
+
+ vector<uint8_t> nullPtrVector(0);
+ EXPECT_TRUE(mMediaCas->refreshEntitlements(3, nullPtrVector).isOk());
+
+ vector<uint8_t> refreshData{0, 1, 2, 3};
+ EXPECT_TRUE(mMediaCas->refreshEntitlements(10, refreshData).isOk());
+
+ int32_t eventID = 1;
+ int32_t eventArg = 2;
+ mCasListener->testEventEcho(mMediaCas, eventID, eventArg, nullPtrVector);
+ mCasListener->testSessionEventEcho(mMediaCas, sessionId, eventID, eventArg, nullPtrVector);
+
+ eventID = 3;
+ eventArg = 4;
+ vector<uint8_t> eventData{'e', 'v', 'e', 'n', 't', 'd', 'a', 't', 'a'};
+ mCasListener->testEventEcho(mMediaCas, eventID, eventArg, eventData);
+ mCasListener->testSessionEventEcho(mMediaCas, sessionId, eventID, eventArg, eventData);
+
+ mCasListener->testStatusUpdate(mMediaCas, &sessionId, intent, mode);
+
+ vector<uint8_t> clearKeyEmmData{'c', 'l', 'e', 'a', 'r', 'k', 'e', 'y', 'e', 'm', 'm'};
+ EXPECT_TRUE(mMediaCas->processEmm(clearKeyEmmData).isOk());
+
+ vector<uint8_t> ecm(kEcmBinaryBuffer, kEcmBinaryBuffer + sizeof(kEcmBinaryBuffer));
+ EXPECT_TRUE(mMediaCas->processEcm(sessionId, ecm).isOk());
+ EXPECT_TRUE(mMediaCas->processEcm(streamSessionId, ecm).isOk());
+
+ if (mDescrambler != nullptr) {
+ bool requiresSecureDecoderComponent = true;
+ EXPECT_TRUE(mDescrambler
+ ->requiresSecureDecoderComponent("video/avc",
+ &requiresSecureDecoderComponent)
+ .isOk());
+ EXPECT_FALSE(requiresSecureDecoderComponent);
+
+ ScopedAStatus descrambleStatus = ScopedAStatus::ok();
+ uint8_t* sharedBuffer = nullptr;
+
+ ASSERT_TRUE(descrambleTestInputBuffer(mDescrambler, descrambleStatus, sharedBuffer));
+
+ int compareResult =
+ memcmp(static_cast<const void*>(sharedBuffer),
+ static_cast<const void*>(kOutRefBinaryBuffer), sizeof(kOutRefBinaryBuffer));
+ EXPECT_EQ(0, compareResult);
+
+ EXPECT_TRUE(mDescrambler->release().isOk());
+ }
+
+ EXPECT_TRUE(mMediaCas->release().isOk());
+}
+
+TEST_P(MediaCasAidlTest, TestClearKeyOobFails) {
+ description("Test that oob descramble request fails with expected error");
+
+ ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID));
+ EXPECT_TRUE(mMediaCas->provision(PROVISION_STR).isOk());
+
+ SessionIntent intent = SessionIntent::LIVE;
+ ScramblingMode mode = ScramblingMode::DVB_CSA1;
+
+ vector<uint8_t> sessionId;
+ ASSERT_TRUE(openCasSession(&sessionId, intent, mode));
+
+ if (mDescrambler != nullptr) {
+ EXPECT_TRUE(mDescrambler->setMediaCasSession(sessionId).isOk());
+ }
+
+ vector<uint8_t> ecm(kEcmBinaryBuffer, kEcmBinaryBuffer + sizeof(kEcmBinaryBuffer));
+ EXPECT_TRUE(mMediaCas->processEcm(sessionId, ecm).isOk());
+
+ if (mDescrambler != nullptr) {
+ ScopedAStatus descrambleStatus = ScopedAStatus::ok();
+
+ // test invalid src buffer offset
+ ASSERT_FALSE(
+ descrambleTestOobInput(mDescrambler, descrambleStatus,
+ {.subSamples = kSubSamples,
+ .numSubSamples = sizeof(kSubSamples) / sizeof(SubSample),
+ .imemSizeActual = sizeof(kInBinaryBuffer),
+ .imemOffset = 0xcccccc,
+ .imemSize = sizeof(kInBinaryBuffer),
+ .srcOffset = 0,
+ .dstOffset = 0}));
+ EXPECT_EQ(Status::BAD_VALUE, descrambleStatus.getServiceSpecificError());
+
+ // test invalid src buffer size
+ ASSERT_FALSE(
+ descrambleTestOobInput(mDescrambler, descrambleStatus,
+ {.subSamples = kSubSamples,
+ .numSubSamples = sizeof(kSubSamples) / sizeof(SubSample),
+ .imemSizeActual = sizeof(kInBinaryBuffer),
+ .imemOffset = 0,
+ .imemSize = 0xcccccc,
+ .srcOffset = 0,
+ .dstOffset = 0}));
+ EXPECT_EQ(Status::BAD_VALUE, descrambleStatus.getServiceSpecificError());
+
+ // test invalid src buffer size
+ ASSERT_FALSE(
+ descrambleTestOobInput(mDescrambler, descrambleStatus,
+ {.subSamples = kSubSamples,
+ .numSubSamples = sizeof(kSubSamples) / sizeof(SubSample),
+ .imemSizeActual = sizeof(kInBinaryBuffer),
+ .imemOffset = 1,
+ .imemSize = -1,
+ .srcOffset = 0,
+ .dstOffset = 0}));
+ EXPECT_EQ(Status::BAD_VALUE, descrambleStatus.getServiceSpecificError());
+
+ // test invalid srcOffset
+ ASSERT_FALSE(
+ descrambleTestOobInput(mDescrambler, descrambleStatus,
+ {.subSamples = kSubSamples,
+ .numSubSamples = sizeof(kSubSamples) / sizeof(SubSample),
+ .imemSizeActual = sizeof(kInBinaryBuffer),
+ .imemOffset = 0,
+ .imemSize = sizeof(kInBinaryBuffer),
+ .srcOffset = 0xcccccc,
+ .dstOffset = 0}));
+ EXPECT_EQ(Status::BAD_VALUE, descrambleStatus.getServiceSpecificError());
+
+ // test invalid dstOffset
+ ASSERT_FALSE(
+ descrambleTestOobInput(mDescrambler, descrambleStatus,
+ {.subSamples = kSubSamples,
+ .numSubSamples = sizeof(kSubSamples) / sizeof(SubSample),
+ .imemSizeActual = sizeof(kInBinaryBuffer),
+ .imemOffset = 0,
+ .imemSize = sizeof(kInBinaryBuffer),
+ .srcOffset = 0,
+ .dstOffset = 0xcccccc}));
+ EXPECT_EQ(Status::BAD_VALUE, descrambleStatus.getServiceSpecificError());
+
+ // test detection of oob subsample sizes
+ const SubSample invalidSubSamples1[] = {{162, 0}, {0, 184}, {0, 0xdddddd}};
+
+ ASSERT_FALSE(descrambleTestOobInput(
+ mDescrambler, descrambleStatus,
+ {.subSamples = invalidSubSamples1,
+ .numSubSamples = sizeof(invalidSubSamples1) / sizeof(SubSample),
+ .imemSizeActual = sizeof(kInBinaryBuffer),
+ .imemOffset = 0,
+ .imemSize = sizeof(kInBinaryBuffer),
+ .srcOffset = 0,
+ .dstOffset = 0}));
+ EXPECT_EQ(Status::BAD_VALUE, descrambleStatus.getServiceSpecificError());
+
+ // test detection of overflowing subsample sizes
+ const SubSample invalidSubSamples2[] = {{162, 0}, {0, 184}, {2, -1}};
+
+ ASSERT_FALSE(descrambleTestOobInput(
+ mDescrambler, descrambleStatus,
+ {.subSamples = invalidSubSamples2,
+ .numSubSamples = sizeof(invalidSubSamples2) / sizeof(SubSample),
+ .imemSizeActual = sizeof(kInBinaryBuffer),
+ .imemOffset = 0,
+ .imemSize = sizeof(kInBinaryBuffer),
+ .srcOffset = 0,
+ .dstOffset = 0}));
+ EXPECT_EQ(Status::BAD_VALUE, descrambleStatus.getServiceSpecificError());
+
+ EXPECT_TRUE(mDescrambler->release().isOk());
+ }
+ EXPECT_TRUE(mMediaCas->release().isOk());
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MediaCasAidlTest);
+
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, MediaCasAidlTest,
+ testing::ValuesIn(android::getAidlHalInstanceNames(IMediaCasService::descriptor)),
+ android::PrintInstanceNameToString);
+
+// Start thread pool to receive callbacks from AIDL service.
+int main(int argc, char** argv) {
+ InitGoogleTest(&argc, argv);
+ ABinderProcess_setThreadPoolMaxThreadCount(1);
+ ABinderProcess_startThreadPool();
+ return RUN_ALL_TESTS();
+}
diff --git a/common/aidl/Android.bp b/common/aidl/Android.bp
index 549d970..7f6890c 100644
--- a/common/aidl/Android.bp
+++ b/common/aidl/Android.bp
@@ -30,13 +30,14 @@
ndk: {
apex_available: [
"//apex_available:platform",
- "com.android.bluetooth",
+ "com.android.btservices",
"com.android.media.swcodec",
"com.android.neuralnetworks",
],
min_sdk_version: "29",
},
},
+ frozen: true,
versions: [
"1",
"2",
diff --git a/common/fmq/aidl/Android.bp b/common/fmq/aidl/Android.bp
index 6fd4200..95fcc41 100644
--- a/common/fmq/aidl/Android.bp
+++ b/common/fmq/aidl/Android.bp
@@ -32,10 +32,11 @@
ndk: {
apex_available: [
"//apex_available:platform",
- "com.android.bluetooth",
+ "com.android.btservices",
],
min_sdk_version: "29",
},
},
+ frozen: true,
versions: ["1"],
}
diff --git a/common/support/NativeHandle.cpp b/common/support/NativeHandle.cpp
index 321d7a8..126ef2e 100644
--- a/common/support/NativeHandle.cpp
+++ b/common/support/NativeHandle.cpp
@@ -22,6 +22,13 @@
using aidl::android::hardware::common::NativeHandle;
+/**
+ * Checks if a NativeHandle is null
+ */
+bool isAidlNativeHandleEmpty(const NativeHandle& handle) {
+ return handle.fds.empty() && handle.ints.empty();
+}
+
static native_handle_t* fromAidl(const NativeHandle& handle, bool doDup) {
native_handle_t* to = native_handle_create(handle.fds.size(), handle.ints.size());
if (!to) return nullptr;
diff --git a/common/support/include/aidlcommonsupport/NativeHandle.h b/common/support/include/aidlcommonsupport/NativeHandle.h
index 10eecba..b5ea1dd 100644
--- a/common/support/include/aidlcommonsupport/NativeHandle.h
+++ b/common/support/include/aidlcommonsupport/NativeHandle.h
@@ -22,6 +22,11 @@
namespace android {
/**
+ * Checks if a NativeHandle is empty.
+ */
+bool isAidlNativeHandleEmpty(const aidl::android::hardware::common::NativeHandle& handle);
+
+/**
* Creates a libcutils native handle from an AIDL native handle, but it does not
* dup internally, so it will contain the same FDs as the handle itself. The
* result should be deleted with native_handle_delete.
diff --git a/common/support/test.cpp b/common/support/test.cpp
index 2359277..9b79581 100644
--- a/common/support/test.cpp
+++ b/common/support/test.cpp
@@ -62,6 +62,7 @@
TEST(ConvertNativeHandle, MakeFromAidlEmpty) {
NativeHandle handle;
+ EXPECT_TRUE(isAidlNativeHandleEmpty(handle));
native_handle_t* to = makeFromAidl(handle);
checkEq(handle, to, false /*exceptFds*/);
// no native_handle_close b/c fds are owned by NativeHandle
@@ -70,6 +71,7 @@
TEST(ConvertNativeHandle, MakeFromAidl) {
NativeHandle handle = makeTestAidlHandle();
+ EXPECT_FALSE(isAidlNativeHandleEmpty(handle));
native_handle_t* to = makeFromAidl(handle);
checkEq(handle, to, false /*exceptFds*/);
// no native_handle_close b/c fds are owned by NativeHandle
@@ -106,6 +108,7 @@
TEST(ConvertNativeHandle, MakeToAidlEmpty) {
native_handle_t* handle = native_handle_create(0, 0);
NativeHandle to = makeToAidl(handle);
+ EXPECT_TRUE(isAidlNativeHandleEmpty(to));
checkEq(to, handle, false /*exceptFds*/);
// no native_handle_close b/c fds are owned by NativeHandle now
EXPECT_EQ(0, native_handle_delete(handle));
@@ -114,6 +117,7 @@
TEST(ConvertNativeHandle, MakeToAidl) {
native_handle_t* handle = makeTestLibcutilsHandle();
NativeHandle to = makeToAidl(handle);
+ EXPECT_FALSE(isAidlNativeHandleEmpty(to));
checkEq(to, handle, false /*exceptFds*/);
// no native_handle_close b/c fds are owned by NativeHandle now
EXPECT_EQ(0, native_handle_delete(handle));
@@ -122,6 +126,7 @@
TEST(ConvertNativeHandle, DupToAidlEmpty) {
native_handle_t* handle = native_handle_create(0, 0);
NativeHandle to = dupToAidl(handle);
+ EXPECT_TRUE(isAidlNativeHandleEmpty(to));
checkEq(to, handle, true /*exceptFds*/);
EXPECT_EQ(0, native_handle_close(handle));
EXPECT_EQ(0, native_handle_delete(handle));
@@ -130,6 +135,7 @@
TEST(ConvertNativeHandle, DupToAidl) {
native_handle_t* handle = makeTestLibcutilsHandle();
NativeHandle to = dupToAidl(handle);
+ EXPECT_FALSE(isAidlNativeHandleEmpty(to));
checkEq(to, handle, true /*exceptFds*/);
EXPECT_EQ(0, native_handle_close(handle));
EXPECT_EQ(0, native_handle_delete(handle));
diff --git a/compatibility_matrices/Android.bp b/compatibility_matrices/Android.bp
index 422b37e..37c2820 100644
--- a/compatibility_matrices/Android.bp
+++ b/compatibility_matrices/Android.bp
@@ -28,8 +28,6 @@
"compatibility_matrix.3.xml",
],
kernel_configs: [
- "kernel_config_p_4.4",
- "kernel_config_p_4.9",
"kernel_config_p_4.14",
],
}
@@ -41,7 +39,6 @@
"compatibility_matrix.4.xml",
],
kernel_configs: [
- "kernel_config_q_4.9",
"kernel_config_q_4.14",
"kernel_config_q_4.19",
],
@@ -87,7 +84,6 @@
vintf_compatibility_matrix {
name: "framework_compatibility_matrix.current.xml",
- enabled: false,
stem: "compatibility_matrix.current.xml",
srcs: [
"compatibility_matrix.current.xml",
diff --git a/compatibility_matrices/Android.mk b/compatibility_matrices/Android.mk
index d6a44d0..d19f0da 100644
--- a/compatibility_matrices/Android.mk
+++ b/compatibility_matrices/Android.mk
@@ -103,6 +103,7 @@
framework_compatibility_matrix.5.xml \
framework_compatibility_matrix.6.xml \
framework_compatibility_matrix.7.xml \
+ framework_compatibility_matrix.current.xml \
framework_compatibility_matrix.device.xml \
my_framework_matrix_deps += \
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index 886f7f5..cf53a1d 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -16,7 +16,7 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="hidl" optional="false">
+ <hal format="hidl" optional="true">
<name>android.hardware.audio.effect</name>
<version>6.0</version>
<version>7.0</version>
@@ -26,6 +26,26 @@
</interface>
</hal>
<hal format="aidl" optional="true">
+ <name>android.hardware.audio.core</name>
+ <version>1</version>
+ <interface>
+ <name>IModule</name>
+ <instance>default</instance>
+ </interface>
+ <interface>
+ <name>IConfig</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+ <hal format="aidl" optional="true">
+ <name>android.hardware.audio.effect</name>
+ <version>1</version>
+ <interface>
+ <name>IFactory</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+ <hal format="aidl" optional="true">
<name>android.hardware.authsecret</name>
<version>1</version>
<interface>
@@ -92,6 +112,13 @@
<regex-instance>.*</regex-instance>
</interface>
</hal>
+ <hal format="aidl" optional="true">
+ <name>android.hardware.automotive.remoteaccess</name>
+ <interface>
+ <name>IRemoteAccess</name>
+ <regex-instance>.*</regex-instance>
+ </interface>
+ </hal>
<hal format="hidl" optional="true">
<name>android.hardware.automotive.vehicle</name>
<version>2.0</version>
@@ -100,14 +127,6 @@
<regex-instance>.*</regex-instance>
</interface>
</hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.biometrics.face</name>
- <version>1.0</version>
- <interface>
- <name>IBiometricsFace</name>
- <instance>default</instance>
- </interface>
- </hal>
<hal format="aidl" optional="true">
<name>android.hardware.biometrics.face</name>
<version>2</version>
@@ -116,14 +135,6 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.biometrics.fingerprint</name>
- <version>2.1-3</version>
- <interface>
- <name>IBiometricsFingerprint</name>
- <instance>default</instance>
- </interface>
- </hal>
<hal format="aidl" optional="true">
<name>android.hardware.biometrics.fingerprint</name>
<version>2</version>
@@ -141,6 +152,13 @@
</interface>
</hal>
<hal format="aidl" optional="true">
+ <name>android.hardware.bluetooth</name>
+ <interface>
+ <name>IBluetoothHci</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+ <hal format="aidl" optional="true">
<name>android.hardware.bluetooth.audio</name>
<version>2</version>
<interface>
@@ -148,9 +166,8 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="hidl" optional="true">
+ <hal format="aidl" optional="true">
<name>android.hardware.boot</name>
- <version>1.2</version>
<interface>
<name>IBootControl</name>
<instance>default</instance>
@@ -180,7 +197,7 @@
<regex-instance>[^/]+/[0-9]+</regex-instance>
</interface>
</hal>
- <hal format="aidl" optional="true">
+ <hal format="aidl" optional="true" updatable-via-apex="true">
<name>android.hardware.camera.provider</name>
<version>1</version>
<interface>
@@ -196,9 +213,16 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="hidl" optional="true">
+ <hal format="aidl" optional="true">
+ <name>android.hardware.cas</name>
+ <interface>
+ <name>IMediaCasService</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+ <hal format="aidl" optional="true">
<name>android.hardware.confirmationui</name>
- <version>1.0</version>
+ <version>1</version>
<interface>
<name>IConfirmationUI</name>
<instance>default</instance>
@@ -211,7 +235,7 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="aidl" optional="true">
+ <hal format="aidl" optional="true" updatable-via-apex="true">
<name>android.hardware.drm</name>
<version>1</version>
<interface>
@@ -238,7 +262,7 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="hidl" optional="false">
+ <hal format="hidl" optional="true">
<name>android.hardware.gatekeeper</name>
<version>1.0</version>
<interface>
@@ -246,11 +270,11 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.gnss</name>
- <version>2.0-1</version>
+ <hal format="aidl" optional="true">
+ <name>android.hardware.gatekeeper</name>
+ <version>1</version>
<interface>
- <name>IGnss</name>
+ <name>IGatekeeper</name>
<instance>default</instance>
</interface>
</hal>
@@ -295,7 +319,7 @@
</hal>
<hal format="aidl" optional="true">
<name>android.hardware.graphics.allocator</name>
- <version>1</version>
+ <version>1-2</version>
<interface>
<name>IAllocator</name>
<instance>default</instance>
@@ -320,7 +344,7 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="hidl" optional="false">
+ <hal format="hidl" optional="true">
<name>android.hardware.graphics.mapper</name>
<!-- New, non-Go devices should use 4.0, tested in vts_treble_vintf_vendor_test -->
<version>2.1</version>
@@ -349,7 +373,7 @@
</hal>
<hal format="aidl" optional="true">
<name>android.hardware.identity</name>
- <version>1-4</version>
+ <version>1-5</version>
<interface>
<name>IIdentityCredentialStore</name>
<instance>default</instance>
@@ -386,23 +410,6 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.keymaster</name>
- <version>3.0</version>
- <version>4.0-1</version>
- <interface>
- <name>IKeymasterDevice</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.keymaster</name>
- <version>4.0-1</version>
- <interface>
- <name>IKeymasterDevice</name>
- <instance>strongbox</instance>
- </interface>
- </hal>
<hal format="aidl" optional="true">
<name>android.hardware.security.dice</name>
<version>1</version>
@@ -413,7 +420,7 @@
</hal>
<hal format="aidl" optional="true">
<name>android.hardware.security.keymint</name>
- <version>1-2</version>
+ <version>1-3</version>
<interface>
<name>IKeyMintDevice</name>
<instance>default</instance>
@@ -422,7 +429,7 @@
</hal>
<hal format="aidl" optional="true">
<name>android.hardware.security.keymint</name>
- <version>1-2</version>
+ <version>1-3</version>
<interface>
<name>IRemotelyProvisionedComponent</name>
<instance>default</instance>
@@ -446,18 +453,6 @@
<regex-instance>vendor[0-9]*_software</regex-instance>
</interface>
</hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.media.omx</name>
- <version>1.0</version>
- <interface>
- <name>IOmx</name>
- <instance>default</instance>
- </interface>
- <interface>
- <name>IOmxStore</name>
- <instance>default</instance>
- </interface>
- </hal>
<hal format="aidl" optional="true">
<name>android.hardware.memtrack</name>
<version>1</version>
@@ -482,14 +477,6 @@
<regex-instance>.*</regex-instance>
</interface>
</hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.nfc</name>
- <version>1.2</version>
- <interface>
- <name>INfc</name>
- <instance>default</instance>
- </interface>
- </hal>
<hal format="aidl" optional="true">
<name>android.hardware.nfc</name>
<interface>
@@ -612,9 +599,9 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="hidl" optional="true">
+ <hal format="aidl" optional="true">
<name>android.hardware.secure_element</name>
- <version>1.0-2</version>
+ <version>1</version>
<interface>
<name>ISecureElement</name>
<regex-instance>eSE[1-9][0-9]*</regex-instance>
@@ -686,22 +673,28 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="hidl" optional="false">
+ <hal format="aidl" optional="false">
<name>android.hardware.thermal</name>
- <version>2.0</version>
+ <version>1</version>
<interface>
<name>IThermal</name>
<instance>default</instance>
</interface>
</hal>
- <hal format="hidl" optional="true">
+ <hal format="aidl" optional="true">
<name>android.hardware.tv.cec</name>
- <version>1.0-1</version>
<interface>
<name>IHdmiCec</name>
<instance>default</instance>
</interface>
</hal>
+ <hal format="aidl" optional="true">
+ <name>android.hardware.tv.hdmi</name>
+ <interface>
+ <name>IHdmi</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
<hal format="hidl" optional="true">
<name>android.hardware.tv.input</name>
<version>1.0</version>
@@ -726,14 +719,6 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.usb</name>
- <version>1.0-3</version>
- <interface>
- <name>IUsb</name>
- <instance>default</instance>
- </interface>
- </hal>
<hal format="aidl" optional="true">
<name>android.hardware.usb</name>
<interface>
@@ -781,6 +766,14 @@
<instance>default</instance>
</interface>
</hal>
+ <hal format="aidl" optional="true">
+ <name>android.hardware.wifi</name>
+ <version>1</version>
+ <interface>
+ <name>IWifi</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
<hal format="hidl" optional="true">
<name>android.hardware.wifi</name>
<version>1.3-6</version>
diff --git a/compatibility_matrices/exclude/fcm_exclude.cpp b/compatibility_matrices/exclude/fcm_exclude.cpp
index 6de9d03..cb77c7b 100644
--- a/compatibility_matrices/exclude/fcm_exclude.cpp
+++ b/compatibility_matrices/exclude/fcm_exclude.cpp
@@ -68,6 +68,8 @@
// does not depend on this HAL, hence it is not declared in any manifests or matrices.
"android.hardware.fastboot@1.0",
"android.hardware.fastboot@1.1",
+ // Fastboot AIDL
+ "android.hardware.fastboot",
// Deprecated HALs.
// HIDL
diff --git a/confirmationui/OWNERS b/confirmationui/OWNERS
new file mode 100644
index 0000000..2bcdb0e
--- /dev/null
+++ b/confirmationui/OWNERS
@@ -0,0 +1,2 @@
+swillden@google.com
+subrahmanyaman@google.com
diff --git a/confirmationui/aidl/Android.bp b/confirmationui/aidl/Android.bp
new file mode 100644
index 0000000..5395101
--- /dev/null
+++ b/confirmationui/aidl/Android.bp
@@ -0,0 +1,38 @@
+// Copyright (C) 2022 The Android Open-Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+aidl_interface {
+ name: "android.hardware.confirmationui",
+ vendor_available: true,
+ imports: [
+ "android.hardware.security.keymint-V3",
+ ],
+ srcs: ["android/hardware/confirmationui/*.aidl"],
+ stability: "vintf",
+ backend: {
+ java: {
+ platform_apis: true,
+ },
+ ndk: {
+ apps_enabled: false,
+ },
+ cpp: {
+ enabled: false,
+ },
+ },
+}
diff --git a/confirmationui/aidl/aidl_api/android.hardware.confirmationui/current/android/hardware/confirmationui/IConfirmationResultCallback.aidl b/confirmationui/aidl/aidl_api/android.hardware.confirmationui/current/android/hardware/confirmationui/IConfirmationResultCallback.aidl
new file mode 100644
index 0000000..6d6ec97
--- /dev/null
+++ b/confirmationui/aidl/aidl_api/android.hardware.confirmationui/current/android/hardware/confirmationui/IConfirmationResultCallback.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.confirmationui;
+@VintfStability
+interface IConfirmationResultCallback {
+ void result(in int error, in byte[] formattedMessage, in byte[] confirmationToken);
+}
diff --git a/confirmationui/aidl/aidl_api/android.hardware.confirmationui/current/android/hardware/confirmationui/IConfirmationUI.aidl b/confirmationui/aidl/aidl_api/android.hardware.confirmationui/current/android/hardware/confirmationui/IConfirmationUI.aidl
new file mode 100644
index 0000000..c5c7aa7
--- /dev/null
+++ b/confirmationui/aidl/aidl_api/android.hardware.confirmationui/current/android/hardware/confirmationui/IConfirmationUI.aidl
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.confirmationui;
+@VintfStability
+interface IConfirmationUI {
+ void abort();
+ void deliverSecureInputEvent(in android.hardware.security.keymint.HardwareAuthToken secureInputToken);
+ void promptUserConfirmation(in android.hardware.confirmationui.IConfirmationResultCallback resultCB, in byte[] promptText, in byte[] extraData, in @utf8InCpp String locale, in android.hardware.confirmationui.UIOption[] uiOptions);
+ const int OK = 0;
+ const int CANCELED = 1;
+ const int ABORTED = 2;
+ const int OPERATION_PENDING = 3;
+ const int IGNORED = 4;
+ const int SYSTEM_ERROR = 5;
+ const int UNIMPLEMENTED = 6;
+ const int UNEXPECTED = 7;
+ const int UI_ERROR = 65536;
+ const int UI_ERROR_MISSING_GLYPH = 65537;
+ const int UI_ERROR_MESSAGE_TOO_LONG = 65538;
+ const int UI_ERROR_MALFORMED_UTF8ENCODING = 65539;
+ const int TEST_KEY_BYTE = 165;
+ const int MAX_MESSAGE_SIZE = 6144;
+}
diff --git a/confirmationui/aidl/aidl_api/android.hardware.confirmationui/current/android/hardware/confirmationui/TestModeCommands.aidl b/confirmationui/aidl/aidl_api/android.hardware.confirmationui/current/android/hardware/confirmationui/TestModeCommands.aidl
new file mode 100644
index 0000000..b8629d1
--- /dev/null
+++ b/confirmationui/aidl/aidl_api/android.hardware.confirmationui/current/android/hardware/confirmationui/TestModeCommands.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.confirmationui;
+@Backing(type="int") @VintfStability
+enum TestModeCommands {
+ OK_EVENT = 0,
+ CANCEL_EVENT = 1,
+}
diff --git a/confirmationui/aidl/aidl_api/android.hardware.confirmationui/current/android/hardware/confirmationui/UIOption.aidl b/confirmationui/aidl/aidl_api/android.hardware.confirmationui/current/android/hardware/confirmationui/UIOption.aidl
new file mode 100644
index 0000000..ebecf9e
--- /dev/null
+++ b/confirmationui/aidl/aidl_api/android.hardware.confirmationui/current/android/hardware/confirmationui/UIOption.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.confirmationui;
+@Backing(type="int") @VintfStability
+enum UIOption {
+ ACCESSIBILITY_INVERTED = 0,
+ ACCESSIBILITY_MAGNIFIED = 1,
+}
diff --git a/confirmationui/aidl/android/hardware/confirmationui/IConfirmationResultCallback.aidl b/confirmationui/aidl/android/hardware/confirmationui/IConfirmationResultCallback.aidl
new file mode 100644
index 0000000..2165fdd
--- /dev/null
+++ b/confirmationui/aidl/android/hardware/confirmationui/IConfirmationResultCallback.aidl
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.confirmationui;
+
+import android.hardware.confirmationui.IConfirmationUI;
+
+/**
+ * Callback interface passed to IConfirmationUI::promptUserConfirmation().
+ * Informs the caller about the result of the prompt operation.
+ */
+@VintfStability
+interface IConfirmationResultCallback {
+ /**
+ * This callback is called by the confirmation provider when it stops prompting the user.
+ * Iff the user has confirmed the prompted text, error is ErrorCode::OK and the
+ * parameters formattedMessage and confirmationToken hold the values needed to request
+ * a signature from keymaster.
+ * In all other cases formattedMessage and confirmationToken must be of length 0.
+ *
+ * @param error - OK: IFF the user has confirmed the prompt.
+ * - CANCELED: If the user has pressed the cancel button.
+ * - ABORTED: If IConfirmationUI::abort() was called.
+ * - SYSTEM_ERROR: If an unexpected System error occurred that prevented the TUI
+ * from being shut down gracefully.
+ *
+ * @param formattedMessage holds the prompt text and extra data.
+ * The message is CBOR (RFC 7049) encoded and has the following format:
+ * CBOR_MAP{ "prompt", <promptText>, "extra", <extraData> }
+ * The message is a CBOR encoded map (type 5) with the keys
+ * "prompt" and "extra". The keys are encoded as CBOR text string
+ * (type 3). The value <promptText> is encoded as CBOR text string
+ * (type 3), and the value <extraData> is encoded as CBOR byte string
+ * (type 2). The map must have exactly one key value pair for each of
+ * the keys "prompt" and "extra". Other keys are not allowed.
+ * The value of "prompt" is given by the proptText argument to
+ * IConfirmationUI::promptUserConfirmation and must not be modified
+ * by the implementation.
+ * The value of "extra" is given by the extraData argument to
+ * IConfirmationUI::promptUserConfirmation and must not be modified
+ * or interpreted by the implementation.
+ *
+ * @param confirmationToken a 32-byte HMAC-SHA256 value, computed over
+ * "confirmation token" || <formattedMessage>
+ * i.e. the literal UTF-8 encoded string "confirmation token", without
+ * the "", concatenated with the formatted message as returned in the
+ * formattedMessage argument. The HMAC is keyed with a 256-bit secret
+ * which is shared with Keymaster. In test mode the test key MUST be
+ * used (see types.hal TestModeCommands and
+ * IConfirmationUI::TEST_KEY_BYTE).
+ */
+ void result(in int error, in byte[] formattedMessage, in byte[] confirmationToken);
+}
diff --git a/confirmationui/aidl/android/hardware/confirmationui/IConfirmationUI.aidl b/confirmationui/aidl/android/hardware/confirmationui/IConfirmationUI.aidl
new file mode 100644
index 0000000..f071126
--- /dev/null
+++ b/confirmationui/aidl/android/hardware/confirmationui/IConfirmationUI.aidl
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.confirmationui;
+
+import android.hardware.confirmationui.IConfirmationResultCallback;
+import android.hardware.confirmationui.UIOption;
+import android.hardware.security.keymint.HardwareAuthToken;
+
+@VintfStability
+interface IConfirmationUI {
+ // Possible Errors.
+ /**
+ * API call succeeded or the user gave approval (result callback).
+ */
+ const int OK = 0;
+ /**
+ * The user canceled the TUI (result callback).
+ */
+ const int CANCELED = 1;
+ /**
+ * IConfirmationUI::abort() was called. (result callback).
+ */
+ const int ABORTED = 2;
+ /**
+ * Cannot start another prompt.
+ */
+ const int OPERATION_PENDING = 3;
+ /**
+ * IConfirmationUI::deliverSecureInputEvent call was ignored.
+ */
+ const int IGNORED = 4;
+ /**
+ * An unexpected system error occurred.
+ */
+ const int SYSTEM_ERROR = 5;
+ /**
+ * Returned by an unimplemented API call.
+ */
+ const int UNIMPLEMENTED = 6;
+ /**
+ * This is returned when an error is diagnosed that should have been
+ * caught by earlier input sanitization. Should never be seen in production.
+ */
+ const int UNEXPECTED = 7;
+ /**
+ * General UI error.
+ */
+ const int UI_ERROR = 0x10000;
+ /**
+ * This is returned if there is no corresponding glyph for a character.
+ */
+ const int UI_ERROR_MISSING_GLYPH = 0x10001;
+ /**
+ * The implementation must return this error code on promptUserConfirmation if the
+ * resulting formatted message does not fit into MAX_MESSAGE_SIZE bytes. It is
+ * advised that the implementation formats the message upon receiving this API call to
+ * be able to diagnose this syndrome.
+ */
+ const int UI_ERROR_MESSAGE_TOO_LONG = 0x10002;
+ /**
+ * This is returned if the UTF8 encoding is malformed.
+ */
+ const int UI_ERROR_MALFORMED_UTF8ENCODING = 0x10003;
+
+ // Constants
+ /**
+ * The test key is 32byte word with all bytes set to TEST_KEY_BYTE.
+ */
+ const int TEST_KEY_BYTE = 0xA5;
+ /**
+ * This defines the maximum message size. This indirectly limits the size of the prompt text
+ * and the extra data that can be passed to the confirmation UI. The prompt text and extra data
+ * must fit in to this size including CBOR header information.
+ */
+ const int MAX_MESSAGE_SIZE = 0x1800;
+
+ /**
+ * Aborts a pending user prompt. This allows the framework to gracefully end a TUI dialog.
+ * If a TUI operation was pending the corresponding call back is informed with
+ * ErrorCode::Aborted.
+ */
+ void abort();
+
+ /**
+ * DeliverSecureInput is used by the framework to deliver a secure input event to the
+ * confirmation provider.
+ *
+ * VTS test mode:
+ * This function can be used to test certain code paths non-interactively.
+ * See TestModeCommands.aidl for details.
+ *
+ * @param secureInputToken An authentication token as generated by Android authentication
+ * providers.
+ */
+ void deliverSecureInputEvent(in HardwareAuthToken secureInputToken);
+
+ /**
+ * Asynchronously initiates a confirmation UI dialog prompting the user to confirm a given text.
+ * The TUI prompt must be implemented in such a way that a positive response indicates with
+ * high confidence that a user has seen the given prompt text even if the Android framework
+ * including the kernel was compromised.
+ *
+ * Service status return:
+ *
+ * OK IFF the dialog was successfully started. In this case, and only in this
+ * case, the implementation must, eventually, call the callback to
+ * indicate completion.
+ * OPERATION_PENDING is returned when the confirmation provider is currently
+ * in use.
+ * SYSTEM_ERROR an error occurred trying to communicate with the confirmation
+ * provider (e.g. trusted app).
+ * UI_ERROR the confirmation provider encountered an issue with displaying
+ * the prompt text to the user.
+ *
+ * @param resultCB Implementation of IResultCallback. Used by the implementation to report
+ * the result of the current pending user prompt.
+ *
+ * @param promptText UTF-8 encoded bytes which is to be presented to the user.
+ *
+ * @param extraData A binary blob that must be included in the formatted output message as is.
+ * It is opaque to the implementation. Implementations must neither interpret
+ * nor modify the content.
+ *
+ * @param locale String specifying the locale that must be used by the TUI dialog. The string
+ * is an IETF BCP 47 tag.
+ *
+ * @param uiOptions A set of uiOptions manipulating how the confirmation prompt is displayed.
+ * Refer to UIOption in types.hal for possible options.
+ */
+ void promptUserConfirmation(in IConfirmationResultCallback resultCB, in byte[] promptText,
+ in byte[] extraData, in @utf8InCpp String locale, in UIOption[] uiOptions);
+}
diff --git a/confirmationui/aidl/android/hardware/confirmationui/TestModeCommands.aidl b/confirmationui/aidl/android/hardware/confirmationui/TestModeCommands.aidl
new file mode 100644
index 0000000..5b1d8fb
--- /dev/null
+++ b/confirmationui/aidl/android/hardware/confirmationui/TestModeCommands.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.confirmationui;
+
+/**
+ * Test mode commands.
+ *
+ * IConfirmationUI::deliverSecureInputEvent can be used to test certain code paths.
+ * To that end, the caller passes an auth token that has an HMAC keyed with the test key
+ * (see IConfirmationUI::TEST_KEY_BYTE). Implementations first check the HMAC against test key.
+ * If the test key produces a matching HMAC, the implementation evaluates the challenge field
+ * of the auth token against the values defined in TestModeCommand.
+ * If the command indicates that a confirmation token is to be generated the test key MUST be used
+ * to generate this confirmation token.
+ *
+ * See command code for individual test command descriptions.
+ */
+@VintfStability
+@Backing(type="int")
+enum TestModeCommands {
+ /**
+ * Simulates the user pressing the OK button on the UI. If no operation is pending
+ * ResponseCode::Ignored must be returned. A pending operation is finalized successfully
+ * see IConfirmationResultCallback::result, however, the test key
+ * (see IConfirmationUI::TEST_KEY_BYTE) MUST be used to generate the confirmation token.
+ */
+ OK_EVENT = 0,
+ /**
+ * Simulates the user pressing the CANCEL button on the UI. If no operation is pending
+ * Result::Ignored must be returned. A pending operation is finalized as specified in
+ * IConfirmationResultCallback.hal.
+ */
+ CANCEL_EVENT = 1,
+}
diff --git a/confirmationui/aidl/android/hardware/confirmationui/UIOption.aidl b/confirmationui/aidl/android/hardware/confirmationui/UIOption.aidl
new file mode 100644
index 0000000..b242c53
--- /dev/null
+++ b/confirmationui/aidl/android/hardware/confirmationui/UIOption.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.confirmationui;
+
+/**
+ * UI modification options.
+ */
+@VintfStability
+@Backing(type="int")
+enum UIOption {
+ /**
+ * Accessibility: Requests color inverted style.
+ */
+ ACCESSIBILITY_INVERTED = 0,
+ /**
+ * Accessibility: Requests magnified style.
+ */
+ ACCESSIBILITY_MAGNIFIED = 1,
+}
diff --git a/confirmationui/aidl/vts/functional/Android.bp b/confirmationui/aidl/vts/functional/Android.bp
new file mode 100644
index 0000000..3649c87
--- /dev/null
+++ b/confirmationui/aidl/vts/functional/Android.bp
@@ -0,0 +1,45 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_test {
+ name: "VtsHalConfirmationUITargetTest",
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "keymint_use_latest_hal_aidl_ndk_shared",
+ "use_libaidlvintf_gtest_helper_static",
+ ],
+ srcs: [
+ "VtsHalConfirmationUITargetTest.cpp",
+ ],
+ static_libs: [
+ "android.hardware.confirmationui-V1-ndk",
+ "libcn-cbor",
+ "android.hardware.confirmationui-support-lib",
+ ],
+ shared_libs: [
+ "libbinder_ndk",
+ "libcrypto",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+}
diff --git a/confirmationui/aidl/vts/functional/VtsHalConfirmationUITargetTest.cpp b/confirmationui/aidl/vts/functional/VtsHalConfirmationUITargetTest.cpp
new file mode 100644
index 0000000..61dae8b
--- /dev/null
+++ b/confirmationui/aidl/vts/functional/VtsHalConfirmationUITargetTest.cpp
@@ -0,0 +1,535 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ConfirmationIOAidlHalTest"
+
+#include <algorithm>
+#include <condition_variable>
+#include <future>
+#include <iostream>
+#include <memory>
+#include <mutex>
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/confirmationui/BnConfirmationResultCallback.h>
+#include <aidl/android/hardware/confirmationui/IConfirmationUI.h>
+#include <aidl/android/hardware/confirmationui/TestModeCommands.h>
+#include <aidl/android/hardware/confirmationui/UIOption.h>
+#include <android-base/thread_annotations.h>
+#include <android/hardware/confirmationui/support/confirmationui_utils.h>
+#include <cutils/log.h>
+
+#include <openssl/hmac.h>
+#include <openssl/sha.h>
+
+#include <cn-cbor/cn-cbor.h>
+
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <android/binder_status.h>
+
+static constexpr int TIMEOUT_PERIOD = 10;
+
+namespace aidl::android::hardware::confirmationui::test {
+using ::aidl::android::hardware::security::keymint::HardwareAuthenticatorType;
+using ::aidl::android::hardware::security::keymint::HardwareAuthToken;
+using ::android::hardware::confirmationui::support::auth_token_key_t;
+using ::android::hardware::confirmationui::support::ByteBufferProxy;
+using ::android::hardware::confirmationui::support::HMac;
+using ::android::hardware::confirmationui::support::hmac_t;
+using ::android::hardware::confirmationui::support::hton;
+using ::android::hardware::confirmationui::support::NullOr;
+using std::shared_ptr;
+using std::string;
+using std::vector;
+
+namespace {
+const auth_token_key_t testKey(static_cast<uint8_t>(IConfirmationUI::TEST_KEY_BYTE));
+
+class HMacImplementation {
+ public:
+ static NullOr<hmac_t> hmac256(const auth_token_key_t& key,
+ std::initializer_list<ByteBufferProxy> buffers) {
+ HMAC_CTX hmacCtx;
+ HMAC_CTX_init(&hmacCtx);
+ if (!HMAC_Init_ex(&hmacCtx, key.data(), key.size(), EVP_sha256(), nullptr)) {
+ return {};
+ }
+ for (auto& buffer : buffers) {
+ if (!HMAC_Update(&hmacCtx, buffer.data(), buffer.size())) {
+ return {};
+ }
+ }
+ hmac_t result;
+ if (!HMAC_Final(&hmacCtx, result.data(), nullptr)) {
+ return {};
+ }
+ return result;
+ }
+};
+
+using HMacer = HMac<HMacImplementation>;
+
+template <typename... Data>
+vector<uint8_t> testHMAC(const Data&... data) {
+ auto hmac = HMacer::hmac256(testKey, data...);
+ if (!hmac.isOk()) {
+ ADD_FAILURE() << "Failed to compute test hmac. This is a self-test error.";
+ return {};
+ }
+ vector<uint8_t> result(hmac.value().size());
+ std::copy(hmac.value().data(), hmac.value().data() + hmac.value().size(), result.data());
+ return result;
+}
+
+template <typename T>
+auto toBytes(const T& v) -> const uint8_t (&)[sizeof(T)] {
+ return *reinterpret_cast<const uint8_t(*)[sizeof(T)]>(&v);
+}
+
+HardwareAuthToken makeTestToken(const TestModeCommands command, uint64_t timestamp = 0) {
+ HardwareAuthToken auth_token;
+ auth_token.challenge = static_cast<uint64_t>(command);
+ auth_token.userId = 0;
+ auth_token.authenticatorId = 0;
+ auth_token.authenticatorType = HardwareAuthenticatorType::NONE;
+ auth_token.timestamp = {static_cast<int64_t>(timestamp)};
+
+ // Canonical form of auth-token v0
+ // version (1 byte)
+ // challenge (8 bytes)
+ // user_id (8 bytes)
+ // authenticator_id (8 bytes)
+ // authenticator_type (4 bytes)
+ // timestamp (8 bytes)
+ // total 37 bytes
+ auth_token.mac = testHMAC("\0",
+ toBytes(auth_token.challenge), //
+ toBytes(auth_token.userId), //
+ toBytes(auth_token.authenticatorId), //
+ toBytes(hton(auth_token.authenticatorType)), //
+ toBytes(hton(auth_token.timestamp))); //
+
+ return auth_token;
+}
+
+#define DEBUG_CONFRIMATIONUI_UTILS_TEST
+
+#ifdef DEBUG_CONFRIMATIONUI_UTILS_TEST
+std::ostream& hexdump(std::ostream& out, const uint8_t* data, size_t size) {
+ for (size_t i = 0; i < size; ++i) {
+ uint8_t byte = data[i];
+ out << std::hex << std::setw(2) << std::setfill('0') << (unsigned)byte;
+ switch (i & 0xf) {
+ case 0xf:
+ out << "\n";
+ break;
+ case 7:
+ out << " ";
+ break;
+ default:
+ out << " ";
+ break;
+ }
+ }
+ return out;
+}
+#endif
+
+constexpr char hex_value[256] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, // '0'..'9'
+ 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 'A'..'F'
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 'a'..'f'
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+std::string hex2str(std::string a) {
+ std::string b;
+ size_t num = a.size() / 2;
+ b.resize(num);
+ for (size_t i = 0; i < num; i++) {
+ b[i] = (hex_value[a[i * 2] & 0xFF] << 4) + (hex_value[a[i * 2 + 1] & 0xFF]);
+ }
+ return b;
+}
+
+int getReturnCode(const ::ndk::ScopedAStatus& result) {
+ if (result.isOk()) return IConfirmationUI::OK;
+
+ if (result.getExceptionCode() == EX_SERVICE_SPECIFIC) {
+ return static_cast<int>(result.getServiceSpecificError());
+ }
+ return result.getStatus();
+}
+
+} // namespace
+
+class ConfirmationUIAidlTest : public ::testing::TestWithParam<std::string> {
+ public:
+ void TearDown() override { confirmator_->abort(); }
+ void SetUp() override {
+ std::string name = GetParam();
+ ASSERT_TRUE(AServiceManager_isDeclared(name.c_str())) << name;
+ ndk::SpAIBinder binder(AServiceManager_waitForService(name.c_str()));
+ ASSERT_NE(binder, nullptr);
+ confirmator_ = IConfirmationUI::fromBinder(binder);
+ ASSERT_NE(confirmator_, nullptr);
+ }
+
+ // Used as a mechanism to inform the test about data/event callback
+ inline void notify() {
+ std::unique_lock<std::mutex> lock(mtx_);
+ cv_.notify_one();
+ }
+
+ // Test code calls this function to wait for data/event callback
+ inline std::cv_status wait() {
+ std::unique_lock<std::mutex> lock(mtx_);
+ auto now = std::chrono::system_clock::now();
+ std::cv_status status = cv_.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD));
+ return status;
+ }
+
+ protected:
+ shared_ptr<IConfirmationUI> confirmator_;
+
+ private:
+ // synchronization objects
+ std::mutex mtx_;
+ std::condition_variable cv_;
+};
+
+class ConfirmationTestCallback
+ : public ::aidl::android::hardware::confirmationui::BnConfirmationResultCallback {
+ public:
+ ConfirmationTestCallback(ConfirmationUIAidlTest& parent) : parent_(parent){};
+ virtual ~ConfirmationTestCallback() = default;
+
+ ::ndk::ScopedAStatus result(int32_t err, const vector<uint8_t>& msg,
+ const vector<uint8_t>& confToken) override {
+ error_ = err;
+ formattedMessage_ = msg;
+ confirmationToken_ = confToken;
+ parent_.notify();
+ return ndk::ScopedAStatus::ok();
+ }
+
+ bool verifyConfirmationToken() {
+ static constexpr char confirmationPrefix[] = "confirmation token";
+ EXPECT_EQ(32U, confirmationToken_.size());
+ return 32U == confirmationToken_.size() &&
+ !memcmp(confirmationToken_.data(),
+ testHMAC(confirmationPrefix, formattedMessage_).data(), 32);
+ }
+
+ int error_;
+ vector<uint8_t> formattedMessage_;
+ vector<uint8_t> confirmationToken_;
+
+ private:
+ ConfirmationUIAidlTest& parent_;
+};
+
+struct CnCborDeleter {
+ void operator()(cn_cbor* ptr) { cn_cbor_free(ptr); }
+};
+
+typedef std::unique_ptr<cn_cbor, CnCborDeleter> CnCborPtr;
+
+// Simulates the User taping Ok
+TEST_P(ConfirmationUIAidlTest, UserOkTest) {
+ static constexpr char test_prompt[] = "Me first, gimme gimme!";
+ static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3};
+ shared_ptr<ConfirmationTestCallback> conf_cb =
+ ::ndk::SharedRefBase::make<ConfirmationTestCallback>(*this);
+ vector<uint8_t> prompt_text(test_prompt, test_prompt + strlen(test_prompt));
+ vector<uint8_t> extra(test_extra, test_extra + 3);
+ ASSERT_TRUE(confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {}).isOk());
+ // Simulate the user taping ok.
+ ASSERT_TRUE(confirmator_->deliverSecureInputEvent(makeTestToken(TestModeCommands::OK_EVENT))
+ .isOk());
+ // Wait for the callback.
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ ASSERT_EQ(IConfirmationUI::OK, conf_cb->error_);
+
+ ASSERT_TRUE(conf_cb->verifyConfirmationToken());
+
+ cn_cbor_errback cn_cbor_error;
+ auto parsed_message = CnCborPtr(cn_cbor_decode(
+ conf_cb->formattedMessage_.data(), conf_cb->formattedMessage_.size(), &cn_cbor_error));
+ // is parsable CBOR
+ ASSERT_TRUE(parsed_message.get());
+ // is a map
+ ASSERT_EQ(CN_CBOR_MAP, parsed_message->type);
+
+ // the message must have exactly 2 key value pairs.
+ // cn_cbor holds 2*<no_of_pairs> in the length field
+ ASSERT_EQ(4, parsed_message->length);
+ // map has key "prompt"
+ auto prompt = cn_cbor_mapget_string(parsed_message.get(), "prompt");
+ ASSERT_TRUE(prompt);
+ ASSERT_EQ(CN_CBOR_TEXT, prompt->type);
+ ASSERT_EQ(22, prompt->length);
+ ASSERT_EQ(0, memcmp(test_prompt, prompt->v.str, 22));
+ // map has key "extra"
+ auto extra_out = cn_cbor_mapget_string(parsed_message.get(), "extra");
+ ASSERT_TRUE(extra_out);
+ ASSERT_EQ(CN_CBOR_BYTES, extra_out->type);
+ ASSERT_EQ(3, extra_out->length);
+ ASSERT_EQ(0, memcmp(test_extra, extra_out->v.bytes, 3));
+}
+
+// Initiates a confirmation prompt with a message that is too long
+TEST_P(ConfirmationUIAidlTest, MessageTooLongTest) {
+ static constexpr uint8_t test_extra[IConfirmationUI::MAX_MESSAGE_SIZE] = {};
+ static constexpr char test_prompt[] = "D\'oh!";
+ shared_ptr<ConfirmationTestCallback> conf_cb =
+ ::ndk::SharedRefBase::make<ConfirmationTestCallback>(*this);
+ vector<uint8_t> prompt_text(test_prompt, test_prompt + strlen(test_prompt));
+ vector<uint8_t> extra(test_extra, test_extra + sizeof(test_extra));
+ auto result = confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {});
+ ASSERT_EQ(IConfirmationUI::UI_ERROR_MESSAGE_TOO_LONG, getReturnCode(result));
+}
+
+// If the message gets very long some HAL implementations might fail even before the message
+// reaches the trusted app implementation. But the HAL must still diagnose the correct error.
+TEST_P(ConfirmationUIAidlTest, MessageWayTooLongTest) {
+ static constexpr uint8_t test_extra[(IConfirmationUI::MAX_MESSAGE_SIZE)*10] = {};
+ static constexpr char test_prompt[] = "D\'oh!";
+ shared_ptr<ConfirmationTestCallback> conf_cb =
+ ::ndk::SharedRefBase::make<ConfirmationTestCallback>(*this);
+ vector<uint8_t> prompt_text(test_prompt, test_prompt + strlen(test_prompt));
+ vector<uint8_t> extra(test_extra, test_extra + sizeof(test_extra));
+ auto result = confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {});
+ ASSERT_EQ(IConfirmationUI::UI_ERROR_MESSAGE_TOO_LONG, getReturnCode(result));
+}
+
+// Simulates the User tapping the Cancel
+TEST_P(ConfirmationUIAidlTest, UserCancelTest) {
+ static constexpr char test_prompt[] = "Me first, gimme gimme!";
+ static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3};
+ shared_ptr<ConfirmationTestCallback> conf_cb =
+ ::ndk::SharedRefBase::make<ConfirmationTestCallback>(*this);
+ vector<uint8_t> prompt_text(test_prompt, test_prompt + strlen(test_prompt));
+ vector<uint8_t> extra(test_extra, test_extra + 3);
+ ASSERT_TRUE(confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {}).isOk());
+
+ // Simulate the user taping ok.
+ ASSERT_TRUE(confirmator_->deliverSecureInputEvent(makeTestToken(TestModeCommands::CANCEL_EVENT))
+ .isOk());
+ // Wait for the callback.
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ ASSERT_EQ(IConfirmationUI::CANCELED, conf_cb->error_);
+
+ ASSERT_EQ(0U, conf_cb->confirmationToken_.size());
+ ASSERT_EQ(0U, conf_cb->formattedMessage_.size());
+}
+
+// Simulates the framework cancelling an ongoing prompt
+TEST_P(ConfirmationUIAidlTest, AbortTest) {
+ static constexpr char test_prompt[] = "Me first, gimme gimme!";
+ static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3};
+ shared_ptr<ConfirmationTestCallback> conf_cb =
+ ::ndk::SharedRefBase::make<ConfirmationTestCallback>(*this);
+ vector<uint8_t> prompt_text(test_prompt, test_prompt + strlen(test_prompt));
+ vector<uint8_t> extra(test_extra, test_extra + 3);
+ ASSERT_TRUE(confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {}).isOk());
+
+ confirmator_->abort();
+
+ // Wait for the callback.
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ ASSERT_EQ(IConfirmationUI::ABORTED, conf_cb->error_);
+ ASSERT_EQ(0U, conf_cb->confirmationToken_.size());
+ ASSERT_EQ(0U, conf_cb->formattedMessage_.size());
+}
+
+// Tests if the confirmation dialog can successfully render 100 'W' characters as required by
+// the design guidelines.
+TEST_P(ConfirmationUIAidlTest, PortableMessageTest1) {
+ static constexpr char test_prompt[] =
+ "WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW"
+ "WWWWWWWWWWWWWW";
+ static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3};
+ shared_ptr<ConfirmationTestCallback> conf_cb =
+ ::ndk::SharedRefBase::make<ConfirmationTestCallback>(*this);
+ vector<uint8_t> prompt_text(test_prompt, test_prompt + strlen(test_prompt));
+ vector<uint8_t> extra(test_extra, test_extra + 3);
+ ASSERT_TRUE(confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {}).isOk());
+
+ confirmator_->abort();
+
+ // Wait for the callback.
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ ASSERT_EQ(IConfirmationUI::ABORTED, conf_cb->error_);
+ ASSERT_EQ(0U, conf_cb->confirmationToken_.size());
+ ASSERT_EQ(0U, conf_cb->formattedMessage_.size());
+}
+
+// Tests if the confirmation dialog can successfully render 100 'W' characters as required by
+// the design guidelines in magnified mode.
+TEST_P(ConfirmationUIAidlTest, PortableMessageTest1Magnified) {
+ static constexpr char test_prompt[] =
+ "WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW"
+ "WWWWWWWWWWWWWW";
+ static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3};
+ shared_ptr<ConfirmationTestCallback> conf_cb =
+ ::ndk::SharedRefBase::make<ConfirmationTestCallback>(*this);
+ vector<uint8_t> prompt_text(test_prompt, test_prompt + strlen(test_prompt));
+ vector<uint8_t> extra(test_extra, test_extra + 3);
+ ASSERT_TRUE(confirmator_
+ ->promptUserConfirmation(conf_cb, prompt_text, extra, "en",
+ {UIOption::ACCESSIBILITY_MAGNIFIED})
+ .isOk());
+
+ confirmator_->abort();
+
+ // Wait for the callback.
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ ASSERT_EQ(IConfirmationUI::ABORTED, conf_cb->error_);
+ ASSERT_EQ(0U, conf_cb->confirmationToken_.size());
+ ASSERT_EQ(0U, conf_cb->formattedMessage_.size());
+}
+
+// Tests if the confirmation dialog can successfully render 8 groups of 12 'W' characters as
+// required by the design guidelines.
+TEST_P(ConfirmationUIAidlTest, PortableMessageTest2) {
+ static constexpr char test_prompt[] =
+ "WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW "
+ "WWWWWWWWWWWW WWWWWWWWWWWW";
+ static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3};
+ shared_ptr<ConfirmationTestCallback> conf_cb =
+ ::ndk::SharedRefBase::make<ConfirmationTestCallback>(*this);
+ vector<uint8_t> prompt_text(test_prompt, test_prompt + strlen(test_prompt));
+ vector<uint8_t> extra(test_extra, test_extra + 3);
+ ASSERT_TRUE(confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {}).isOk());
+
+ confirmator_->abort();
+
+ // Wait for the callback.
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ ASSERT_EQ(IConfirmationUI::ABORTED, conf_cb->error_);
+ ASSERT_EQ(0U, conf_cb->confirmationToken_.size());
+ ASSERT_EQ(0U, conf_cb->formattedMessage_.size());
+}
+
+// Tests if the confirmation dialog can successfully render 8 groups of 12 'W' characters as
+// required by the design guidelines in magnified mode.
+TEST_P(ConfirmationUIAidlTest, PortableMessageTest2Magnified) {
+ static constexpr char test_prompt[] =
+ "WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW "
+ "WWWWWWWWWWWW WWWWWWWWWWWW";
+ static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3};
+ shared_ptr<ConfirmationTestCallback> conf_cb =
+ ::ndk::SharedRefBase::make<ConfirmationTestCallback>(*this);
+ vector<uint8_t> prompt_text(test_prompt, test_prompt + strlen(test_prompt));
+ vector<uint8_t> extra(test_extra, test_extra + 3);
+ ASSERT_TRUE(confirmator_
+ ->promptUserConfirmation(conf_cb, prompt_text, extra, "en",
+ {UIOption::ACCESSIBILITY_MAGNIFIED})
+ .isOk());
+
+ confirmator_->abort();
+
+ // Wait for the callback.
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ ASSERT_EQ(IConfirmationUI::ABORTED, conf_cb->error_);
+ ASSERT_EQ(0U, conf_cb->confirmationToken_.size());
+ ASSERT_EQ(0U, conf_cb->formattedMessage_.size());
+}
+
+// Passing malformed UTF-8 to the confirmation UI
+// This test passes a string that ends in the middle of a multibyte character
+TEST_P(ConfirmationUIAidlTest, MalformedUTF8Test1) {
+ static constexpr char test_prompt[] = {char(0xc0), 0};
+ static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3};
+ shared_ptr<ConfirmationTestCallback> conf_cb =
+ ::ndk::SharedRefBase::make<ConfirmationTestCallback>(*this);
+ vector<uint8_t> prompt_text(test_prompt, test_prompt + strlen(test_prompt));
+ vector<uint8_t> extra(test_extra, test_extra + 3);
+ auto result = confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {});
+ ASSERT_EQ(IConfirmationUI::UI_ERROR_MALFORMED_UTF8ENCODING, getReturnCode(result));
+}
+
+// Passing malformed UTF-8 to the confirmation UI
+// This test passes a string with a 5-byte character.
+TEST_P(ConfirmationUIAidlTest, MalformedUTF8Test2) {
+ static constexpr char test_prompt[] = {char(0xf8), char(0x82), char(0x82),
+ char(0x82), char(0x82), 0};
+ static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3};
+ shared_ptr<ConfirmationTestCallback> conf_cb =
+ ::ndk::SharedRefBase::make<ConfirmationTestCallback>(*this);
+ vector<uint8_t> prompt_text(test_prompt, test_prompt + strlen(test_prompt));
+ vector<uint8_t> extra(test_extra, test_extra + 3);
+ auto result = confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {});
+ ASSERT_EQ(IConfirmationUI::UI_ERROR_MALFORMED_UTF8ENCODING, getReturnCode(result));
+}
+
+// Passing malformed UTF-8 to the confirmation UI
+// This test passes a string with a 2-byte character followed by a stray non UTF-8 character.
+TEST_P(ConfirmationUIAidlTest, MalformedUTF8Test3) {
+ static constexpr char test_prompt[] = {char(0xc0), char(0x82), char(0x83), 0};
+ static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3};
+ shared_ptr<ConfirmationTestCallback> conf_cb =
+ ::ndk::SharedRefBase::make<ConfirmationTestCallback>(*this);
+ vector<uint8_t> prompt_text(test_prompt, test_prompt + strlen(test_prompt));
+ vector<uint8_t> extra(test_extra, test_extra + 3);
+ auto result = confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {});
+ ASSERT_EQ(IConfirmationUI::UI_ERROR_MALFORMED_UTF8ENCODING, getReturnCode(result));
+}
+
+// Test the implementation of HMAC SHA 256 against a golden blob.
+TEST(ConfirmationUITestSelfTest, HMAC256SelfTest) {
+ const char key_str[32] = "keykeykeykeykeykeykeykeykeykeyk";
+ const uint8_t(&key)[32] = *reinterpret_cast<const uint8_t(*)[32]>(key_str);
+ auto expected = hex2str("2377fbcaa7fb3f6c20cfa1d9ebc60e9922cf58c909e25e300f3cb57f7805c886");
+ auto result = HMacer::hmac256(key, "value1", "value2", "value3");
+
+#ifdef DEBUG_CONFRIMATIONUI_UTILS_TEST
+ hexdump(std::cout, reinterpret_cast<const uint8_t*>(expected.data()), 32) << std::endl;
+ hexdump(std::cout, result.value().data(), 32) << std::endl;
+#endif
+
+ ByteBufferProxy expected_bytes(expected);
+ ASSERT_TRUE(result.isOk());
+ ASSERT_EQ(expected, result.value());
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ConfirmationUIAidlTest);
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, ConfirmationUIAidlTest,
+ testing::ValuesIn(::android::getAidlHalInstanceNames(IConfirmationUI::descriptor)),
+ ::android::PrintInstanceNameToString);
+
+} // namespace aidl::android::hardware::confirmationui::test
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ ABinderProcess_setThreadPoolMaxThreadCount(1);
+ ABinderProcess_startThreadPool();
+ return RUN_ALL_TESTS();
+}
diff --git a/confirmationui/support/Android.bp b/confirmationui/support/Android.bp
index 6ab83f2..1200115 100644
--- a/confirmationui/support/Android.bp
+++ b/confirmationui/support/Android.bp
@@ -36,7 +36,7 @@
],
export_include_dirs: [
"include",
- ]
+ ],
}
cc_test {
@@ -56,6 +56,5 @@
"libhidlbase",
],
test_suites: ["general-tests"],
- clang: true,
- cflags: [ "-O0" ],
+ cflags: ["-O0"],
}
diff --git a/current.txt b/current.txt
index afde7b1..146ded6 100644
--- a/current.txt
+++ b/current.txt
@@ -929,4 +929,7 @@
1bac6a7c8136dfb0414fe5639eec115aa2d12927e64a0642a43fb53225f099b2 android.hardware.wifi@1.6::IWifiStaIface
0a800e010e8eb6eecdfdc96f04fd2ae2f417a79a74a7c0eec3a9f539199bccd4 android.hardware.wifi@1.6::types
+# ABI preserving changes to HALs during Android U
+2aa559cda86c358c6429114ef6bc72c1b43281e98f9eb6b4df5e7073c8d05767 android.hardware.automotive.vehicle@2.0::types
+
# There will be no more HIDL HALs. Use AIDL instead.
diff --git a/drm/aidl/Android.bp b/drm/aidl/Android.bp
index 0fdba31..6273a38 100644
--- a/drm/aidl/Android.bp
+++ b/drm/aidl/Android.bp
@@ -23,9 +23,6 @@
sdk_version: "module_current",
},
ndk: {
- vndk: {
- enabled: true,
- },
min_sdk_version: "current",
},
},
diff --git a/dumpstate/aidl/Android.bp b/dumpstate/aidl/Android.bp
index b250d74..1eb8b32 100644
--- a/dumpstate/aidl/Android.bp
+++ b/dumpstate/aidl/Android.bp
@@ -34,11 +34,6 @@
enabled: true,
sdk_version: "module_current",
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
versions_with_info: [
{
diff --git a/fastboot/OWNERS b/fastboot/OWNERS
new file mode 100644
index 0000000..286b65f
--- /dev/null
+++ b/fastboot/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 1228891
+dvander@google.com
+elsk@google.com
+dhavale@google.com
diff --git a/fastboot/aidl/Android.bp b/fastboot/aidl/Android.bp
new file mode 100644
index 0000000..a5735ab
--- /dev/null
+++ b/fastboot/aidl/Android.bp
@@ -0,0 +1,38 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+aidl_interface {
+ name: "android.hardware.fastboot",
+ vendor_available: true,
+ recovery_available: true,
+ srcs: ["android/hardware/fastboot/*.aidl"],
+ stability: "vintf",
+ backend: {
+ cpp: {
+ enabled: false,
+ },
+ java: {
+ enabled: false,
+ },
+ },
+}
diff --git a/fastboot/aidl/aidl_api/android.hardware.fastboot/current/android/hardware/fastboot/FileSystemType.aidl b/fastboot/aidl/aidl_api/android.hardware.fastboot/current/android/hardware/fastboot/FileSystemType.aidl
new file mode 100644
index 0000000..b15d037
--- /dev/null
+++ b/fastboot/aidl/aidl_api/android.hardware.fastboot/current/android/hardware/fastboot/FileSystemType.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.fastboot;
+@Backing(type="byte") @VintfStability
+enum FileSystemType {
+ EXT4 = 0,
+ F2FS = 1,
+ RAW = 2,
+}
diff --git a/fastboot/aidl/aidl_api/android.hardware.fastboot/current/android/hardware/fastboot/IFastboot.aidl b/fastboot/aidl/aidl_api/android.hardware.fastboot/current/android/hardware/fastboot/IFastboot.aidl
new file mode 100644
index 0000000..445fcde
--- /dev/null
+++ b/fastboot/aidl/aidl_api/android.hardware.fastboot/current/android/hardware/fastboot/IFastboot.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.fastboot;
+@VintfStability
+interface IFastboot {
+ String doOemCommand(in String oemCmd);
+ void doOemSpecificErase();
+ int getBatteryVoltageFlashingThreshold();
+ boolean getOffModeChargeState();
+ android.hardware.fastboot.FileSystemType getPartitionType(in String partitionName);
+ String getVariant();
+ const int FAILURE_UNKNOWN = 1;
+}
diff --git a/fastboot/aidl/android/hardware/fastboot/FileSystemType.aidl b/fastboot/aidl/android/hardware/fastboot/FileSystemType.aidl
new file mode 100644
index 0000000..b4027ec
--- /dev/null
+++ b/fastboot/aidl/android/hardware/fastboot/FileSystemType.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.fastboot;
+
+@VintfStability
+@Backing(type="byte")
+enum FileSystemType {
+ /**
+ * Fourth extended file system.
+ */
+ EXT4,
+ /**
+ * Flash Friendly File System.
+ */
+ F2FS,
+ /**
+ * Raw file system.
+ */
+ RAW,
+}
diff --git a/fastboot/aidl/android/hardware/fastboot/IFastboot.aidl b/fastboot/aidl/android/hardware/fastboot/IFastboot.aidl
new file mode 100644
index 0000000..abdc215
--- /dev/null
+++ b/fastboot/aidl/android/hardware/fastboot/IFastboot.aidl
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.fastboot;
+
+import android.hardware.fastboot.FileSystemType;
+
+/**
+ * IFastboot interface implements vendor specific fastboot commands.
+ */
+@VintfStability
+interface IFastboot {
+ /**
+ * Status code for function.
+ * Operation failed due to unknown reason.
+ */
+ const int FAILURE_UNKNOWN = 1;
+ /**
+ * Executes a fastboot OEM command.
+ *
+ * @param oemCmd The oem command that is passed to the fastboot HAL.
+ * @return optional String if the operation is successful and output is expected
+ * for the command.
+ * @throws :
+ * - EX_ILLEGAL_ARGUMENT for bad arguments.
+ * - EX_UNSUPPORTED_OPERATION for unsupported commands.
+ * - EX_SERVICE_SPECIFIC with status FAILURE_UNKNOWN for other errors.
+ */
+ String doOemCommand(in String oemCmd);
+
+ /**
+ * Executes an OEM specific erase after fastboot erase userdata.
+ *
+ * @throws :
+ * - EX_UNSUPPORTED_OPERATION if it is not supported.
+ * - EX_SERVICE_SPECIFIC with status FAILURE_UNKNOWN for
+ * unknown error in oem specific command or other errors.
+ */
+ void doOemSpecificErase();
+
+ /**
+ * Returns the minimum battery voltage required for flashing in mV.
+ *
+ * @return Minimum batterery voltage (in mV) required for flashing to
+ * be successful.
+ * @throws :
+ * - EX_SERVICE_SPECIFIC with status FAILURE_UNKNOWN if error.
+ */
+ int getBatteryVoltageFlashingThreshold();
+
+ /**
+ * Returns whether off-mode-charging is enabled. If enabled, the device
+ * autoboots into a special mode when power is applied.
+ *
+ * @return Returns whether off-mode-charging is enabled.
+ * @throws :
+ * - EX_SERVICE_SPECIFIC with status FAILURE_UNKNOWN if error.
+ */
+ boolean getOffModeChargeState();
+
+ /**
+ * Returns the file system type of the partition. Implementation is only
+ * required for physical partitions that need to be wiped and reformatted.
+ * @param in partitionName Name of the partition.
+ * @return Returns the file system type of the partition. Type can be ext4,
+ * f2fs or raw.
+ * @throws :
+ * - EX_SERVICE_SPECIFIC with status FAILURE_UNKNOWN if the partition
+ * is invalid or does not require reformatting.
+ */
+ FileSystemType getPartitionType(in String partitionName);
+
+ /**
+ * Returns an OEM-defined string indicating the variant of the device, for
+ * example, US and ROW.
+ * @return Indicates the device variant.
+ * @throws :
+ * - EX_SERVICE_SPECIFIC with status FAILURE_UNKNOWN if error.
+ */
+ String getVariant();
+}
diff --git a/fastboot/aidl/default/Android.bp b/fastboot/aidl/default/Android.bp
new file mode 100644
index 0000000..0c96b33
--- /dev/null
+++ b/fastboot/aidl/default/Android.bp
@@ -0,0 +1,43 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_binary {
+ name: "android.hardware.fastboot-service.example_recovery",
+ init_rc: ["android.hardware.fastboot-service.example_recovery.rc"],
+ vintf_fragments: ["android.hardware.fastboot-service.example.xml"],
+ recovery_available: true,
+ srcs: [
+ "Fastboot.cpp",
+ "main.cpp",
+ ],
+ relative_install_path: "hw",
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "liblog",
+ "libutils",
+ "libcutils",
+ "android.hardware.fastboot-V1-ndk",
+ ],
+}
diff --git a/fastboot/aidl/default/Fastboot.cpp b/fastboot/aidl/default/Fastboot.cpp
new file mode 100644
index 0000000..1ba73d3
--- /dev/null
+++ b/fastboot/aidl/default/Fastboot.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Fastboot.h"
+
+using ndk::ScopedAStatus;
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace fastboot {
+
+ScopedAStatus Fastboot::getPartitionType(const std::string& in_partitionName,
+ FileSystemType* _aidl_return) {
+ if (in_partitionName.empty()) {
+ return ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "Invalid partition name");
+ }
+ *_aidl_return = FileSystemType::RAW;
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus Fastboot::doOemCommand(const std::string& in_oemCmd, std::string* _aidl_return) {
+ *_aidl_return = "";
+ if (in_oemCmd.empty()) {
+ return ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT, "Invalid command");
+ }
+ return ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_UNSUPPORTED_OPERATION, "Command not supported in default implementation");
+}
+
+ScopedAStatus Fastboot::getVariant(std::string* _aidl_return) {
+ *_aidl_return = "NA";
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus Fastboot::getOffModeChargeState(bool* _aidl_return) {
+ *_aidl_return = false;
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus Fastboot::getBatteryVoltageFlashingThreshold(int32_t* _aidl_return) {
+ *_aidl_return = 0;
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus Fastboot::doOemSpecificErase() {
+ return ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_UNSUPPORTED_OPERATION, "Command not supported in default implementation");
+}
+
+} // namespace fastboot
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/fastboot/aidl/default/Fastboot.h b/fastboot/aidl/default/Fastboot.h
new file mode 100644
index 0000000..48e2c38
--- /dev/null
+++ b/fastboot/aidl/default/Fastboot.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "aidl/android/hardware/fastboot/BnFastboot.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace fastboot {
+class Fastboot : public BnFastboot {
+ ::ndk::ScopedAStatus doOemCommand(const std::string& in_oemCmd,
+ std::string* _aidl_return) override;
+ ::ndk::ScopedAStatus doOemSpecificErase() override;
+ ::ndk::ScopedAStatus getBatteryVoltageFlashingThreshold(int32_t* _aidl_return) override;
+ ::ndk::ScopedAStatus getOffModeChargeState(bool* _aidl_return) override;
+ ::ndk::ScopedAStatus getPartitionType(
+ const std::string& in_partitionName,
+ ::aidl::android::hardware::fastboot::FileSystemType* _aidl_return) override;
+ ::ndk::ScopedAStatus getVariant(std::string* _aidl_return) override;
+};
+
+} // namespace fastboot
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/fastboot/aidl/default/android.hardware.fastboot-service.example.xml b/fastboot/aidl/default/android.hardware.fastboot-service.example.xml
new file mode 100644
index 0000000..9490f98
--- /dev/null
+++ b/fastboot/aidl/default/android.hardware.fastboot-service.example.xml
@@ -0,0 +1,8 @@
+<manifest version="1.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.fastboot</name>
+ <version>1</version>
+ <fqname>IFastboot/default</fqname>
+ </hal>
+</manifest>
+
diff --git a/fastboot/aidl/default/android.hardware.fastboot-service.example_recovery.rc b/fastboot/aidl/default/android.hardware.fastboot-service.example_recovery.rc
new file mode 100644
index 0000000..5d4ee13
--- /dev/null
+++ b/fastboot/aidl/default/android.hardware.fastboot-service.example_recovery.rc
@@ -0,0 +1,6 @@
+service vendor.fastboot-default /system/bin/hw/android.hardware.fastboot-service.example_recovery
+ class hal
+ seclabel u:r:hal_fastboot_default:s0
+ user system
+ group system
+ interface aidl android.hardware.fastboot.IFastboot/default
diff --git a/fastboot/aidl/default/main.cpp b/fastboot/aidl/default/main.cpp
new file mode 100644
index 0000000..1b1b41d
--- /dev/null
+++ b/fastboot/aidl/default/main.cpp
@@ -0,0 +1,38 @@
+
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include "Fastboot.h"
+
+using aidl::android::hardware::fastboot::Fastboot;
+using aidl::android::hardware::fastboot::IFastboot;
+
+int main(int, char* argv[]) {
+ android::base::InitLogging(argv, android::base::KernelLogger);
+ ABinderProcess_setThreadPoolMaxThreadCount(0);
+ std::shared_ptr<IFastboot> service = ndk::SharedRefBase::make<Fastboot>();
+
+ const std::string instance = std::string(IFastboot::descriptor) + "/default";
+ auto status = AServiceManager_addService(service->asBinder().get(), instance.c_str());
+ CHECK_EQ(status, STATUS_OK) << "Failed to add service " << instance << " " << status;
+ LOG(INFO) << "IFastboot AIDL service running...";
+
+ ABinderProcess_joinThreadPool();
+ return EXIT_FAILURE; // should not reach
+}
diff --git a/fastboot/aidl/fastbootshim/Android.bp b/fastboot/aidl/fastbootshim/Android.bp
new file mode 100644
index 0000000..c843c12
--- /dev/null
+++ b/fastboot/aidl/fastbootshim/Android.bp
@@ -0,0 +1,61 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_defaults {
+ name: "libfastbootshim_defaults",
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ static_libs: [
+ "android.hardware.fastboot-V1-ndk",
+ "android.hardware.fastboot@1.0",
+ "android.hardware.fastboot@1.1",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "libcutils",
+ "libhidlbase",
+ "liblog",
+ "libutils",
+ ],
+}
+
+// Shim library that wraps a HIDL Fastboot object into an AIDL Fastboot object.
+cc_library_static {
+ name: "libfastbootshim",
+ defaults: ["libfastbootshim_defaults"],
+ recovery_available: true,
+ srcs: [
+ "fastbootshim.cpp",
+ ],
+ export_include_dirs: [
+ "include",
+ ],
+}
diff --git a/fastboot/aidl/fastbootshim/fastbootshim.cpp b/fastboot/aidl/fastbootshim/fastbootshim.cpp
new file mode 100644
index 0000000..4ab67f3
--- /dev/null
+++ b/fastboot/aidl/fastbootshim/fastbootshim.cpp
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fastbootshim.h>
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::Void;
+using ::android::hardware::fastboot::V1_0::FileSystemType;
+using ::android::hardware::fastboot::V1_0::Result;
+using ::android::hardware::fastboot::V1_0::Status;
+
+using ndk::ScopedAStatus;
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace fastboot {
+ScopedAStatus ResultToAStatus(Result result) {
+ switch (result.status) {
+ case Status::SUCCESS:
+ return ScopedAStatus::ok();
+ case Status::NOT_SUPPORTED:
+ return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ case Status::INVALID_ARGUMENT:
+ return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ case Status::FAILURE_UNKNOWN:
+ return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+ BnFastboot::FAILURE_UNKNOWN, ("Error " + std::string(result.message)).c_str());
+ }
+ return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+ BnFastboot::FAILURE_UNKNOWN,
+ ("Unrecognized status value " + toString(result.status)).c_str());
+}
+FastbootShim::FastbootShim(const sp<HidlFastboot>& service) : service_(service) {}
+
+ScopedAStatus FastbootShim::getPartitionType(const std::string& in_partitionName,
+ FileSystemType* _aidl_return) {
+ Result out_result = {Status::FAILURE_UNKNOWN, ""};
+ if (in_partitionName.empty()) {
+ return ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "Invalid partition name");
+ }
+ const hidl_string partition = in_partitionName;
+ auto ret = service_->getPartitionType(partition, [&](auto type, auto& result) {
+ out_result = result;
+ if (out_result.status != Status::SUCCESS) return;
+ *_aidl_return = static_cast<aidl::android::hardware::fastboot::FileSystemType>(type);
+ });
+ return ResultToAStatus(out_result);
+}
+
+ScopedAStatus FastbootShim::doOemCommand(const std::string& in_oemCmd, std::string* _aidl_return) {
+ Result out_result = {Status::FAILURE_UNKNOWN, ""};
+ *_aidl_return = "";
+ if (in_oemCmd.empty()) {
+ return ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT, "Invalid command");
+ }
+ const hidl_string oemCmdArgs = in_oemCmd;
+ auto ret = service_->doOemCommand(oemCmdArgs, [&](auto& result) {
+ out_result = result;
+ if (out_result.status != Status::SUCCESS) return;
+ *_aidl_return = std::string(result.message.c_str());
+ });
+ return ResultToAStatus(out_result);
+}
+
+ScopedAStatus FastbootShim::getVariant(std::string* _aidl_return) {
+ Result out_result = {Status::FAILURE_UNKNOWN, ""};
+ *_aidl_return = "";
+ auto ret = service_->getVariant([&](auto& variant, auto& result) {
+ out_result = result;
+ if (out_result.status != Status::SUCCESS) return;
+ *_aidl_return = std::string(variant.c_str());
+ });
+ return ResultToAStatus(out_result);
+}
+
+ScopedAStatus FastbootShim::getOffModeChargeState(bool* _aidl_return) {
+ Result out_result = {Status::FAILURE_UNKNOWN, ""};
+ *_aidl_return = false;
+ auto ret = service_->getOffModeChargeState([&](auto state, auto& result) {
+ out_result = result;
+ if (out_result.status != Status::SUCCESS) return;
+ *_aidl_return = state;
+ });
+ return ResultToAStatus(out_result);
+}
+
+ScopedAStatus FastbootShim::getBatteryVoltageFlashingThreshold(int32_t* _aidl_return) {
+ Result out_result = {Status::FAILURE_UNKNOWN, ""};
+ *_aidl_return = 0;
+ auto ret = service_->getBatteryVoltageFlashingThreshold([&](auto batteryVoltage, auto& result) {
+ out_result = result;
+ if (out_result.status != Status::SUCCESS) return;
+ *_aidl_return = batteryVoltage;
+ });
+ return ResultToAStatus(out_result);
+}
+
+ScopedAStatus FastbootShim::doOemSpecificErase() {
+ Result out_result = {Status::FAILURE_UNKNOWN, ""};
+ auto ret = service_->doOemSpecificErase([&](auto& result) { out_result = result; });
+ return ResultToAStatus(out_result);
+}
+
+} // namespace fastboot
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/fastboot/aidl/fastbootshim/include/fastbootshim.h b/fastboot/aidl/fastbootshim/include/fastbootshim.h
new file mode 100644
index 0000000..410a03e
--- /dev/null
+++ b/fastboot/aidl/fastbootshim/include/fastbootshim.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/fastboot/BnFastboot.h>
+#include <android/hardware/fastboot/1.1/IFastboot.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace fastboot {
+// Shim that wraps HIDL IFastboot with AIDL BnFastboot
+class FastbootShim : public BnFastboot {
+ using HidlFastboot = ::android::hardware::fastboot::V1_1::IFastboot;
+
+ public:
+ explicit FastbootShim(const ::android::sp<HidlFastboot>& service);
+ ::ndk::ScopedAStatus doOemCommand(const std::string& in_oemCmd,
+ std::string* _aidl_return) override;
+ ::ndk::ScopedAStatus doOemSpecificErase() override;
+ ::ndk::ScopedAStatus getBatteryVoltageFlashingThreshold(int32_t* _aidl_return) override;
+ ::ndk::ScopedAStatus getOffModeChargeState(bool* _aidl_return) override;
+ ::ndk::ScopedAStatus getPartitionType(
+ const std::string& in_partitionName,
+ ::aidl::android::hardware::fastboot::FileSystemType* _aidl_return) override;
+ ::ndk::ScopedAStatus getVariant(std::string* _aidl_return) override;
+
+ private:
+ ::android::sp<HidlFastboot> service_;
+};
+
+} // namespace fastboot
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/gatekeeper/1.0/vts/OWNERS b/gatekeeper/1.0/vts/OWNERS
index 738c710..ee2af97 100644
--- a/gatekeeper/1.0/vts/OWNERS
+++ b/gatekeeper/1.0/vts/OWNERS
@@ -1,3 +1,3 @@
-jdanis@google.com
+# Bug component: 1124862
swillden@google.com
guangzhu@google.com
diff --git a/gatekeeper/1.0/vts/functional/VtsHalGatekeeperV1_0TargetTest.cpp b/gatekeeper/1.0/vts/functional/VtsHalGatekeeperV1_0TargetTest.cpp
index f3fa0b4..e938b01 100644
--- a/gatekeeper/1.0/vts/functional/VtsHalGatekeeperV1_0TargetTest.cpp
+++ b/gatekeeper/1.0/vts/functional/VtsHalGatekeeperV1_0TargetTest.cpp
@@ -244,6 +244,47 @@
}
/**
+ * Ensure that passwords containing a NUL byte aren't truncated
+ */
+TEST_P(GatekeeperHidlTest, PasswordIsBinaryData) {
+ GatekeeperResponse enrollRsp;
+ GatekeeperResponse verifyRsp;
+ hidl_vec<uint8_t> rightPassword = {'A', 'B', 'C', '\0', 'D', 'E', 'F'};
+ hidl_vec<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(GatekeeperHidlTest, LongPassword) {
+ GatekeeperResponse enrollRsp;
+ GatekeeperResponse verifyRsp;
+ hidl_vec<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/gatekeeper/OWNERS b/gatekeeper/OWNERS
new file mode 100644
index 0000000..fddc2ff
--- /dev/null
+++ b/gatekeeper/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 1124862
+swillden@google.com
+guangzhu@google.com
+subrahmanyaman@google.com
diff --git a/gatekeeper/aidl/Android.bp b/gatekeeper/aidl/Android.bp
new file mode 100644
index 0000000..770e8ab
--- /dev/null
+++ b/gatekeeper/aidl/Android.bp
@@ -0,0 +1,29 @@
+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.gatekeeper",
+ vendor_available: true,
+ imports: [
+ "android.hardware.security.keymint-V3",
+ ],
+ srcs: ["android/hardware/gatekeeper/*.aidl"],
+ stability: "vintf",
+ backend: {
+ java: {
+ platform_apis: true,
+ },
+ ndk: {
+ apps_enabled: false,
+ },
+ cpp: {
+ enabled: false,
+ },
+ },
+}
diff --git a/gatekeeper/aidl/aidl_api/android.hardware.gatekeeper/current/android/hardware/gatekeeper/GatekeeperEnrollResponse.aidl b/gatekeeper/aidl/aidl_api/android.hardware.gatekeeper/current/android/hardware/gatekeeper/GatekeeperEnrollResponse.aidl
new file mode 100644
index 0000000..ae64ffc
--- /dev/null
+++ b/gatekeeper/aidl/aidl_api/android.hardware.gatekeeper/current/android/hardware/gatekeeper/GatekeeperEnrollResponse.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.gatekeeper;
+@VintfStability
+parcelable GatekeeperEnrollResponse {
+ int statusCode;
+ int timeoutMs;
+ long secureUserId;
+ byte[] data;
+}
diff --git a/gatekeeper/aidl/aidl_api/android.hardware.gatekeeper/current/android/hardware/gatekeeper/GatekeeperVerifyResponse.aidl b/gatekeeper/aidl/aidl_api/android.hardware.gatekeeper/current/android/hardware/gatekeeper/GatekeeperVerifyResponse.aidl
new file mode 100644
index 0000000..f55da30
--- /dev/null
+++ b/gatekeeper/aidl/aidl_api/android.hardware.gatekeeper/current/android/hardware/gatekeeper/GatekeeperVerifyResponse.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.gatekeeper;
+@VintfStability
+parcelable GatekeeperVerifyResponse {
+ int statusCode;
+ int timeoutMs;
+ android.hardware.security.keymint.HardwareAuthToken hardwareAuthToken;
+}
diff --git a/gatekeeper/aidl/aidl_api/android.hardware.gatekeeper/current/android/hardware/gatekeeper/IGatekeeper.aidl b/gatekeeper/aidl/aidl_api/android.hardware.gatekeeper/current/android/hardware/gatekeeper/IGatekeeper.aidl
new file mode 100644
index 0000000..1a6f1ff
--- /dev/null
+++ b/gatekeeper/aidl/aidl_api/android.hardware.gatekeeper/current/android/hardware/gatekeeper/IGatekeeper.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.gatekeeper;
+@SensitiveData @VintfStability
+interface IGatekeeper {
+ void deleteAllUsers();
+ void deleteUser(in int uid);
+ android.hardware.gatekeeper.GatekeeperEnrollResponse enroll(in int uid, in byte[] currentPasswordHandle, in byte[] currentPassword, in byte[] desiredPassword);
+ android.hardware.gatekeeper.GatekeeperVerifyResponse verify(in int uid, in long challenge, in byte[] enrolledPasswordHandle, in byte[] providedPassword);
+ const int STATUS_REENROLL = 1;
+ const int STATUS_OK = 0;
+ const int ERROR_GENERAL_FAILURE = -1;
+ const int ERROR_RETRY_TIMEOUT = -2;
+ const int ERROR_NOT_IMPLEMENTED = -3;
+}
diff --git a/gatekeeper/aidl/android/hardware/gatekeeper/GatekeeperEnrollResponse.aidl b/gatekeeper/aidl/android/hardware/gatekeeper/GatekeeperEnrollResponse.aidl
new file mode 100644
index 0000000..04bacf0
--- /dev/null
+++ b/gatekeeper/aidl/android/hardware/gatekeeper/GatekeeperEnrollResponse.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.gatekeeper;
+
+/**
+ * Gatekeeper response to enroll requests has this structure as mandatory part
+ */
+@VintfStability
+parcelable GatekeeperEnrollResponse {
+ /**
+ * Request completion status
+ */
+ int statusCode;
+ /**
+ * Retry timeout in ms, if code == ERROR_RETRY_TIMEOUT
+ * otherwise unused (0)
+ */
+ int timeoutMs;
+ /**
+ * secure user id.
+ */
+ long secureUserId;
+ /**
+ * optional crypto blob. Opaque to Android system.
+ */
+ byte[] data;
+}
diff --git a/gatekeeper/aidl/android/hardware/gatekeeper/GatekeeperVerifyResponse.aidl b/gatekeeper/aidl/android/hardware/gatekeeper/GatekeeperVerifyResponse.aidl
new file mode 100644
index 0000000..bcf2d76
--- /dev/null
+++ b/gatekeeper/aidl/android/hardware/gatekeeper/GatekeeperVerifyResponse.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.gatekeeper;
+
+import android.hardware.security.keymint.HardwareAuthToken;
+
+/**
+ * Gatekeeper response to verify requests has this structure as mandatory part
+ */
+@VintfStability
+parcelable GatekeeperVerifyResponse {
+ /**
+ * Request completion status
+ */
+ int statusCode;
+ /**
+ * Retry timeout in ms, if code == ERROR_RETRY_TIMEOUT
+ * otherwise unused (0)
+ */
+ int timeoutMs;
+ /**
+ * On successful verification of the password,
+ * IGatekeeper implementations must return hardware auth token
+ * in the response.
+ */
+ HardwareAuthToken hardwareAuthToken;
+}
diff --git a/gatekeeper/aidl/android/hardware/gatekeeper/IGatekeeper.aidl b/gatekeeper/aidl/android/hardware/gatekeeper/IGatekeeper.aidl
new file mode 100644
index 0000000..927293e
--- /dev/null
+++ b/gatekeeper/aidl/android/hardware/gatekeeper/IGatekeeper.aidl
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.gatekeeper;
+
+import android.hardware.gatekeeper.GatekeeperEnrollResponse;
+import android.hardware.gatekeeper.GatekeeperVerifyResponse;
+
+@VintfStability
+@SensitiveData
+interface IGatekeeper {
+ /**
+ * enroll and verify binder calls may return a ServiceSpecificException
+ * with the following error codes.
+ */
+ /* Success, but upper layers should re-enroll the verified password due to a version change. */
+ const int STATUS_REENROLL = 1;
+ /* operation is successful */
+ const int STATUS_OK = 0;
+ /* operation is successful. */
+ const int ERROR_GENERAL_FAILURE = -1;
+ /* operation should be retried after timeout. */
+ const int ERROR_RETRY_TIMEOUT = -2;
+ /* operation is not implemented. */
+ const int ERROR_NOT_IMPLEMENTED = -3;
+
+ /**
+ * Deletes all the enrolled_password_handles for all uid's. Once called,
+ * no users must be enrolled on the device.
+ * This is an optional method.
+ *
+ * Service status return:
+ *
+ * OK if all the users are deleted successfully.
+ * ERROR_GENERAL_FAILURE on failure.
+ * ERROR_NOT_IMPLEMENTED if not implemented.
+ */
+ void deleteAllUsers();
+
+ /**
+ * Deletes the enrolledPasswordHandle associated with the uid. Once deleted
+ * the user cannot be verified anymore.
+ * This is an optional method.
+ *
+ * Service status return:
+ *
+ * OK if user is deleted successfully.
+ * ERROR_GENERAL_FAILURE on failure.
+ * ERROR_NOT_IMPLEMENTED if not implemented.
+ *
+ * @param uid The Android user identifier
+ */
+ void deleteUser(in int uid);
+
+ /**
+ * Enrolls desiredPassword, which may be derived from a user selected pin
+ * or password, with the private key used only for enrolling authentication
+ * factor data.
+ *
+ * If there was already a password enrolled, current password handle must be
+ * passed in currentPasswordHandle, and current password must be passed in
+ * currentPassword. Valid currentPassword must verify() against
+ * currentPasswordHandle.
+ *
+ * Service status return:
+ *
+ * OK if password is enrolled successfully.
+ * ERROR_GENERAL_FAILURE on failure.
+ * ERROR_NOT_IMPLEMENTED if not implemented.
+ *
+ * @param uid The Android user identifier
+ *
+ * @param currentPasswordHandle The currently enrolled password handle the user
+ * wants to replace. May be empty only if there's no currently enrolled
+ * password. Otherwise must be non-empty.
+ *
+ * @param currentPassword The user's current password in plain text.
+ * it MUST verify against current_password_handle if the latter is not-empty
+ *
+ * @param desiredPassword The new password the user wishes to enroll in
+ * plaintext.
+ *
+ * @return
+ * On success, data buffer must contain the new password handle referencing
+ * the password provided in desiredPassword.
+ * This buffer can be used on subsequent calls to enroll or
+ * verify. response.statusCode must contain either ERROR_RETRY_TIMEOUT or
+ * STATUS_OK. On error, this buffer must be empty. This method may return
+ * ERROR_GENERAL_FAILURE on failure.
+ * If ERROR_RETRY_TIMEOUT is returned, response.timeout must be non-zero.
+ */
+ GatekeeperEnrollResponse enroll(in int uid, in byte[] currentPasswordHandle,
+ in byte[] currentPassword, in byte[] desiredPassword);
+
+ /**
+ * Verifies that providedPassword matches enrolledPasswordHandle.
+ *
+ * Implementations of this module may retain the result of this call
+ * to attest to the recency of authentication.
+ *
+ * On success, returns verification token in response.data, which shall be
+ * usable to attest password verification to other trusted services.
+ *
+ * Service status return:
+ *
+ * OK if password is enrolled successfully.
+ * ERROR_GENERAL_FAILURE on failure.
+ * ERROR_NOT_IMPLEMENTED if not implemented.
+ *
+ * @param uid The Android user identifier
+ *
+ * @param challenge An optional challenge to authenticate against, or 0.
+ * Used when a separate authenticator requests password verification,
+ * or for transactional password authentication.
+ *
+ * @param enrolledPasswordHandle The currently enrolled password handle that
+ * user wishes to verify against. Must be non-empty.
+ *
+ * @param providedPassword The plaintext password to be verified against the
+ * enrolledPasswordHandle
+ *
+ * @return
+ * On success, a HardwareAuthToken resulting from this verification is returned.
+ * response.statusCode must contain either ERROR_RETRY_TIMEOUT or
+ * or STATUS_REENROLL or STATUS_OK.
+ * On error, data buffer must be empty.
+ * This method may return ERROR_GENERAL_FAILURE on failure.
+ * If password re-enrollment is necessary, it must return STATUS_REENROLL.
+ * If ERROR_RETRY_TIMEOUT is returned, response.timeout must be non-zero.
+ */
+ GatekeeperVerifyResponse verify(in int uid, in long challenge, in byte[] enrolledPasswordHandle,
+ in byte[] providedPassword);
+}
diff --git a/gatekeeper/aidl/vts/functional/Android.bp b/gatekeeper/aidl/vts/functional/Android.bp
new file mode 100644
index 0000000..2fa80de
--- /dev/null
+++ b/gatekeeper/aidl/vts/functional/Android.bp
@@ -0,0 +1,39 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_test {
+ name: "VtsHalGatekeeperTargetTest",
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "use_libaidlvintf_gtest_helper_static",
+ "keymint_use_latest_hal_aidl_ndk_shared",
+ ],
+ srcs: ["VtsHalGatekeeperTargetTest.cpp"],
+ shared_libs: [
+ "libbinder_ndk",
+ "libbase",
+ ],
+ static_libs: ["android.hardware.gatekeeper-V1-ndk"],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+}
diff --git a/gatekeeper/aidl/vts/functional/VtsHalGatekeeperTargetTest.cpp b/gatekeeper/aidl/vts/functional/VtsHalGatekeeperTargetTest.cpp
new file mode 100644
index 0000000..c89243b
--- /dev/null
+++ b/gatekeeper/aidl/vts/functional/VtsHalGatekeeperTargetTest.cpp
@@ -0,0 +1,413 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "gatekeeper_aidl_hal_test"
+
+#include <inttypes.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <cmath>
+#include <string>
+#include <vector>
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/gatekeeper/GatekeeperEnrollResponse.h>
+#include <aidl/android/hardware/gatekeeper/GatekeeperVerifyResponse.h>
+#include <aidl/android/hardware/gatekeeper/IGatekeeper.h>
+#include <aidl/android/hardware/security/keymint/HardwareAuthToken.h>
+#include <android-base/endian.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <hardware/hw_auth_token.h>
+
+#include <log/log.h>
+
+using aidl::android::hardware::gatekeeper::GatekeeperEnrollResponse;
+using aidl::android::hardware::gatekeeper::GatekeeperVerifyResponse;
+using aidl::android::hardware::gatekeeper::IGatekeeper;
+using aidl::android::hardware::security::keymint::HardwareAuthToken;
+using Status = ::ndk::ScopedAStatus;
+
+struct GatekeeperRequest {
+ uint32_t uid;
+ uint64_t challenge;
+ std::vector<uint8_t> curPwdHandle;
+ std::vector<uint8_t> curPwd;
+ std::vector<uint8_t> newPwd;
+ GatekeeperRequest() : uid(0), challenge(0) {}
+};
+
+// ASSERT_* macros generate return "void" internally
+// we have to use EXPECT_* if we return anything but "void"
+static void verifyAuthToken(GatekeeperVerifyResponse& rsp) {
+ uint32_t auth_type = static_cast<uint32_t>(rsp.hardwareAuthToken.authenticatorType);
+ uint64_t auth_tstamp = static_cast<uint64_t>(rsp.hardwareAuthToken.timestamp.milliSeconds);
+
+ EXPECT_EQ(HW_AUTH_PASSWORD, auth_type);
+ EXPECT_NE(UINT64_C(~0), auth_tstamp);
+ ALOGI("Authenticator ID: %016" PRIX64, rsp.hardwareAuthToken.authenticatorId);
+ EXPECT_NE(UINT32_C(0), rsp.hardwareAuthToken.userId);
+}
+
+// The main test class for Gatekeeper AIDL HAL.
+class GatekeeperAidlTest : public ::testing::TestWithParam<std::string> {
+ protected:
+ void setUid(uint32_t uid) { uid_ = uid; }
+
+ Status doEnroll(GatekeeperRequest& req, GatekeeperEnrollResponse& rsp) {
+ Status ret;
+ while (true) {
+ ret = gatekeeper_->enroll(uid_, req.curPwdHandle, req.curPwd, req.newPwd, &rsp);
+ if (ret.isOk()) break;
+ if (getReturnStatusCode(ret) != IGatekeeper::ERROR_RETRY_TIMEOUT) break;
+ ALOGI("%s: got retry code; retrying in 1 sec", __func__);
+ sleep(1);
+ }
+ return ret;
+ }
+
+ Status doVerify(GatekeeperRequest& req, GatekeeperVerifyResponse& rsp) {
+ Status ret;
+ while (true) {
+ ret = gatekeeper_->verify(uid_, req.challenge, req.curPwdHandle, req.newPwd, &rsp);
+ if (ret.isOk()) break;
+ if (getReturnStatusCode(ret) != IGatekeeper::ERROR_RETRY_TIMEOUT) break;
+ ALOGI("%s: got retry code; retrying in 1 sec", __func__);
+ sleep(1);
+ }
+ return ret;
+ }
+
+ Status doDeleteUser() { return gatekeeper_->deleteUser(uid_); }
+
+ Status doDeleteAllUsers() { return gatekeeper_->deleteAllUsers(); }
+
+ void generatePassword(std::vector<uint8_t>& password, uint8_t seed) {
+ password.resize(16);
+ memset(password.data(), seed, password.size());
+ }
+
+ void checkEnroll(GatekeeperEnrollResponse& rsp, Status& ret, bool expectSuccess) {
+ if (expectSuccess) {
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(IGatekeeper::STATUS_OK, rsp.statusCode);
+ EXPECT_NE(nullptr, rsp.data.data());
+ EXPECT_GT(rsp.data.size(), UINT32_C(0));
+ EXPECT_NE(UINT32_C(0), rsp.secureUserId);
+ } else {
+ EXPECT_EQ(IGatekeeper::ERROR_GENERAL_FAILURE, getReturnStatusCode(ret));
+ EXPECT_EQ(UINT32_C(0), rsp.data.size());
+ }
+ }
+
+ void checkVerify(GatekeeperVerifyResponse& rsp, Status& ret, uint64_t challenge,
+ bool expectSuccess) {
+ if (expectSuccess) {
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_GE(rsp.statusCode, IGatekeeper::STATUS_OK);
+ EXPECT_LE(rsp.statusCode, IGatekeeper::STATUS_REENROLL);
+
+ verifyAuthToken(rsp);
+ EXPECT_EQ(challenge, rsp.hardwareAuthToken.challenge);
+ } else {
+ EXPECT_EQ(IGatekeeper::ERROR_GENERAL_FAILURE, getReturnStatusCode(ret));
+ }
+ }
+
+ void enrollNewPassword(std::vector<uint8_t>& password, GatekeeperEnrollResponse& rsp,
+ bool expectSuccess) {
+ GatekeeperRequest req;
+ req.newPwd = password;
+ Status ret = doEnroll(req, rsp);
+ checkEnroll(rsp, ret, expectSuccess);
+ }
+
+ void verifyPassword(std::vector<uint8_t>& password, std::vector<uint8_t>& passwordHandle,
+ uint64_t challenge, GatekeeperVerifyResponse& verifyRsp,
+ bool expectSuccess) {
+ GatekeeperRequest verifyReq;
+
+ // build verify request for the same password (we want it to succeed)
+ verifyReq.newPwd = password;
+ // use enrolled password handle we've got
+ verifyReq.curPwdHandle = passwordHandle;
+ verifyReq.challenge = challenge;
+ Status ret = doVerify(verifyReq, verifyRsp);
+ checkVerify(verifyRsp, ret, challenge, expectSuccess);
+ }
+
+ int32_t getReturnStatusCode(const Status& result) {
+ if (!result.isOk()) {
+ if (result.getExceptionCode() == EX_SERVICE_SPECIFIC) {
+ return result.getServiceSpecificError();
+ }
+ return IGatekeeper::ERROR_GENERAL_FAILURE;
+ }
+ return IGatekeeper::STATUS_OK;
+ }
+
+ protected:
+ std::shared_ptr<IGatekeeper> gatekeeper_;
+ uint32_t uid_;
+
+ public:
+ GatekeeperAidlTest() : uid_(0) {}
+ virtual void SetUp() override {
+ gatekeeper_ = IGatekeeper::fromBinder(
+ ndk::SpAIBinder(AServiceManager_waitForService(GetParam().c_str())));
+ ASSERT_NE(nullptr, gatekeeper_.get());
+ doDeleteAllUsers();
+ }
+
+ virtual void TearDown() override { doDeleteAllUsers(); }
+};
+
+/**
+ * Ensure we can enroll new password
+ */
+TEST_P(GatekeeperAidlTest, EnrollSuccess) {
+ std::vector<uint8_t> password;
+ GatekeeperEnrollResponse rsp;
+ ALOGI("Testing Enroll (expected success)");
+ generatePassword(password, 0);
+ enrollNewPassword(password, rsp, true);
+ ALOGI("Testing Enroll done");
+}
+
+/**
+ * Ensure we can not enroll empty password
+ */
+TEST_P(GatekeeperAidlTest, EnrollNoPassword) {
+ std::vector<uint8_t> password;
+ GatekeeperEnrollResponse rsp;
+ ALOGI("Testing Enroll (expected failure)");
+ enrollNewPassword(password, rsp, false);
+ ALOGI("Testing Enroll done");
+}
+
+/**
+ * Ensure we can successfully verify previously enrolled password
+ */
+TEST_P(GatekeeperAidlTest, VerifySuccess) {
+ GatekeeperEnrollResponse enrollRsp;
+ GatekeeperVerifyResponse verifyRsp;
+ std::vector<uint8_t> password;
+
+ ALOGI("Testing Enroll+Verify (expected success)");
+ generatePassword(password, 0);
+ enrollNewPassword(password, enrollRsp, true);
+ verifyPassword(password, enrollRsp.data, 1, verifyRsp, true);
+
+ ALOGI("Testing unenrolled password doesn't verify");
+ verifyRsp = {0, 0, {}};
+ generatePassword(password, 1);
+ verifyPassword(password, enrollRsp.data, 1, verifyRsp, false);
+ ALOGI("Testing Enroll+Verify done");
+}
+
+/**
+ * Ensure we can securely update password (keep the same
+ * secure user_id) if we prove we know old password
+ */
+TEST_P(GatekeeperAidlTest, TrustedReenroll) {
+ GatekeeperEnrollResponse enrollRsp;
+ GatekeeperRequest reenrollReq;
+ GatekeeperEnrollResponse reenrollRsp;
+ GatekeeperVerifyResponse verifyRsp;
+ GatekeeperVerifyResponse reenrollVerifyRsp;
+ std::vector<uint8_t> password;
+ std::vector<uint8_t> newPassword;
+
+ generatePassword(password, 0);
+
+ ALOGI("Testing Trusted Reenroll (expected success)");
+ enrollNewPassword(password, enrollRsp, true);
+ verifyPassword(password, enrollRsp.data, 0, verifyRsp, true);
+ ALOGI("Primary Enroll+Verify done");
+
+ generatePassword(newPassword, 1);
+ reenrollReq.newPwd = newPassword;
+ reenrollReq.curPwd = password;
+ reenrollReq.curPwdHandle = enrollRsp.data;
+
+ Status ret = doEnroll(reenrollReq, reenrollRsp);
+ checkEnroll(reenrollRsp, ret, true);
+ verifyPassword(newPassword, reenrollRsp.data, 0, reenrollVerifyRsp, true);
+ ALOGI("Trusted ReEnroll+Verify done");
+
+ verifyAuthToken(verifyRsp);
+ verifyAuthToken(reenrollVerifyRsp);
+ EXPECT_EQ(verifyRsp.hardwareAuthToken.userId, reenrollVerifyRsp.hardwareAuthToken.userId);
+ ALOGI("Testing Trusted Reenroll done");
+}
+
+/**
+ * Ensure we can update password (and get new
+ * secure user_id) if we don't know old password
+ */
+TEST_P(GatekeeperAidlTest, UntrustedReenroll) {
+ GatekeeperEnrollResponse enrollRsp;
+ GatekeeperEnrollResponse reenrollRsp;
+ GatekeeperVerifyResponse verifyRsp;
+ GatekeeperVerifyResponse reenrollVerifyRsp;
+ std::vector<uint8_t> password;
+ std::vector<uint8_t> newPassword;
+
+ ALOGI("Testing Untrusted Reenroll (expected success)");
+ generatePassword(password, 0);
+ enrollNewPassword(password, enrollRsp, true);
+ verifyPassword(password, enrollRsp.data, 0, verifyRsp, true);
+ ALOGI("Primary Enroll+Verify done");
+
+ generatePassword(newPassword, 1);
+ enrollNewPassword(newPassword, reenrollRsp, true);
+ verifyPassword(newPassword, reenrollRsp.data, 0, reenrollVerifyRsp, true);
+ ALOGI("Untrusted ReEnroll+Verify done");
+
+ verifyAuthToken(verifyRsp);
+ verifyAuthToken(reenrollVerifyRsp);
+ EXPECT_NE(verifyRsp.hardwareAuthToken.userId, reenrollVerifyRsp.hardwareAuthToken.userId);
+ ALOGI("Testing Untrusted Reenroll done");
+}
+
+/**
+ * Ensure we don't get successful verify with invalid data
+ */
+TEST_P(GatekeeperAidlTest, VerifyNoData) {
+ std::vector<uint8_t> password;
+ std::vector<uint8_t> passwordHandle;
+ GatekeeperVerifyResponse verifyRsp;
+
+ ALOGI("Testing Verify (expected failure)");
+ verifyPassword(password, passwordHandle, 0, verifyRsp, false);
+ ALOGI("Testing Verify done");
+}
+
+/**
+ * Ensure we can not verify password after we enrolled it and then deleted user
+ */
+TEST_P(GatekeeperAidlTest, DeleteUserTest) {
+ std::vector<uint8_t> password;
+ GatekeeperEnrollResponse enrollRsp;
+ GatekeeperVerifyResponse verifyRsp;
+ ALOGI("Testing deleteUser (expected success)");
+ setUid(10001);
+ generatePassword(password, 0);
+ enrollNewPassword(password, enrollRsp, true);
+ verifyPassword(password, enrollRsp.data, 0, verifyRsp, true);
+ ALOGI("Enroll+Verify done");
+ auto result = doDeleteUser();
+ EXPECT_TRUE(result.isOk() ||
+ (getReturnStatusCode(result) == IGatekeeper::ERROR_NOT_IMPLEMENTED));
+ ALOGI("DeleteUser done");
+ if (result.isOk()) {
+ verifyRsp = {0, 0, {}};
+ verifyPassword(password, enrollRsp.data, 0, verifyRsp, false);
+ ALOGI("Verify after Delete done (must fail)");
+ }
+ ALOGI("Testing deleteUser done: rsp=%" PRIi32, getReturnStatusCode(result));
+}
+
+/**
+ * Ensure we can not delete a user that does not exist
+ */
+TEST_P(GatekeeperAidlTest, DeleteInvalidUserTest) {
+ std::vector<uint8_t> password;
+ GatekeeperEnrollResponse enrollRsp;
+ GatekeeperVerifyResponse verifyRsp;
+ ALOGI("Testing deleteUser (expected failure)");
+ setUid(10002);
+ generatePassword(password, 0);
+ enrollNewPassword(password, enrollRsp, true);
+ verifyPassword(password, enrollRsp.data, 0, verifyRsp, true);
+ ALOGI("Enroll+Verify done");
+
+ // Delete the user
+ Status result1 = doDeleteUser();
+ EXPECT_TRUE(result1.isOk() ||
+ (getReturnStatusCode(result1) == IGatekeeper::ERROR_NOT_IMPLEMENTED));
+
+ // Delete the user again
+ Status result2 = doDeleteUser();
+ int32_t retCode2 = getReturnStatusCode(result2);
+ EXPECT_TRUE((retCode2 == IGatekeeper::ERROR_NOT_IMPLEMENTED) ||
+ (retCode2 == IGatekeeper::ERROR_GENERAL_FAILURE));
+ ALOGI("DeleteUser done");
+ ALOGI("Testing deleteUser done: rsp=%" PRIi32, retCode2);
+}
+
+/**
+ * Ensure we can not verify passwords after we enrolled them and then deleted
+ * all users
+ */
+TEST_P(GatekeeperAidlTest, DeleteAllUsersTest) {
+ struct UserData {
+ uint32_t userId;
+ std::vector<uint8_t> password;
+ GatekeeperEnrollResponse enrollRsp;
+ GatekeeperVerifyResponse verifyRsp;
+ UserData(int id) { userId = id; }
+ } users[3]{10001, 10002, 10003};
+ ALOGI("Testing deleteAllUsers (expected success)");
+
+ // enroll multiple users
+ for (size_t i = 0; i < sizeof(users) / sizeof(users[0]); ++i) {
+ setUid(users[i].userId);
+ generatePassword(users[i].password, (i % 255) + 1);
+ enrollNewPassword(users[i].password, users[i].enrollRsp, true);
+ }
+ ALOGI("Multiple users enrolled");
+
+ // verify multiple users
+ for (size_t i = 0; i < sizeof(users) / sizeof(users[0]); ++i) {
+ setUid(users[i].userId);
+ verifyPassword(users[i].password, users[i].enrollRsp.data, 0, users[i].verifyRsp, true);
+ }
+ ALOGI("Multiple users verified");
+
+ Status result = doDeleteAllUsers();
+ EXPECT_TRUE(result.isOk() ||
+ (getReturnStatusCode(result) == IGatekeeper::ERROR_NOT_IMPLEMENTED));
+ ALOGI("All users deleted");
+
+ if (result.isOk()) {
+ // verify multiple users after they are deleted; all must fail
+ for (size_t i = 0; i < sizeof(users) / sizeof(users[0]); ++i) {
+ setUid(users[i].userId);
+ users[i].verifyRsp = {0, 0, {}};
+ verifyPassword(users[i].password, users[i].enrollRsp.data, 0, users[i].verifyRsp,
+ false);
+ }
+ ALOGI("Multiple users verified after delete (all must fail)");
+ }
+
+ ALOGI("Testing deleteAllUsers done: rsp=%" PRIi32, getReturnStatusCode(result));
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GatekeeperAidlTest);
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, GatekeeperAidlTest,
+ testing::ValuesIn(android::getAidlHalInstanceNames(IGatekeeper::descriptor)),
+ android::PrintInstanceNameToString);
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ ABinderProcess_setThreadPoolMaxThreadCount(1);
+ ABinderProcess_startThreadPool();
+ return RUN_ALL_TESTS();
+}
diff --git a/gnss/aidl/Android.bp b/gnss/aidl/Android.bp
index 9f9090c..f45fe5d 100644
--- a/gnss/aidl/Android.bp
+++ b/gnss/aidl/Android.bp
@@ -36,11 +36,6 @@
java: {
platform_apis: true,
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
versions_with_info: [
{
diff --git a/gnss/aidl/android/hardware/gnss/IGnss.aidl b/gnss/aidl/android/hardware/gnss/IGnss.aidl
index f0b583d..aaafe7f 100644
--- a/gnss/aidl/android/hardware/gnss/IGnss.aidl
+++ b/gnss/aidl/android/hardware/gnss/IGnss.aidl
@@ -104,7 +104,7 @@
*
* The framework calls this method to instruct the GPS engine to prepare for serving requests
* from the framework. The GNSS HAL implementation must respond to all GNSS requests from the
- * framework upon successful return from this method until cleanup() method is called to
+ * framework upon successful return from this method until close() method is called to
* close this interface.
*
* @param callback Callback interface for IGnss.
diff --git a/gnss/aidl/vts/gnss_hal_test.cpp b/gnss/aidl/vts/gnss_hal_test.cpp
index 0e1218e..3907f57 100644
--- a/gnss/aidl/vts/gnss_hal_test.cpp
+++ b/gnss/aidl/vts/gnss_hal_test.cpp
@@ -107,6 +107,17 @@
}
}
+void GnssHalTest::TearDown() {
+ GnssHalTestTemplate<IGnss_V2_1>::TearDown();
+ if (aidl_gnss_hal_ != nullptr) {
+ aidl_gnss_hal_->close();
+ aidl_gnss_hal_ = nullptr;
+ }
+
+ // Set to nullptr to destruct the callback event queues and warn of any unprocessed events.
+ aidl_gnss_cb_ = nullptr;
+}
+
void GnssHalTest::CheckLocation(const GnssLocation& location, bool check_speed) {
Utils::checkLocation(location, check_speed, /* check_more_accuracies= */ true);
}
diff --git a/gnss/aidl/vts/gnss_hal_test.h b/gnss/aidl/vts/gnss_hal_test.h
index 645fc82..c49c1b9 100644
--- a/gnss/aidl/vts/gnss_hal_test.h
+++ b/gnss/aidl/vts/gnss_hal_test.h
@@ -64,6 +64,7 @@
virtual void SetUp() override;
virtual void SetUpGnssCallback() override;
+ virtual void TearDown() override;
void CheckLocation(const android::hardware::gnss::GnssLocation& location,
const bool check_speed);
diff --git a/graphics/Android.bp b/graphics/Android.bp
new file mode 100644
index 0000000..cdd81ed
--- /dev/null
+++ b/graphics/Android.bp
@@ -0,0 +1,59 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_defaults {
+ name: "android.hardware.graphics.allocator-ndk_static",
+ static_libs: [
+ "android.hardware.graphics.allocator-V2-ndk",
+ ],
+}
+
+cc_defaults {
+ name: "android.hardware.graphics.allocator-ndk_shared",
+ shared_libs: [
+ "android.hardware.graphics.allocator-V2-ndk",
+ ],
+}
+
+cc_defaults {
+ name: "android.hardware.graphics.common-ndk_static",
+ static_libs: [
+ "android.hardware.graphics.common-V3-ndk",
+ ],
+}
+
+cc_defaults {
+ name: "android.hardware.graphics.common-ndk_shared",
+ shared_libs: [
+ "android.hardware.graphics.common-V3-ndk",
+ ],
+}
+
+cc_defaults {
+ name: "android.hardware.graphics.composer3-ndk_static",
+ static_libs: [
+ "android.hardware.graphics.composer3-V1-ndk",
+ ],
+}
+
+cc_defaults {
+ name: "android.hardware.graphics.composer3-ndk_shared",
+ shared_libs: [
+ "android.hardware.graphics.composer3-V1-ndk",
+ ],
+}
diff --git a/graphics/OWNERS b/graphics/OWNERS
index 75ceb23..1cb6015 100644
--- a/graphics/OWNERS
+++ b/graphics/OWNERS
@@ -6,4 +6,5 @@
chrisforbes@google.com
jreck@google.com
lpy@google.com
+scroggo@google.com
sumir@google.com
\ No newline at end of file
diff --git a/graphics/allocator/2.0/default/OWNERS b/graphics/allocator/2.0/default/OWNERS
deleted file mode 100644
index c9f24d0..0000000
--- a/graphics/allocator/2.0/default/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Graphics team
-chrisforbes@google.com
-jreck@google.com
-lpy@google.com
diff --git a/graphics/allocator/2.0/utils/OWNERS b/graphics/allocator/2.0/utils/OWNERS
deleted file mode 100644
index c9f24d0..0000000
--- a/graphics/allocator/2.0/utils/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Graphics team
-chrisforbes@google.com
-jreck@google.com
-lpy@google.com
diff --git a/graphics/allocator/aidl/Android.bp b/graphics/allocator/aidl/Android.bp
index 272ab48..66a7603 100644
--- a/graphics/allocator/aidl/Android.bp
+++ b/graphics/allocator/aidl/Android.bp
@@ -14,9 +14,11 @@
enabled: true,
support_system_process: true,
},
+ vndk_use_version: "2",
srcs: ["android/hardware/graphics/allocator/*.aidl"],
imports: [
"android.hardware.common-V2",
+ "android.hardware.graphics.common-V3",
],
stability: "vintf",
backend: {
@@ -37,6 +39,7 @@
min_sdk_version: "29",
},
},
+ frozen: false,
versions_with_info: [
{
version: "1",
diff --git a/graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl b/graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl
new file mode 100644
index 0000000..980e246
--- /dev/null
+++ b/graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.allocator;
+@VintfStability
+parcelable BufferDescriptorInfo {
+ byte[128] name;
+ int width;
+ int height;
+ int layerCount;
+ android.hardware.graphics.common.PixelFormat format = android.hardware.graphics.common.PixelFormat.UNSPECIFIED;
+ android.hardware.graphics.common.BufferUsage usage = android.hardware.graphics.common.BufferUsage.CPU_READ_NEVER;
+ long reservedSize;
+}
diff --git a/graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/IAllocator.aidl b/graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/IAllocator.aidl
index fe0b0a2..48bef16 100644
--- a/graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/IAllocator.aidl
+++ b/graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/IAllocator.aidl
@@ -34,5 +34,11 @@
package android.hardware.graphics.allocator;
@VintfStability
interface IAllocator {
+ /**
+ * @deprecated As of android.hardware.graphics.allocator-V2, this is deprecated & replaced with allocate2
+ */
android.hardware.graphics.allocator.AllocationResult allocate(in byte[] descriptor, in int count);
+ android.hardware.graphics.allocator.AllocationResult allocate2(in android.hardware.graphics.allocator.BufferDescriptorInfo descriptor, in int count);
+ boolean isSupported(in android.hardware.graphics.allocator.BufferDescriptorInfo descriptor);
+ String getIMapperLibrarySuffix();
}
diff --git a/graphics/allocator/aidl/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl b/graphics/allocator/aidl/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl
new file mode 100644
index 0000000..ffc50b8
--- /dev/null
+++ b/graphics/allocator/aidl/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.allocator;
+
+import android.hardware.graphics.common.BufferUsage;
+import android.hardware.graphics.common.PixelFormat;
+
+@VintfStability
+parcelable BufferDescriptorInfo {
+ /**
+ * The name of the buffer in ASCII. Useful for debugging/tracing.
+ */
+ byte[128] name;
+
+ /**
+ * The width specifies how many columns of pixels must be in the
+ * allocated buffer, but does not necessarily represent the offset in
+ * columns between the same column in adjacent rows. The rows may be
+ * padded.
+ */
+ int width;
+
+ /**
+ * The height specifies how many rows of pixels must be in the
+ * allocated buffer.
+ */
+ int height;
+
+ /**
+ * The number of image layers that must be in the allocated buffer.
+ */
+ int layerCount;
+
+ /**
+ * Buffer pixel format. See PixelFormat.aidl in graphics/common for
+ * valid values
+ */
+ PixelFormat format = PixelFormat.UNSPECIFIED;
+
+ /**
+ * Buffer usage mask; valid flags can be found in the definition of
+ * BufferUsage.aidl in graphics/common
+ */
+ BufferUsage usage = BufferUsage.CPU_READ_NEVER;
+
+ /**
+ * The size in bytes of the reserved region associated with the buffer.
+ * See getReservedRegion for more information.
+ */
+ long reservedSize;
+}
diff --git a/graphics/allocator/aidl/android/hardware/graphics/allocator/IAllocator.aidl b/graphics/allocator/aidl/android/hardware/graphics/allocator/IAllocator.aidl
index 92dfd4f..71cebd6 100644
--- a/graphics/allocator/aidl/android/hardware/graphics/allocator/IAllocator.aidl
+++ b/graphics/allocator/aidl/android/hardware/graphics/allocator/IAllocator.aidl
@@ -17,6 +17,7 @@
package android.hardware.graphics.allocator;
import android.hardware.graphics.allocator.AllocationResult;
+import android.hardware.graphics.allocator.BufferDescriptorInfo;
@VintfStability
interface IAllocator {
@@ -31,6 +32,43 @@
* @param count The number of buffers to allocate.
* @return An AllocationResult containing the result of the allocation
* @throws AllocationError on failure
+ * @deprecated As of android.hardware.graphics.allocator-V2, this is deprecated & replaced with
+ * allocate2
*/
AllocationResult allocate(in byte[] descriptor, in int count);
+
+ /**
+ * Allocates buffers with the properties specified by the descriptor.
+ *
+ * Allocations should be optimized for usage bits provided in the
+ * descriptor.
+ *
+ * @param descriptor Properties of the buffers to allocate. This must be
+ * obtained from IMapper::createDescriptor().
+ * @param count The number of buffers to allocate.
+ * @return An AllocationResult containing the result of the allocation
+ * @throws AllocationError on failure
+ */
+ AllocationResult allocate2(in BufferDescriptorInfo descriptor, in int count);
+
+ /**
+ * Test whether the given BufferDescriptorInfo is allocatable.
+ *
+ * If this function returns true, it means that a buffer with the given
+ * description can be allocated on this implementation, unless resource
+ * exhaustion occurs. If this function returns false, it means that the
+ * allocation of the given description will never succeed.
+ *
+ * @param description the description of the buffer
+ * @return supported whether the description is supported
+ */
+ boolean isSupported(in BufferDescriptorInfo descriptor);
+
+ /**
+ * Retrieve the library suffix to load for the IMapper SP-HAL. This library must implement the
+ * IMapper stable-C interface (android/hardware/graphics/mapper/IMapper.h).
+ *
+ * The library that will attempt to be loaded is "/vendor/lib[64]/hw/mapper.<imapper_suffix>.so"
+ */
+ String getIMapperLibrarySuffix();
}
diff --git a/graphics/allocator/aidl/vts/Android.bp b/graphics/allocator/aidl/vts/Android.bp
index 99ffb24..630ab2a 100644
--- a/graphics/allocator/aidl/vts/Android.bp
+++ b/graphics/allocator/aidl/vts/Android.bp
@@ -27,6 +27,7 @@
name: "VtsHalGraphicsAllocatorAidl_TargetTest",
defaults: [
"VtsHalTargetTestDefaults",
+ "android.hardware.graphics.allocator-ndk_shared",
"use_libaidlvintf_gtest_helper_static",
"hwui_defaults",
],
@@ -35,8 +36,6 @@
],
shared_libs: [
- "android.hardware.graphics.allocator-V1-ndk",
- "android.hardware.graphics.common-V3-ndk",
"android.hardware.graphics.mapper@4.0",
"libEGL",
"libGLESv2",
@@ -56,6 +55,7 @@
],
header_libs: [
"libhwui_internal_headers",
+ "libimapper_stablec",
],
cflags: [
"-Wall",
diff --git a/graphics/allocator/aidl/vts/VtsHalGraphicsAllocatorAidl_TargetTest.cpp b/graphics/allocator/aidl/vts/VtsHalGraphicsAllocatorAidl_TargetTest.cpp
index 59af5cf..09f1c15 100644
--- a/graphics/allocator/aidl/vts/VtsHalGraphicsAllocatorAidl_TargetTest.cpp
+++ b/graphics/allocator/aidl/vts/VtsHalGraphicsAllocatorAidl_TargetTest.cpp
@@ -25,7 +25,10 @@
#include <aidl/android/hardware/graphics/common/PixelFormat.h>
#include <aidlcommonsupport/NativeHandle.h>
#include <android/binder_manager.h>
+#include <android/dlext.h>
#include <android/hardware/graphics/mapper/4.0/IMapper.h>
+#include <android/hardware/graphics/mapper/IMapper.h>
+#include <dlfcn.h>
#include <gtest/gtest.h>
#include <hidl/GtestPrinter.h>
#include <hidl/ServiceManagement.h>
@@ -33,6 +36,7 @@
#include <renderthread/EglManager.h>
#include <utils/GLUtils.h>
#include <vndk/hardware_buffer.h>
+#include <vndksupport/linker.h>
#include <initializer_list>
#include <optional>
#include <string>
@@ -42,60 +46,70 @@
using namespace aidl::android::hardware::graphics::common;
using namespace android;
using namespace android::hardware;
-using namespace android::hardware::graphics::mapper::V4_0;
+using IMapper4 = android::hardware::graphics::mapper::V4_0::IMapper;
+using Error = android::hardware::graphics::mapper::V4_0::Error;
+using android::hardware::graphics::mapper::V4_0::BufferDescriptor;
using android::uirenderer::AutoEglImage;
using android::uirenderer::AutoGLFramebuffer;
using android::uirenderer::AutoSkiaGlTexture;
using android::uirenderer::renderthread::EglManager;
-static constexpr uint64_t pack(const std::initializer_list<BufferUsage>& usages) {
- uint64_t ret = 0;
- for (const auto u : usages) {
- ret |= static_cast<uint64_t>(u);
- }
- return ret;
+typedef AIMapper_Error (*AIMapper_loadIMapperFn)(AIMapper* _Nullable* _Nonnull outImplementation);
+
+inline BufferUsage operator|(BufferUsage lhs, BufferUsage rhs) {
+ using T = std::underlying_type_t<BufferUsage>;
+ return static_cast<BufferUsage>(static_cast<T>(lhs) | static_cast<T>(rhs));
}
-static constexpr hardware::graphics::common::V1_2::PixelFormat cast(PixelFormat format) {
- return static_cast<hardware::graphics::common::V1_2::PixelFormat>(format);
+inline BufferUsage& operator|=(BufferUsage& lhs, BufferUsage rhs) {
+ lhs = lhs | rhs;
+ return lhs;
}
+static IMapper4::BufferDescriptorInfo convert(const BufferDescriptorInfo& info) {
+ return IMapper4::BufferDescriptorInfo{
+ .name{reinterpret_cast<const char*>(info.name.data())},
+ .width = static_cast<uint32_t>(info.width),
+ .height = static_cast<uint32_t>(info.height),
+ .layerCount = static_cast<uint32_t>(info.layerCount),
+ .format = static_cast<hardware::graphics::common::V1_2::PixelFormat>(info.format),
+ .usage = static_cast<uint64_t>(info.usage),
+ .reservedSize = 0,
+ };
+}
+
+class GraphicsTestsBase;
+
class BufferHandle {
- sp<IMapper> mMapper;
+ GraphicsTestsBase& mTestBase;
native_handle_t* mRawHandle;
bool mImported = false;
uint32_t mStride;
- const IMapper::BufferDescriptorInfo mInfo;
+ const BufferDescriptorInfo mInfo;
BufferHandle(const BufferHandle&) = delete;
void operator=(const BufferHandle&) = delete;
public:
- BufferHandle(const sp<IMapper> mapper, native_handle_t* handle, bool imported, uint32_t stride,
- const IMapper::BufferDescriptorInfo& info)
- : mMapper(mapper), mRawHandle(handle), mImported(imported), mStride(stride), mInfo(info) {}
+ BufferHandle(GraphicsTestsBase& testBase, native_handle_t* handle, bool imported,
+ uint32_t stride, const BufferDescriptorInfo& info)
+ : mTestBase(testBase),
+ mRawHandle(handle),
+ mImported(imported),
+ mStride(stride),
+ mInfo(info) {}
- ~BufferHandle() {
- if (mRawHandle == nullptr) return;
-
- if (mImported) {
- Error error = mMapper->freeBuffer(mRawHandle);
- EXPECT_EQ(Error::NONE, error) << "failed to free buffer " << mRawHandle;
- } else {
- native_handle_close(mRawHandle);
- native_handle_delete(mRawHandle);
- }
- }
+ ~BufferHandle();
uint32_t stride() const { return mStride; }
AHardwareBuffer_Desc describe() const {
return {
- .width = mInfo.width,
- .height = mInfo.height,
- .layers = mInfo.layerCount,
+ .width = static_cast<uint32_t>(mInfo.width),
+ .height = static_cast<uint32_t>(mInfo.height),
+ .layers = static_cast<uint32_t>(mInfo.layerCount),
.format = static_cast<uint32_t>(mInfo.format),
- .usage = mInfo.usage,
+ .usage = static_cast<uint64_t>(mInfo.usage),
.stride = stride(),
.rfu0 = 0,
.rfu1 = 0,
@@ -114,25 +128,43 @@
class GraphicsTestsBase {
private:
+ friend class BufferHandle;
+ int32_t mIAllocatorVersion = 1;
std::shared_ptr<IAllocator> mAllocator;
- sp<IMapper> mMapper;
+ sp<IMapper4> mMapper4;
+ AIMapper* mAIMapper = nullptr;
protected:
- void Initialize(std::string allocatorService, std::string mapperService) {
+ void Initialize(std::string allocatorService) {
mAllocator = IAllocator::fromBinder(
ndk::SpAIBinder(AServiceManager_checkService(allocatorService.c_str())));
- mMapper = IMapper::getService(mapperService);
+ ASSERT_TRUE(mAllocator->getInterfaceVersion(&mIAllocatorVersion).isOk());
+ if (mIAllocatorVersion >= 2) {
+ std::string mapperSuffix;
+ auto status = mAllocator->getIMapperLibrarySuffix(&mapperSuffix);
+ ASSERT_TRUE(status.isOk());
+ std::string lib_name = "mapper." + mapperSuffix + ".so";
+ void* so = android_load_sphal_library(lib_name.c_str(), RTLD_LOCAL | RTLD_NOW);
+ ASSERT_NE(nullptr, so) << "Failed to load " << lib_name;
+ auto loadIMapper = (AIMapper_loadIMapperFn)dlsym(so, "AIMapper_loadIMapper");
+ ASSERT_NE(nullptr, loadIMapper) << "AIMapper_locaIMapper missing from " << lib_name;
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, loadIMapper(&mAIMapper));
+ ASSERT_NE(mAIMapper, nullptr);
+ } else {
+ // Don't have IMapper 5, fall back to IMapper 4
+ mMapper4 = IMapper4::getService();
+ ASSERT_NE(nullptr, mMapper4.get()) << "failed to get mapper service";
+ ASSERT_FALSE(mMapper4->isRemote()) << "mapper is not in passthrough mode";
+ }
ASSERT_NE(nullptr, mAllocator.get()) << "failed to get allocator service";
- ASSERT_NE(nullptr, mMapper.get()) << "failed to get mapper service";
- ASSERT_FALSE(mMapper->isRemote()) << "mapper is not in passthrough mode";
}
- public:
- BufferDescriptor createDescriptor(const IMapper::BufferDescriptorInfo& descriptorInfo) {
+ private:
+ BufferDescriptor createDescriptor(const BufferDescriptorInfo& descriptorInfo) {
BufferDescriptor descriptor;
- mMapper->createDescriptor(
- descriptorInfo, [&](const auto& tmpError, const auto& tmpDescriptor) {
+ mMapper4->createDescriptor(
+ convert(descriptorInfo), [&](const auto& tmpError, const auto& tmpDescriptor) {
ASSERT_EQ(Error::NONE, tmpError) << "failed to create descriptor";
descriptor = tmpDescriptor;
});
@@ -140,14 +172,22 @@
return descriptor;
}
- std::unique_ptr<BufferHandle> allocate(const IMapper::BufferDescriptorInfo& descriptorInfo) {
- auto descriptor = createDescriptor(descriptorInfo);
- if (::testing::Test::HasFatalFailure()) {
- return nullptr;
- }
-
+ public:
+ std::unique_ptr<BufferHandle> allocate(const BufferDescriptorInfo& descriptorInfo) {
AllocationResult result;
- auto status = mAllocator->allocate(descriptor, 1, &result);
+ ::ndk::ScopedAStatus status;
+ if (mIAllocatorVersion >= 2) {
+ status = mAllocator->allocate2(descriptorInfo, 1, &result);
+ } else {
+ auto descriptor = createDescriptor(descriptorInfo);
+ if (::testing::Test::HasFatalFailure()) {
+ return nullptr;
+ }
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+ status = mAllocator->allocate(descriptor, 1, &result);
+#pragma clang diagnostic pop // deprecation
+ }
if (!status.isOk()) {
status_t error = status.getExceptionCode();
if (error == EX_SERVICE_SPECIFIC) {
@@ -158,28 +198,48 @@
}
return nullptr;
} else {
- return std::make_unique<BufferHandle>(mMapper, dupFromAidl(result.buffers[0]), false,
+ return std::make_unique<BufferHandle>(*this, dupFromAidl(result.buffers[0]), false,
result.stride, descriptorInfo);
}
}
- bool isSupported(const IMapper::BufferDescriptorInfo& descriptorInfo) {
+ bool isSupported(const BufferDescriptorInfo& descriptorInfo) {
bool ret = false;
- EXPECT_TRUE(mMapper->isSupported(descriptorInfo,
- [&](auto error, bool supported) {
- ASSERT_EQ(Error::NONE, error);
- ret = supported;
- })
- .isOk());
+ if (mIAllocatorVersion >= 2) {
+ EXPECT_TRUE(mAllocator->isSupported(descriptorInfo, &ret).isOk());
+ } else {
+ EXPECT_TRUE(mMapper4->isSupported(convert(descriptorInfo),
+ [&](auto error, bool supported) {
+ ASSERT_EQ(Error::NONE, error);
+ ret = supported;
+ })
+ .isOk());
+ }
return ret;
}
};
-class GraphicsAllocatorAidlTests
- : public GraphicsTestsBase,
- public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
+BufferHandle::~BufferHandle() {
+ if (mRawHandle == nullptr) return;
+
+ if (mImported) {
+ if (mTestBase.mAIMapper) {
+ AIMapper_Error error = mTestBase.mAIMapper->v5.freeBuffer(mRawHandle);
+ EXPECT_EQ(AIMAPPER_ERROR_NONE, error);
+ } else {
+ Error error = mTestBase.mMapper4->freeBuffer(mRawHandle);
+ EXPECT_EQ(Error::NONE, error) << "failed to free buffer " << mRawHandle;
+ }
+ } else {
+ native_handle_close(mRawHandle);
+ native_handle_delete(mRawHandle);
+ }
+}
+
+class GraphicsAllocatorAidlTests : public GraphicsTestsBase,
+ public ::testing::TestWithParam<std::string> {
public:
- void SetUp() override { Initialize(std::get<0>(GetParam()), std::get<1>(GetParam())); }
+ void SetUp() override { Initialize(GetParam()); }
void TearDown() override {}
};
@@ -191,22 +251,22 @@
class GraphicsFrontBufferTests
: public GraphicsTestsBase,
- public ::testing::TestWithParam<std::tuple<std::string, std::string, FlushMethod>> {
+ public ::testing::TestWithParam<std::tuple<std::string, FlushMethod>> {
private:
EglManager eglManager;
std::function<void(EglManager&)> flush;
public:
void SetUp() override {
- Initialize(std::get<0>(GetParam()), std::get<1>(GetParam()));
- flush = std::get<2>(GetParam()).func;
+ Initialize(std::get<0>(GetParam()));
+ flush = std::get<1>(GetParam()).func;
eglManager.initialize();
}
void TearDown() override { eglManager.destroy(); }
void fillWithGpu(AHardwareBuffer* buffer, float red, float green, float blue, float alpha) {
- const EGLClientBuffer clientBuffer = eglGetNativeClientBufferANDROID(buffer);
+ EGLClientBuffer clientBuffer = eglGetNativeClientBufferANDROID(buffer);
AutoEglImage eglImage(eglManager.eglDisplay(), clientBuffer);
AutoSkiaGlTexture glTexture;
AutoGLFramebuffer glFbo;
@@ -235,26 +295,14 @@
}
};
-TEST_P(GraphicsAllocatorAidlTests, CreateDescriptorBasic) {
- ASSERT_NO_FATAL_FAILURE(createDescriptor({
- .name = "CPU_8888",
- .width = 64,
- .height = 64,
- .layerCount = 1,
- .format = cast(PixelFormat::RGBA_8888),
- .usage = pack({BufferUsage::CPU_WRITE_OFTEN, BufferUsage::CPU_READ_OFTEN}),
- .reservedSize = 0,
- }));
-}
-
TEST_P(GraphicsAllocatorAidlTests, CanAllocate) {
auto buffer = allocate({
- .name = "CPU_8888",
+ .name = {"CPU_8888"},
.width = 64,
.height = 64,
.layerCount = 1,
- .format = cast(PixelFormat::RGBA_8888),
- .usage = pack({BufferUsage::CPU_WRITE_OFTEN, BufferUsage::CPU_READ_OFTEN}),
+ .format = PixelFormat::RGBA_8888,
+ .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
.reservedSize = 0,
});
ASSERT_NE(nullptr, buffer.get());
@@ -262,14 +310,14 @@
}
TEST_P(GraphicsFrontBufferTests, FrontBufferGpuToCpu) {
- IMapper::BufferDescriptorInfo info{
- .name = "CPU_8888",
+ BufferDescriptorInfo info{
+ .name = {"CPU_8888"},
.width = 64,
.height = 64,
.layerCount = 1,
- .format = cast(PixelFormat::RGBA_8888),
- .usage = pack({BufferUsage::GPU_RENDER_TARGET, BufferUsage::CPU_READ_OFTEN,
- BufferUsage::FRONT_BUFFER}),
+ .format = PixelFormat::RGBA_8888,
+ .usage = BufferUsage::GPU_RENDER_TARGET | BufferUsage::CPU_READ_OFTEN |
+ BufferUsage::FRONT_BUFFER,
.reservedSize = 0,
};
const bool supported = isSupported(info);
@@ -304,14 +352,14 @@
}
TEST_P(GraphicsFrontBufferTests, FrontBufferGpuToGpu) {
- IMapper::BufferDescriptorInfo info{
- .name = "CPU_8888",
+ BufferDescriptorInfo info{
+ .name = {"CPU_8888"},
.width = 64,
.height = 64,
.layerCount = 1,
- .format = cast(PixelFormat::RGBA_8888),
- .usage = pack({BufferUsage::GPU_RENDER_TARGET, BufferUsage::GPU_TEXTURE,
- BufferUsage::FRONT_BUFFER}),
+ .format = PixelFormat::RGBA_8888,
+ .usage = BufferUsage::GPU_RENDER_TARGET | BufferUsage::GPU_TEXTURE |
+ BufferUsage::FRONT_BUFFER,
.reservedSize = 0,
};
const bool supported = isSupported(info);
@@ -344,11 +392,9 @@
}
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsAllocatorAidlTests);
-INSTANTIATE_TEST_CASE_P(
- PerInstance, GraphicsAllocatorAidlTests,
- testing::Combine(testing::ValuesIn(getAidlHalInstanceNames(IAllocator::descriptor)),
- testing::ValuesIn(getAllHalInstanceNames(IMapper::descriptor))),
- PrintInstanceTupleNameToString<>);
+INSTANTIATE_TEST_CASE_P(PerInstance, GraphicsAllocatorAidlTests,
+ testing::ValuesIn(getAidlHalInstanceNames(IAllocator::descriptor)),
+ PrintInstanceNameToString);
const auto FlushMethodsValues = testing::Values(
FlushMethod{"glFinish", [](EglManager&) { glFinish(); }},
@@ -362,7 +408,7 @@
}},
FlushMethod{"eglClientWaitSync", [](EglManager& eglManager) {
EGLDisplay display = eglManager.eglDisplay();
- EGLSyncKHR fence = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, NULL);
+ EGLSyncKHR fence = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr);
eglClientWaitSyncKHR(display, fence, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
EGL_FOREVER_KHR);
eglDestroySyncKHR(display, fence);
@@ -371,9 +417,8 @@
INSTANTIATE_TEST_CASE_P(
PerInstance, GraphicsFrontBufferTests,
testing::Combine(testing::ValuesIn(getAidlHalInstanceNames(IAllocator::descriptor)),
- testing::ValuesIn(getAllHalInstanceNames(IMapper::descriptor)),
FlushMethodsValues),
[](auto info) -> std::string {
- std::string name = std::to_string(info.index) + "/" + std::get<2>(info.param).name;
+ std::string name = std::to_string(info.index) + "/" + std::get<1>(info.param).name;
return Sanitize(name);
- });
+ });
\ No newline at end of file
diff --git a/graphics/bufferqueue/1.0/Android.bp b/graphics/bufferqueue/1.0/Android.bp
index 11559b2..82c71f1 100644
--- a/graphics/bufferqueue/1.0/Android.bp
+++ b/graphics/bufferqueue/1.0/Android.bp
@@ -27,7 +27,7 @@
gen_java: true,
apex_available: [
"//apex_available:platform",
- "com.android.bluetooth",
+ "com.android.btservices",
"com.android.media",
"com.android.media.swcodec",
],
diff --git a/graphics/bufferqueue/2.0/Android.bp b/graphics/bufferqueue/2.0/Android.bp
index 552daff..3067e24 100644
--- a/graphics/bufferqueue/2.0/Android.bp
+++ b/graphics/bufferqueue/2.0/Android.bp
@@ -29,7 +29,7 @@
gen_java: true,
apex_available: [
"//apex_available:platform",
- "com.android.bluetooth",
+ "com.android.btservices",
"com.android.media",
"com.android.media.swcodec",
],
diff --git a/graphics/common/1.0/Android.bp b/graphics/common/1.0/Android.bp
index 19c51cd..3288583 100644
--- a/graphics/common/1.0/Android.bp
+++ b/graphics/common/1.0/Android.bp
@@ -23,7 +23,7 @@
gen_java_constants: true,
apex_available: [
"//apex_available:platform",
- "com.android.bluetooth",
+ "com.android.btservices",
"com.android.media.swcodec",
"test_com.android.media.swcodec",
],
diff --git a/graphics/common/1.1/Android.bp b/graphics/common/1.1/Android.bp
index 0f1b5bf..5d07eae 100644
--- a/graphics/common/1.1/Android.bp
+++ b/graphics/common/1.1/Android.bp
@@ -26,7 +26,7 @@
gen_java_constants: true,
apex_available: [
"//apex_available:platform",
- "com.android.bluetooth",
+ "com.android.btservices",
"com.android.media.swcodec",
"test_com.android.media.swcodec",
],
diff --git a/graphics/common/1.2/Android.bp b/graphics/common/1.2/Android.bp
index ce3350d..4aa4af5 100644
--- a/graphics/common/1.2/Android.bp
+++ b/graphics/common/1.2/Android.bp
@@ -27,7 +27,7 @@
gen_java_constants: true,
apex_available: [
"//apex_available:platform",
- "com.android.bluetooth",
+ "com.android.btservices",
"com.android.media.swcodec",
"test_com.android.media.swcodec",
],
diff --git a/graphics/common/OWNERS b/graphics/common/OWNERS
deleted file mode 100644
index 94999ea..0000000
--- a/graphics/common/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-# Bug component: 1075130
-adyabr@google.com
-alecmouri@google.com
-jreck@google.com
-scroggo@google.com
diff --git a/graphics/common/aidl/Android.bp b/graphics/common/aidl/Android.bp
index 40a575d..3fddc9f 100644
--- a/graphics/common/aidl/Android.bp
+++ b/graphics/common/aidl/Android.bp
@@ -40,6 +40,7 @@
min_sdk_version: "29",
},
},
+ frozen: true,
versions_with_info: [
{
version: "1",
diff --git a/graphics/composer/2.1/default/OWNERS b/graphics/composer/2.1/default/OWNERS
deleted file mode 100644
index 331c80d..0000000
--- a/graphics/composer/2.1/default/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Graphics team
-adyabr@google.com
-alecmouri@google.com
-lpy@google.com
diff --git a/graphics/composer/2.1/utils/OWNERS b/graphics/composer/2.1/utils/OWNERS
deleted file mode 100644
index 83c4f5f..0000000
--- a/graphics/composer/2.1/utils/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-adyabr@google.com
-alecmouri@google.com
-lpy@google.com
diff --git a/graphics/composer/2.1/utils/hwc2on1adapter/Android.bp b/graphics/composer/2.1/utils/hwc2on1adapter/Android.bp
index 0171dd6..3527cca 100644
--- a/graphics/composer/2.1/utils/hwc2on1adapter/Android.bp
+++ b/graphics/composer/2.1/utils/hwc2on1adapter/Android.bp
@@ -25,7 +25,6 @@
name: "libhwc2on1adapter",
vendor: true,
- clang: true,
cflags: [
"-Wall",
"-Werror",
diff --git a/graphics/composer/2.1/utils/hwc2onfbadapter/Android.bp b/graphics/composer/2.1/utils/hwc2onfbadapter/Android.bp
index 3965d12..d613ba9 100644
--- a/graphics/composer/2.1/utils/hwc2onfbadapter/Android.bp
+++ b/graphics/composer/2.1/utils/hwc2onfbadapter/Android.bp
@@ -25,7 +25,6 @@
name: "libhwc2onfbadapter",
vendor: true,
- clang: true,
cflags: [
"-Wall",
"-Wextra",
@@ -37,6 +36,9 @@
],
header_libs: ["libhardware_headers"],
- shared_libs: ["liblog", "libsync"],
+ shared_libs: [
+ "liblog",
+ "libsync",
+ ],
export_include_dirs: ["include"],
}
diff --git a/graphics/composer/2.1/utils/vts/Android.bp b/graphics/composer/2.1/utils/vts/Android.bp
index c0a0c07..7b6a0e6 100644
--- a/graphics/composer/2.1/utils/vts/Android.bp
+++ b/graphics/composer/2.1/utils/vts/Android.bp
@@ -25,14 +25,16 @@
cc_library_static {
name: "android.hardware.graphics.composer@2.1-vts",
- defaults: ["hidl_defaults"],
+ defaults: [
+ "android.hardware.graphics.allocator-ndk_static",
+ "hidl_defaults",
+ ],
srcs: [
"ComposerVts.cpp",
"GraphicsComposerCallback.cpp",
"TestCommandReader.cpp",
],
static_libs: [
- "android.hardware.graphics.allocator-V1-ndk",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.mapper@2.0-vts",
"android.hardware.graphics.mapper@3.0-vts",
@@ -40,7 +42,6 @@
"libgtest",
],
export_static_lib_headers: [
- "android.hardware.graphics.allocator-V1-ndk",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.mapper@2.0-vts",
"android.hardware.graphics.mapper@3.0-vts",
diff --git a/graphics/composer/2.1/vts/OWNERS b/graphics/composer/2.1/vts/OWNERS
deleted file mode 100644
index a643bbd..0000000
--- a/graphics/composer/2.1/vts/OWNERS
+++ /dev/null
@@ -1,8 +0,0 @@
-# Graphics team
-adyabr@google.com
-alecmouri@google.com
-lpy@google.com
-
-# VTS team
-yim@google.com
-zhuoyao@google.com
diff --git a/graphics/composer/2.1/vts/functional/Android.bp b/graphics/composer/2.1/vts/functional/Android.bp
index 502036e..0f6d7e8 100644
--- a/graphics/composer/2.1/vts/functional/Android.bp
+++ b/graphics/composer/2.1/vts/functional/Android.bp
@@ -25,7 +25,10 @@
cc_test {
name: "VtsHalGraphicsComposerV2_1TargetTest",
- defaults: ["VtsHalTargetTestDefaults"],
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "android.hardware.graphics.allocator-ndk_static",
+ ],
tidy_timeout_srcs: ["VtsHalGraphicsComposerV2_1TargetTest.cpp"],
srcs: ["VtsHalGraphicsComposerV2_1TargetTest.cpp"],
@@ -42,7 +45,6 @@
"android.hardware.graphics.mapper@4.0",
],
static_libs: [
- "android.hardware.graphics.allocator-V1-ndk",
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.allocator@4.0",
diff --git a/graphics/composer/2.1/vts/functional/OWNERS b/graphics/composer/2.1/vts/functional/OWNERS
deleted file mode 100644
index 3d970d1..0000000
--- a/graphics/composer/2.1/vts/functional/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Bug component: 25423
-adyabr@google.com
-alecmouri@google.com
-sumir@google.com
diff --git a/graphics/composer/2.2/default/OWNERS b/graphics/composer/2.2/default/OWNERS
deleted file mode 100644
index e8f584d..0000000
--- a/graphics/composer/2.2/default/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-# Graphics team
-adyabr@google.com
-alecmouri@google.com
-lpy@google.com
-
diff --git a/graphics/composer/2.2/utils/OWNERS b/graphics/composer/2.2/utils/OWNERS
deleted file mode 100644
index 331c80d..0000000
--- a/graphics/composer/2.2/utils/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Graphics team
-adyabr@google.com
-alecmouri@google.com
-lpy@google.com
diff --git a/graphics/composer/2.2/utils/vts/Android.bp b/graphics/composer/2.2/utils/vts/Android.bp
index cca5323..e383ce2 100644
--- a/graphics/composer/2.2/utils/vts/Android.bp
+++ b/graphics/composer/2.2/utils/vts/Android.bp
@@ -25,7 +25,11 @@
cc_library_static {
name: "android.hardware.graphics.composer@2.2-vts",
- defaults: ["hidl_defaults"],
+ defaults: [
+ "android.hardware.graphics.allocator-ndk_static",
+ "android.hardware.graphics.composer3-ndk_static",
+ "hidl_defaults",
+ ],
srcs: [
"ComposerVts.cpp",
"ReadbackVts.cpp",
@@ -35,7 +39,6 @@
"libui",
],
static_libs: [
- "android.hardware.graphics.allocator-V1-ndk",
"android.hardware.graphics.composer@2.1-vts",
"android.hardware.graphics.composer@2.2",
"android.hardware.graphics.composer3-V1-ndk",
@@ -53,7 +56,6 @@
"android.hardware.graphics.mapper@4.0-vts",
],
export_static_lib_headers: [
- "android.hardware.graphics.allocator-V1-ndk",
"android.hardware.graphics.composer@2.1-vts",
"android.hardware.graphics.composer@2.2",
"android.hardware.graphics.mapper@2.1-vts",
diff --git a/graphics/composer/2.2/vts/functional/Android.bp b/graphics/composer/2.2/vts/functional/Android.bp
index 960b62d..cdc7a93 100644
--- a/graphics/composer/2.2/vts/functional/Android.bp
+++ b/graphics/composer/2.2/vts/functional/Android.bp
@@ -27,6 +27,8 @@
name: "VtsHalGraphicsComposerV2_2TargetTest",
defaults: [
"VtsHalTargetTestDefaults",
+ "android.hardware.graphics.allocator-ndk_static",
+ "android.hardware.graphics.composer3-ndk_static",
// Needed for librenderengine
"skia_deps",
],
@@ -59,7 +61,6 @@
"android.hardware.graphics.mapper@4.0",
],
static_libs: [
- "android.hardware.graphics.allocator-V1-ndk",
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.allocator@4.0",
diff --git a/graphics/composer/2.2/vts/functional/OWNERS b/graphics/composer/2.2/vts/functional/OWNERS
deleted file mode 100644
index a4eb0ca..0000000
--- a/graphics/composer/2.2/vts/functional/OWNERS
+++ /dev/null
@@ -1,6 +0,0 @@
-# Bug component: 25423
-# Graphics team
-adyabr@google.com
-alecmouri@google.com
-lpy@google.com
-sumir@google.com
diff --git a/graphics/composer/2.3/default/OWNERS b/graphics/composer/2.3/default/OWNERS
deleted file mode 100644
index 331c80d..0000000
--- a/graphics/composer/2.3/default/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Graphics team
-adyabr@google.com
-alecmouri@google.com
-lpy@google.com
diff --git a/graphics/composer/2.3/utils/OWNERS b/graphics/composer/2.3/utils/OWNERS
deleted file mode 100644
index 331c80d..0000000
--- a/graphics/composer/2.3/utils/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Graphics team
-adyabr@google.com
-alecmouri@google.com
-lpy@google.com
diff --git a/graphics/composer/2.3/utils/vts/Android.bp b/graphics/composer/2.3/utils/vts/Android.bp
index 7bc07a4..b372804 100644
--- a/graphics/composer/2.3/utils/vts/Android.bp
+++ b/graphics/composer/2.3/utils/vts/Android.bp
@@ -25,7 +25,10 @@
cc_library_static {
name: "android.hardware.graphics.composer@2.3-vts",
- defaults: ["hidl_defaults"],
+ defaults: [
+ "android.hardware.graphics.allocator-ndk_static",
+ "hidl_defaults",
+ ],
srcs: [
"ComposerVts.cpp",
],
diff --git a/graphics/composer/2.3/vts/functional/Android.bp b/graphics/composer/2.3/vts/functional/Android.bp
index 40b77d5..13f2b11 100644
--- a/graphics/composer/2.3/vts/functional/Android.bp
+++ b/graphics/composer/2.3/vts/functional/Android.bp
@@ -25,7 +25,10 @@
cc_test {
name: "VtsHalGraphicsComposerV2_3TargetTest",
- defaults: ["VtsHalTargetTestDefaults"],
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "android.hardware.graphics.allocator-ndk_static",
+ ],
tidy_timeout_srcs: ["VtsHalGraphicsComposerV2_3TargetTest.cpp"],
srcs: ["VtsHalGraphicsComposerV2_3TargetTest.cpp"],
@@ -43,7 +46,6 @@
"android.hardware.graphics.mapper@4.0",
],
static_libs: [
- "android.hardware.graphics.allocator-V1-ndk",
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.allocator@4.0",
diff --git a/graphics/composer/2.3/vts/functional/OWNERS b/graphics/composer/2.3/vts/functional/OWNERS
deleted file mode 100644
index a4eb0ca..0000000
--- a/graphics/composer/2.3/vts/functional/OWNERS
+++ /dev/null
@@ -1,6 +0,0 @@
-# Bug component: 25423
-# Graphics team
-adyabr@google.com
-alecmouri@google.com
-lpy@google.com
-sumir@google.com
diff --git a/graphics/composer/2.4/default/OWNERS b/graphics/composer/2.4/default/OWNERS
deleted file mode 100644
index 331c80d..0000000
--- a/graphics/composer/2.4/default/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Graphics team
-adyabr@google.com
-alecmouri@google.com
-lpy@google.com
diff --git a/graphics/composer/2.4/utils/OWNERS b/graphics/composer/2.4/utils/OWNERS
deleted file mode 100644
index 331c80d..0000000
--- a/graphics/composer/2.4/utils/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Graphics team
-adyabr@google.com
-alecmouri@google.com
-lpy@google.com
diff --git a/graphics/composer/2.4/utils/vts/Android.bp b/graphics/composer/2.4/utils/vts/Android.bp
index de31975..d2b2ffa 100644
--- a/graphics/composer/2.4/utils/vts/Android.bp
+++ b/graphics/composer/2.4/utils/vts/Android.bp
@@ -25,14 +25,16 @@
cc_library_static {
name: "android.hardware.graphics.composer@2.4-vts",
- defaults: ["hidl_defaults"],
+ defaults: [
+ "android.hardware.graphics.allocator-ndk_static",
+ "hidl_defaults",
+ ],
srcs: [
"ComposerVts.cpp",
"GraphicsComposerCallback.cpp",
"TestCommandReader.cpp",
],
static_libs: [
- "android.hardware.graphics.allocator-V1-ndk",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.composer@2.2",
"android.hardware.graphics.composer@2.3-vts",
diff --git a/graphics/composer/2.4/vts/functional/Android.bp b/graphics/composer/2.4/vts/functional/Android.bp
index b73ea94..b4ab259 100644
--- a/graphics/composer/2.4/vts/functional/Android.bp
+++ b/graphics/composer/2.4/vts/functional/Android.bp
@@ -25,7 +25,10 @@
cc_test {
name: "VtsHalGraphicsComposerV2_4TargetTest",
- defaults: ["VtsHalTargetTestDefaults"],
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "android.hardware.graphics.allocator-ndk_static",
+ ],
tidy_timeout_srcs: ["VtsHalGraphicsComposerV2_4TargetTest.cpp"],
srcs: ["VtsHalGraphicsComposerV2_4TargetTest.cpp"],
@@ -42,7 +45,6 @@
"android.hardware.graphics.mapper@4.0",
],
static_libs: [
- "android.hardware.graphics.allocator-V1-ndk",
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.allocator@4.0",
diff --git a/graphics/composer/2.4/vts/functional/OWNERS b/graphics/composer/2.4/vts/functional/OWNERS
deleted file mode 100644
index a4eb0ca..0000000
--- a/graphics/composer/2.4/vts/functional/OWNERS
+++ /dev/null
@@ -1,6 +0,0 @@
-# Bug component: 25423
-# Graphics team
-adyabr@google.com
-alecmouri@google.com
-lpy@google.com
-sumir@google.com
diff --git a/graphics/composer/aidl/Android.bp b/graphics/composer/aidl/Android.bp
index 9b88d98..56e6ed2 100644
--- a/graphics/composer/aidl/Android.bp
+++ b/graphics/composer/aidl/Android.bp
@@ -31,6 +31,7 @@
enabled: true,
support_system_process: true,
},
+ frozen: true,
srcs: [
"android/hardware/graphics/composer3/*.aidl",
],
diff --git a/graphics/composer/aidl/OWNERS b/graphics/composer/aidl/OWNERS
deleted file mode 100644
index 9028d9d..0000000
--- a/graphics/composer/aidl/OWNERS
+++ /dev/null
@@ -1,6 +0,0 @@
-# Bug component: 1075131
-
-# Graphics team
-adyabr@google.com
-alecmouri@google.com
-sumir@google.com
\ No newline at end of file
diff --git a/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerServiceWriter.h b/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerServiceWriter.h
index 34cda6a..b50b84b 100644
--- a/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerServiceWriter.h
+++ b/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerServiceWriter.h
@@ -18,6 +18,7 @@
#include <aidl/android/hardware/graphics/composer3/CommandResultPayload.h>
#include <aidl/android/hardware/graphics/composer3/IComposerClient.h>
+#include <android-base/logging.h>
#include <inttypes.h>
#include <string.h>
@@ -26,8 +27,6 @@
#include <memory>
#include <vector>
-#include "Util.h"
-
namespace aidl::android::hardware::graphics::composer3::impl {
class ComposerServiceWriter {
diff --git a/graphics/composer/aidl/vts/OWNERS b/graphics/composer/aidl/vts/OWNERS
deleted file mode 100644
index d95d98d..0000000
--- a/graphics/composer/aidl/vts/OWNERS
+++ /dev/null
@@ -1,6 +0,0 @@
-# Bug component: 199413815
-
-# Graphics team
-adyabr@google.com
-alecmouri@google.com
-ramindani@google.com
diff --git a/graphics/composer/aidl/vts/VtsComposerClient.cpp b/graphics/composer/aidl/vts/VtsComposerClient.cpp
index 2b60703..5bc7296 100644
--- a/graphics/composer/aidl/vts/VtsComposerClient.cpp
+++ b/graphics/composer/aidl/vts/VtsComposerClient.cpp
@@ -488,10 +488,13 @@
}
bool VtsComposerClient::destroyAllLayers() {
- for (const auto& it : mDisplayResources) {
- const auto& [display, resource] = it;
+ std::unordered_map<int64_t, DisplayResource> physicalDisplays;
+ while (!mDisplayResources.empty()) {
+ const auto& it = mDisplayResources.begin();
+ const auto& [display, resource] = *it;
- for (auto layer : resource.layers) {
+ while (!resource.layers.empty()) {
+ auto layer = *resource.layers.begin();
const auto status = destroyLayer(display, layer);
if (!status.isOk()) {
ALOGE("Unable to destroy all the layers, failed at layer %" PRId64 " with error %s",
@@ -507,8 +510,12 @@
status.getDescription().c_str());
return false;
}
+ } else {
+ auto extractIter = mDisplayResources.extract(it);
+ physicalDisplays.insert(std::move(extractIter));
}
}
+ mDisplayResources.swap(physicalDisplays);
mDisplayResources.clear();
return true;
}
diff --git a/graphics/mapper/2.0/default/OWNERS b/graphics/mapper/2.0/default/OWNERS
deleted file mode 100644
index c9f24d0..0000000
--- a/graphics/mapper/2.0/default/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Graphics team
-chrisforbes@google.com
-jreck@google.com
-lpy@google.com
diff --git a/graphics/mapper/2.0/utils/OWNERS b/graphics/mapper/2.0/utils/OWNERS
deleted file mode 100644
index c9f24d0..0000000
--- a/graphics/mapper/2.0/utils/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Graphics team
-chrisforbes@google.com
-jreck@google.com
-lpy@google.com
diff --git a/graphics/mapper/2.0/utils/passthrough/include/mapper-passthrough/2.0/Gralloc1Hal.h b/graphics/mapper/2.0/utils/passthrough/include/mapper-passthrough/2.0/Gralloc1Hal.h
index db7e67d..5f0a176 100644
--- a/graphics/mapper/2.0/utils/passthrough/include/mapper-passthrough/2.0/Gralloc1Hal.h
+++ b/graphics/mapper/2.0/utils/passthrough/include/mapper-passthrough/2.0/Gralloc1Hal.h
@@ -259,19 +259,22 @@
for (int i = 0; i < 3; i++) {
const auto& plane = flex.planes[i];
- // must have 8-bit depth
- if (plane.bits_per_component != 8 || plane.bits_used != 8) {
+ // Must be a positive multiple of 8.
+ if (plane.bits_per_component <= 0 || (plane.bits_per_component % 8) != 0) {
return false;
}
-
+ // Must be between 1 and bits_per_component, inclusive.
+ if (plane.bits_used < 1 || plane.bits_used > plane.bits_per_component) {
+ return false;
+ }
if (plane.component == FLEX_COMPONENT_Y) {
// Y must not be interleaved
- if (plane.h_increment != 1) {
+ if (plane.h_increment != 1 && plane.h_increment != 2) {
return false;
}
} else {
// Cb and Cr can be interleaved
- if (plane.h_increment != 1 && plane.h_increment != 2) {
+ if (plane.h_increment != 1 && plane.h_increment != 2 && plane.h_increment != 4) {
return false;
}
}
diff --git a/graphics/mapper/2.0/vts/OWNERS b/graphics/mapper/2.0/vts/OWNERS
deleted file mode 100644
index 62e3f2a..0000000
--- a/graphics/mapper/2.0/vts/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-# Bug component: 25423
-chrisforbes@google.com
-jreck@google.com
-lpy@google.com
-sumir@google.com
diff --git a/graphics/mapper/2.1/default/OWNERS b/graphics/mapper/2.1/default/OWNERS
deleted file mode 100644
index c9f24d0..0000000
--- a/graphics/mapper/2.1/default/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Graphics team
-chrisforbes@google.com
-jreck@google.com
-lpy@google.com
diff --git a/graphics/mapper/2.1/utils/OWNERS b/graphics/mapper/2.1/utils/OWNERS
deleted file mode 100644
index c9f24d0..0000000
--- a/graphics/mapper/2.1/utils/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Graphics team
-chrisforbes@google.com
-jreck@google.com
-lpy@google.com
diff --git a/graphics/mapper/2.1/vts/OWNERS b/graphics/mapper/2.1/vts/OWNERS
deleted file mode 100644
index 43c018a..0000000
--- a/graphics/mapper/2.1/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 25423
-include ../../2.0/vts/OWNERS
diff --git a/graphics/mapper/3.0/utils/OWNERS b/graphics/mapper/3.0/utils/OWNERS
deleted file mode 100644
index c9f24d0..0000000
--- a/graphics/mapper/3.0/utils/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Graphics team
-chrisforbes@google.com
-jreck@google.com
-lpy@google.com
diff --git a/graphics/mapper/3.0/vts/OWNERS b/graphics/mapper/3.0/vts/OWNERS
deleted file mode 100644
index 43c018a..0000000
--- a/graphics/mapper/3.0/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 25423
-include ../../2.0/vts/OWNERS
diff --git a/graphics/mapper/4.0/utils/OWNERS b/graphics/mapper/4.0/utils/OWNERS
deleted file mode 100644
index c9f24d0..0000000
--- a/graphics/mapper/4.0/utils/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Graphics team
-chrisforbes@google.com
-jreck@google.com
-lpy@google.com
diff --git a/graphics/mapper/4.0/utils/vts/Android.bp b/graphics/mapper/4.0/utils/vts/Android.bp
index 7abf5db..269b972 100644
--- a/graphics/mapper/4.0/utils/vts/Android.bp
+++ b/graphics/mapper/4.0/utils/vts/Android.bp
@@ -25,14 +25,17 @@
cc_library_static {
name: "android.hardware.graphics.mapper@4.0-vts",
- defaults: ["VtsHalTargetTestDefaults"],
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "android.hardware.graphics.allocator-ndk_static",
+ "android.hardware.graphics.common-ndk_static",
+ ],
srcs: ["MapperVts.cpp"],
cflags: [
"-O0",
"-g",
],
static_libs: [
- "android.hardware.graphics.allocator-V1-ndk",
"android.hardware.graphics.allocator@4.0",
"android.hardware.graphics.common-V3-ndk",
"android.hardware.graphics.mapper@4.0",
@@ -44,7 +47,6 @@
"libvndksupport",
],
export_static_lib_headers: [
- "android.hardware.graphics.allocator-V1-ndk",
"android.hardware.graphics.allocator@4.0",
"android.hardware.graphics.common-V3-ndk",
"android.hardware.graphics.mapper@4.0",
diff --git a/graphics/mapper/4.0/vts/OWNERS b/graphics/mapper/4.0/vts/OWNERS
deleted file mode 100644
index 43c018a..0000000
--- a/graphics/mapper/4.0/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 25423
-include ../../2.0/vts/OWNERS
diff --git a/graphics/mapper/4.0/vts/functional/Android.bp b/graphics/mapper/4.0/vts/functional/Android.bp
index e830633..8f3e7eb 100644
--- a/graphics/mapper/4.0/vts/functional/Android.bp
+++ b/graphics/mapper/4.0/vts/functional/Android.bp
@@ -27,6 +27,8 @@
name: "VtsHalGraphicsMapperV4_0TargetTest",
defaults: [
"VtsHalTargetTestDefaults",
+ "android.hardware.graphics.allocator-ndk_shared",
+ "android.hardware.graphics.common-ndk_static",
"use_libaidlvintf_gtest_helper_static",
],
srcs: ["VtsHalGraphicsMapperV4_0TargetTest.cpp"],
@@ -38,7 +40,6 @@
"libsync",
],
shared_libs: [
- "android.hardware.graphics.allocator-V1-ndk",
"android.hardware.graphics.allocator@4.0",
"android.hardware.graphics.common@1.0",
"android.hardware.graphics.common@1.1",
diff --git a/graphics/mapper/stable-c/Android.bp b/graphics/mapper/stable-c/Android.bp
new file mode 100644
index 0000000..c03f67e
--- /dev/null
+++ b/graphics/mapper/stable-c/Android.bp
@@ -0,0 +1,104 @@
+/**
+ * Copyright (c) 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_headers {
+ name: "libimapper_stablec",
+ export_include_dirs: ["include"],
+ vendor_available: true,
+ header_libs: [
+ "libarect_headers",
+ ],
+ export_header_lib_headers: [
+ "libarect_headers",
+ ],
+}
+
+cc_library_headers {
+ name: "libimapper_providerutils",
+ vendor_available: true,
+ export_include_dirs: ["implutils/include"],
+ header_libs: [
+ "libbase_headers",
+ "libimapper_stablec",
+ ],
+ export_header_lib_headers: [
+ "libbase_headers",
+ "libimapper_stablec",
+ ],
+}
+
+cc_test {
+ name: "libimapper_providerutils_tests",
+ defaults: [
+ "android.hardware.graphics.allocator-ndk_shared",
+ "android.hardware.graphics.common-ndk_shared",
+ ],
+ header_libs: [
+ "libimapper_providerutils",
+ ],
+ srcs: [
+ "implutils/impltests.cpp",
+ ],
+ visibility: [":__subpackages__"],
+ cpp_std: "experimental",
+}
+
+cc_test {
+ name: "VtsHalGraphicsMapperStableC_TargetTest",
+ cpp_std: "experimental",
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "use_libaidlvintf_gtest_helper_static",
+ "android.hardware.graphics.allocator-ndk_shared",
+ "android.hardware.graphics.common-ndk_shared",
+ ],
+ srcs: [
+ "vts/VtsHalGraphicsMapperStableC_TargetTest.cpp",
+ ],
+
+ shared_libs: [
+ "libbinder_ndk",
+ "libbase",
+ "libsync",
+ "libvndksupport",
+ ],
+ static_libs: [
+ "libaidlcommonsupport",
+ "libgralloctypes",
+ "libgtest",
+ ],
+ header_libs: [
+ "libimapper_stablec",
+ "libimapper_providerutils",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+}
diff --git a/graphics/mapper/stable-c/implutils/impltests.cpp b/graphics/mapper/stable-c/implutils/impltests.cpp
new file mode 100644
index 0000000..9c5d70b
--- /dev/null
+++ b/graphics/mapper/stable-c/implutils/impltests.cpp
@@ -0,0 +1,314 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <android/hardware/graphics/mapper/utils/IMapperMetadataTypes.h>
+#include <android/hardware/graphics/mapper/utils/IMapperProvider.h>
+#include <vector>
+
+using namespace ::android::hardware::graphics::mapper;
+using namespace ::aidl::android::hardware::graphics::common;
+
+// These tests are primarily interested in hitting all the different *types* that can be
+// serialized/deserialized than in exhaustively testing all the StandardMetadataTypes.
+// Exhaustive testing of the actual metadata types is relegated for IMapper's VTS suite
+// where meaning & correctness of values are more narrowly defined (eg, read-only values)
+
+TEST(Metadata, setGetBufferId) {
+ using BufferId = StandardMetadata<StandardMetadataType::BUFFER_ID>::value;
+
+ std::vector<char> buffer;
+ buffer.resize(12, 0);
+ *reinterpret_cast<int64_t*>(buffer.data()) = 42;
+
+ EXPECT_EQ(8, BufferId::encode(18, buffer.data(), 0));
+ EXPECT_EQ(42, *reinterpret_cast<int64_t*>(buffer.data()));
+ EXPECT_EQ(8, BufferId::encode(18, buffer.data(), buffer.size()));
+ EXPECT_EQ(18, *reinterpret_cast<int64_t*>(buffer.data()));
+ EXPECT_FALSE(BufferId::decode(buffer.data(), 0));
+ auto read = BufferId::decode(buffer.data(), buffer.size());
+ EXPECT_TRUE(read.has_value());
+ EXPECT_EQ(18, read.value_or(0));
+}
+
+TEST(Metadata, setGetDataspace) {
+ using DataspaceValue = StandardMetadata<StandardMetadataType::DATASPACE>::value;
+ using intType = std::underlying_type_t<Dataspace>;
+ std::vector<char> buffer;
+ buffer.resize(12, 0);
+
+ EXPECT_EQ(4, DataspaceValue::encode(Dataspace::BT2020, buffer.data(), 0));
+ EXPECT_EQ(0, *reinterpret_cast<intType*>(buffer.data()));
+ EXPECT_EQ(4, DataspaceValue::encode(Dataspace::BT2020, buffer.data(), buffer.size()));
+ EXPECT_EQ(static_cast<intType>(Dataspace::BT2020), *reinterpret_cast<intType*>(buffer.data()));
+ EXPECT_FALSE(DataspaceValue::decode(buffer.data(), 0));
+ auto read = DataspaceValue::decode(buffer.data(), buffer.size());
+ ASSERT_TRUE(read.has_value());
+ EXPECT_EQ(Dataspace::BT2020, *read);
+}
+
+TEST(Metadata, setGetValidName) {
+ using NameValue = StandardMetadata<StandardMetadataType::NAME>::value;
+
+ std::vector<char> buffer;
+ buffer.resize(100, 'a');
+ buffer[buffer.size() - 1] = '\0';
+
+ // len("Hello") + sizeof(int64)
+ constexpr int expectedSize = 5 + sizeof(int64_t);
+ EXPECT_EQ(expectedSize, NameValue::encode("Hello", buffer.data(), buffer.size()));
+ EXPECT_EQ(5, *reinterpret_cast<int64_t*>(buffer.data()));
+ // Verify didn't write past the end of the desired size
+ EXPECT_EQ('a', buffer[expectedSize]);
+
+ auto readValue = NameValue::decode(buffer.data(), buffer.size());
+ ASSERT_TRUE(readValue.has_value());
+ EXPECT_EQ(5, readValue->length());
+ EXPECT_EQ("Hello", *readValue);
+}
+
+TEST(Metadata, setGetInvalidName) {
+ using NameValue = StandardMetadata<StandardMetadataType::NAME>::value;
+
+ std::vector<char> buffer;
+ buffer.resize(12, 'a');
+ buffer[buffer.size() - 1] = '\0';
+
+ // len("This is a long string") + sizeof(int64)
+ constexpr int expectedSize = 21 + sizeof(int64_t);
+ EXPECT_EQ(expectedSize,
+ NameValue::encode("This is a long string", buffer.data(), buffer.size()));
+ EXPECT_EQ(21, *reinterpret_cast<int64_t*>(buffer.data()));
+ // Verify didn't write the too-long string
+ EXPECT_EQ('a', buffer[9]);
+ EXPECT_EQ('\0', buffer[buffer.size() - 1]);
+
+ auto readValue = NameValue::decode(buffer.data(), buffer.size());
+ EXPECT_FALSE(readValue.has_value());
+ readValue = NameValue::decode(buffer.data(), 0);
+ ASSERT_FALSE(readValue.has_value());
+}
+
+TEST(Metadata, wouldOverflowName) {
+ using NameValue = StandardMetadata<StandardMetadataType::NAME>::value;
+ std::vector<char> buffer(100, 0);
+
+ // int_max + sizeof(int64) overflows int32
+ std::string_view bad_string{"badbeef", std::numeric_limits<int32_t>::max()};
+ EXPECT_EQ(-AIMAPPER_ERROR_BAD_VALUE,
+ NameValue::encode(bad_string, buffer.data(), buffer.size()));
+
+ // check barely overflows
+ bad_string = std::string_view{"badbeef", std::numeric_limits<int32_t>::max() - 7};
+ EXPECT_EQ(-AIMAPPER_ERROR_BAD_VALUE,
+ NameValue::encode(bad_string, buffer.data(), buffer.size()));
+}
+
+TEST(Metadata, setGetCompression) {
+ using CompressionValue = StandardMetadata<StandardMetadataType::COMPRESSION>::value;
+ ExtendableType myCompression{"bestest_compression_ever", 42};
+ std::vector<char> buffer(100, '\0');
+ const int expectedSize = myCompression.name.length() + sizeof(int64_t) + sizeof(int64_t);
+ EXPECT_EQ(expectedSize, CompressionValue::encode(myCompression, buffer.data(), 0));
+ EXPECT_EQ(0, buffer[0]);
+ EXPECT_EQ(expectedSize, CompressionValue::encode(myCompression, buffer.data(), buffer.size()));
+ EXPECT_EQ(myCompression.name.length(), *reinterpret_cast<int64_t*>(buffer.data()));
+ EXPECT_FALSE(CompressionValue::decode(buffer.data(), 0).has_value());
+ auto read = CompressionValue::decode(buffer.data(), buffer.size());
+ ASSERT_TRUE(read.has_value());
+ EXPECT_EQ(myCompression, read.value());
+}
+
+TEST(Metadata, setGetPlaneLayout) {
+ using PlaneLayoutValue = StandardMetadata<StandardMetadataType::PLANE_LAYOUTS>::value;
+ PlaneLayout myPlaneLayout;
+ myPlaneLayout.offsetInBytes = 10;
+ myPlaneLayout.sampleIncrementInBits = 11;
+ myPlaneLayout.strideInBytes = 12;
+ myPlaneLayout.widthInSamples = 13;
+ myPlaneLayout.heightInSamples = 14;
+ myPlaneLayout.totalSizeInBytes = 15;
+ myPlaneLayout.horizontalSubsampling = 16;
+ myPlaneLayout.verticalSubsampling = 17;
+
+ myPlaneLayout.components.resize(3);
+ for (int i = 0; i < myPlaneLayout.components.size(); i++) {
+ auto& it = myPlaneLayout.components[i];
+ it.type = ExtendableType{"Plane ID", 40 + i};
+ it.offsetInBits = 20 + i;
+ it.sizeInBits = 30 + i;
+ }
+
+ std::vector<PlaneLayout> layouts{myPlaneLayout, PlaneLayout{}};
+
+ std::vector<char> buffer(5000, '\0');
+ constexpr int componentSize = 8 + (4 * sizeof(int64_t));
+ constexpr int firstLayoutSize = (8 + 1) * sizeof(int64_t) + (3 * componentSize);
+ constexpr int secondLayoutSize = (8 + 1) * sizeof(int64_t);
+ constexpr int expectedSize = firstLayoutSize + secondLayoutSize + sizeof(int64_t);
+ EXPECT_EQ(expectedSize, PlaneLayoutValue::encode(layouts, buffer.data(), 0));
+ EXPECT_EQ(0, buffer[0]);
+ EXPECT_EQ(expectedSize, PlaneLayoutValue::encode(layouts, buffer.data(), buffer.size()));
+ EXPECT_EQ(3, reinterpret_cast<int64_t*>(buffer.data())[1]);
+ EXPECT_EQ(8, reinterpret_cast<int64_t*>(buffer.data())[2]);
+ EXPECT_EQ(40, reinterpret_cast<int64_t*>(buffer.data())[4]);
+ EXPECT_EQ(31, reinterpret_cast<int64_t*>(buffer.data())[11]);
+ EXPECT_EQ(22, reinterpret_cast<int64_t*>(buffer.data())[15]);
+ EXPECT_EQ(10, reinterpret_cast<int64_t*>(buffer.data())[17]);
+ EXPECT_EQ(11, reinterpret_cast<int64_t*>(buffer.data())[18]);
+ EXPECT_FALSE(PlaneLayoutValue::decode(buffer.data(), 0).has_value());
+ auto read = PlaneLayoutValue::decode(buffer.data(), buffer.size());
+ ASSERT_TRUE(read.has_value());
+ EXPECT_EQ(layouts, *read);
+}
+
+TEST(Metadata, setGetRects) {
+ using RectsValue = StandardMetadata<StandardMetadataType::CROP>::value;
+ std::vector<uint8_t> buffer(500, 0);
+ std::vector<Rect> cropRects{2};
+ cropRects[0] = Rect{10, 11, 12, 13};
+ cropRects[1] = Rect{20, 21, 22, 23};
+
+ constexpr int expectedSize = sizeof(int64_t) + (8 * sizeof(int32_t));
+ EXPECT_EQ(expectedSize, RectsValue::encode(cropRects, buffer.data(), buffer.size()));
+ EXPECT_EQ(2, reinterpret_cast<int64_t*>(buffer.data())[0]);
+ EXPECT_EQ(10, reinterpret_cast<int32_t*>(buffer.data())[2]);
+ auto read = RectsValue::decode(buffer.data(), buffer.size());
+ ASSERT_TRUE(read.has_value());
+ EXPECT_EQ(cropRects.size(), read->size());
+ EXPECT_EQ(cropRects, *read);
+}
+
+TEST(Metadata, setGetSmpte2086) {
+ using Smpte2086Value = StandardMetadata<StandardMetadataType::SMPTE2086>::value;
+ Smpte2086 source;
+ source.minLuminance = 12.335f;
+ source.maxLuminance = 452.889f;
+ source.whitePoint = XyColor{-6.f, -9.f};
+ source.primaryRed = XyColor{.1f, .2f};
+ source.primaryGreen = XyColor{.3f, .4f};
+ source.primaryBlue = XyColor{.5f, .6f};
+
+ constexpr int expectedSize = 10 * sizeof(float);
+ std::vector<uint8_t> buffer(500, 0);
+ EXPECT_EQ(expectedSize, Smpte2086Value::encode(source, buffer.data(), buffer.size()));
+ auto read = Smpte2086Value::decode(buffer.data(), buffer.size());
+ ASSERT_TRUE(read.has_value());
+ ASSERT_TRUE(read->has_value());
+ EXPECT_EQ(source, read->value());
+
+ // A valid encoding of a nullopt
+ read = Smpte2086Value::decode(nullptr, 0);
+ ASSERT_TRUE(read.has_value());
+ EXPECT_FALSE(read->has_value());
+}
+
+TEST(Metadata, setGetCta861_3) {
+ using Cta861_3Value = StandardMetadata<StandardMetadataType::CTA861_3>::value;
+ Cta861_3 source;
+ source.maxFrameAverageLightLevel = 244.55f;
+ source.maxContentLightLevel = 202.202f;
+
+ constexpr int expectedSize = 2 * sizeof(float);
+ std::vector<uint8_t> buffer(500, 0);
+ EXPECT_EQ(expectedSize, Cta861_3Value::encode(source, buffer.data(), buffer.size()));
+ auto read = Cta861_3Value::decode(buffer.data(), buffer.size());
+ ASSERT_TRUE(read.has_value());
+ ASSERT_TRUE(read->has_value());
+ EXPECT_EQ(source, read->value());
+
+ // A valid encoding of a nullopt
+ read = Cta861_3Value::decode(nullptr, 0);
+ ASSERT_TRUE(read.has_value());
+ EXPECT_FALSE(read->has_value());
+}
+
+TEST(Metadata, setGetSmpte2094_10) {
+ using SMPTE2094_10Value = StandardMetadata<StandardMetadataType::SMPTE2094_10>::value;
+
+ std::vector<uint8_t> buffer(500, 0);
+ EXPECT_EQ(0, SMPTE2094_10Value::encode(std::nullopt, buffer.data(), buffer.size()));
+ auto read = SMPTE2094_10Value::decode(buffer.data(), 0);
+ ASSERT_TRUE(read.has_value());
+ EXPECT_FALSE(read->has_value());
+
+ const std::vector<uint8_t> emptyBuffer;
+ EXPECT_EQ(sizeof(int64_t),
+ SMPTE2094_10Value::encode(emptyBuffer, buffer.data(), buffer.size()));
+ read = SMPTE2094_10Value::decode(buffer.data(), buffer.size());
+ ASSERT_TRUE(read.has_value());
+ ASSERT_TRUE(read->has_value());
+ EXPECT_EQ(0, read->value().size());
+
+ const std::vector<uint8_t> simpleBuffer{0, 1, 2, 3, 4, 5};
+ EXPECT_EQ(sizeof(int64_t) + 6,
+ SMPTE2094_10Value::encode(simpleBuffer, buffer.data(), buffer.size()));
+ read = SMPTE2094_10Value::decode(buffer.data(), buffer.size());
+ ASSERT_TRUE(read.has_value());
+ ASSERT_TRUE(read->has_value());
+ EXPECT_EQ(6, read->value().size());
+ EXPECT_EQ(simpleBuffer, read->value());
+}
+
+TEST(MetadataProvider, bufferId) {
+ using BufferId = StandardMetadata<StandardMetadataType::BUFFER_ID>::value;
+ std::vector<uint8_t> buffer(500, 0);
+ int result = provideStandardMetadata(StandardMetadataType::BUFFER_ID, buffer.data(),
+ buffer.size(), []<StandardMetadataType T>(auto&& provide) {
+ if constexpr (T == StandardMetadataType::BUFFER_ID) {
+ return provide(42);
+ }
+ return 0;
+ });
+
+ EXPECT_EQ(8, result);
+ auto read = BufferId::decode(buffer.data(), buffer.size());
+ EXPECT_EQ(42, read.value_or(0));
+}
+
+TEST(MetadataProvider, allJumpsWork) {
+ const auto& values = ndk::internal::enum_values<StandardMetadataType>;
+ auto get = [](StandardMetadataType type) -> int {
+ return provideStandardMetadata(type, nullptr, 0, []<StandardMetadataType T>(auto&&) {
+ return static_cast<int>(T) + 100;
+ });
+ };
+
+ for (auto& type : values) {
+ const int expected = type == StandardMetadataType::INVALID ? -AIMAPPER_ERROR_UNSUPPORTED
+ : static_cast<int>(type) + 100;
+ EXPECT_EQ(expected, get(type));
+ }
+}
+
+TEST(MetadataProvider, invalid) {
+ int result = provideStandardMetadata(StandardMetadataType::INVALID, nullptr, 0,
+ []<StandardMetadataType T>(auto&&) { return 10; });
+
+ EXPECT_EQ(-AIMAPPER_ERROR_UNSUPPORTED, result);
+}
+
+TEST(MetadataProvider, outOfBounds) {
+ int result = provideStandardMetadata(static_cast<StandardMetadataType>(-1), nullptr, 0,
+ []<StandardMetadataType T>(auto&&) { return 10; });
+ EXPECT_EQ(-AIMAPPER_ERROR_UNSUPPORTED, result) << "-1 should have resulted in UNSUPPORTED";
+
+ result = provideStandardMetadata(static_cast<StandardMetadataType>(100), nullptr, 0,
+ []<StandardMetadataType T>(auto&&) { return 10; });
+ EXPECT_EQ(-AIMAPPER_ERROR_UNSUPPORTED, result)
+ << "100 (out of range) should have resulted in UNSUPPORTED";
+}
diff --git a/graphics/mapper/stable-c/implutils/include/android/hardware/graphics/mapper/utils/IMapperMetadataTypes.h b/graphics/mapper/stable-c/implutils/include/android/hardware/graphics/mapper/utils/IMapperMetadataTypes.h
new file mode 100644
index 0000000..7861af8
--- /dev/null
+++ b/graphics/mapper/stable-c/implutils/include/android/hardware/graphics/mapper/utils/IMapperMetadataTypes.h
@@ -0,0 +1,576 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/graphics/common/BlendMode.h>
+#include <aidl/android/hardware/graphics/common/BufferUsage.h>
+#include <aidl/android/hardware/graphics/common/Cta861_3.h>
+#include <aidl/android/hardware/graphics/common/Dataspace.h>
+#include <aidl/android/hardware/graphics/common/ExtendableType.h>
+#include <aidl/android/hardware/graphics/common/PixelFormat.h>
+#include <aidl/android/hardware/graphics/common/PlaneLayout.h>
+#include <aidl/android/hardware/graphics/common/PlaneLayoutComponent.h>
+#include <aidl/android/hardware/graphics/common/Rect.h>
+#include <aidl/android/hardware/graphics/common/Smpte2086.h>
+#include <aidl/android/hardware/graphics/common/StandardMetadataType.h>
+#include <aidl/android/hardware/graphics/common/XyColor.h>
+#include <android/hardware/graphics/mapper/IMapper.h>
+
+#include <cinttypes>
+#include <string_view>
+#include <type_traits>
+#include <vector>
+
+namespace android::hardware::graphics::mapper {
+
+using ::aidl::android::hardware::graphics::common::BlendMode;
+using ::aidl::android::hardware::graphics::common::BufferUsage;
+using ::aidl::android::hardware::graphics::common::Cta861_3;
+using ::aidl::android::hardware::graphics::common::Dataspace;
+using ::aidl::android::hardware::graphics::common::ExtendableType;
+using ::aidl::android::hardware::graphics::common::PixelFormat;
+using ::aidl::android::hardware::graphics::common::PlaneLayout;
+using ::aidl::android::hardware::graphics::common::PlaneLayoutComponent;
+using ::aidl::android::hardware::graphics::common::Rect;
+using ::aidl::android::hardware::graphics::common::Smpte2086;
+using ::aidl::android::hardware::graphics::common::StandardMetadataType;
+using ::aidl::android::hardware::graphics::common::XyColor;
+
+class MetadataWriter {
+ private:
+ uint8_t* _Nonnull mDest;
+ size_t mSizeRemaining = 0;
+ int32_t mDesiredSize = 0;
+
+ void* _Nullable reserve(size_t sizeToWrite) {
+ if (mDesiredSize < 0) {
+ // Error state
+ return nullptr;
+ }
+ if (__builtin_add_overflow(mDesiredSize, sizeToWrite, &mDesiredSize)) {
+ // Overflowed, abort writing any further data
+ mDesiredSize = -AIMAPPER_ERROR_BAD_VALUE;
+ mSizeRemaining = 0;
+ return nullptr;
+ }
+ if (sizeToWrite > mSizeRemaining) {
+ mSizeRemaining = 0;
+ return nullptr;
+ } else {
+ mSizeRemaining -= sizeToWrite;
+ uint8_t* whereToWrite = mDest;
+ mDest += sizeToWrite;
+ return whereToWrite;
+ }
+ }
+
+ public:
+ explicit MetadataWriter(void* _Nullable destBuffer, size_t destBufferSize)
+ : mDest(reinterpret_cast<uint8_t*>(destBuffer)), mSizeRemaining(destBufferSize) {}
+
+ int32_t desiredSize() const { return mDesiredSize; }
+
+ template <typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
+ MetadataWriter& write(T value) {
+ auto sizeToWrite = sizeof(T);
+ if (void* dest = reserve(sizeToWrite)) {
+ memcpy(dest, &value, sizeToWrite);
+ }
+ return *this;
+ }
+
+ MetadataWriter& write(float value) {
+ auto sizeToWrite = sizeof(float);
+ if (void* dest = reserve(sizeToWrite)) {
+ memcpy(dest, &value, sizeToWrite);
+ }
+ return *this;
+ }
+
+ MetadataWriter& write(const std::string_view& value) {
+ auto sizeToWrite = value.length();
+ write<int64_t>(sizeToWrite);
+ if (void* dest = reserve(sizeToWrite)) {
+ memcpy(dest, value.data(), sizeToWrite);
+ }
+ return *this;
+ }
+
+ MetadataWriter& write(const std::vector<uint8_t>& value) {
+ auto sizeToWrite = value.size();
+ write<int64_t>(sizeToWrite);
+ if (void* dest = reserve(sizeToWrite)) {
+ memcpy(dest, value.data(), sizeToWrite);
+ }
+ return *this;
+ }
+
+ MetadataWriter& write(const ExtendableType& value) {
+ return write(value.name).write(value.value);
+ }
+
+ MetadataWriter& write(const XyColor& value) { return write(value.x).write(value.y); }
+};
+
+class MetadataReader {
+ private:
+ const uint8_t* _Nonnull mSrc;
+ size_t mSizeRemaining = 0;
+ bool mOk = true;
+
+ const void* _Nullable advance(size_t size) {
+ if (mOk && mSizeRemaining >= size) {
+ const void* buf = mSrc;
+ mSrc += size;
+ mSizeRemaining -= size;
+ return buf;
+ }
+ mOk = false;
+ return nullptr;
+ }
+
+ public:
+ explicit MetadataReader(const void* _Nonnull metadata, size_t metadataSize)
+ : mSrc(reinterpret_cast<const uint8_t*>(metadata)), mSizeRemaining(metadataSize) {}
+
+ [[nodiscard]] size_t remaining() const { return mSizeRemaining; }
+ [[nodiscard]] bool ok() const { return mOk; }
+
+ template <typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
+ MetadataReader& read(T& dest) {
+ if (const void* src = advance(sizeof(T))) {
+ memcpy(&dest, src, sizeof(T));
+ }
+ return *this;
+ }
+
+ MetadataReader& read(float& dest) {
+ if (const void* src = advance(sizeof(float))) {
+ memcpy(&dest, src, sizeof(float));
+ }
+ return *this;
+ }
+
+ MetadataReader& read(std::string& dest) {
+ dest = readString();
+ return *this;
+ }
+
+ MetadataReader& read(ExtendableType& dest) {
+ dest.name = readString();
+ read(dest.value);
+ return *this;
+ }
+
+ MetadataReader& read(XyColor& dest) {
+ read(dest.x);
+ read(dest.y);
+ return *this;
+ }
+
+ template <typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
+ [[nodiscard]] std::optional<T> readInt() {
+ auto sizeToRead = sizeof(T);
+ if (const void* src = advance(sizeof(T))) {
+ T ret;
+ memcpy(&ret, src, sizeToRead);
+ return ret;
+ }
+ return std::nullopt;
+ }
+
+ [[nodiscard]] std::string_view readString() {
+ auto lengthOpt = readInt<int64_t>();
+ if (!lengthOpt) {
+ return std::string_view{};
+ }
+ size_t length = lengthOpt.value();
+ if (const void* src = advance(length)) {
+ return std::string_view{reinterpret_cast<const char*>(src), length};
+ }
+ return std::string_view{};
+ }
+
+ [[nodiscard]] std::optional<ExtendableType> readExtendable() {
+ ExtendableType ret;
+ ret.name = readString();
+ auto value = readInt<int64_t>();
+ if (value) {
+ ret.value = value.value();
+ return ret;
+ } else {
+ return std::nullopt;
+ }
+ }
+
+ [[nodiscard]] std::vector<uint8_t> readBuffer() {
+ std::vector<uint8_t> ret;
+ size_t length = readInt<int64_t>().value_or(0);
+ if (const void* src = advance(length)) {
+ ret.resize(length);
+ memcpy(ret.data(), src, length);
+ }
+ return ret;
+ }
+};
+
+template <typename T, class Enable = void>
+struct MetadataValue {};
+
+template <typename T>
+struct MetadataValue<T, std::enable_if_t<std::is_integral_v<T>>> {
+ [[nodiscard]] static int32_t encode(T value, void* _Nullable destBuffer,
+ size_t destBufferSize) {
+ return MetadataWriter{destBuffer, destBufferSize}.write(value).desiredSize();
+ }
+
+ [[nodiscard]] static std::optional<T> decode(const void* _Nonnull metadata,
+ size_t metadataSize) {
+ return MetadataReader{metadata, metadataSize}.readInt<T>();
+ }
+};
+
+template <typename T>
+struct MetadataValue<T, std::enable_if_t<std::is_enum_v<T>>> {
+ [[nodiscard]] static int32_t encode(T value, void* _Nullable destBuffer,
+ size_t destBufferSize) {
+ return MetadataWriter{destBuffer, destBufferSize}
+ .write(static_cast<std::underlying_type_t<T>>(value))
+ .desiredSize();
+ }
+
+ [[nodiscard]] static std::optional<T> decode(const void* _Nonnull metadata,
+ size_t metadataSize) {
+ std::underlying_type_t<T> temp;
+ return MetadataReader{metadata, metadataSize}.read(temp).ok()
+ ? std::optional<T>(static_cast<T>(temp))
+ : std::nullopt;
+ }
+};
+
+template <>
+struct MetadataValue<std::string> {
+ [[nodiscard]] static int32_t encode(const std::string_view& value, void* _Nullable destBuffer,
+ size_t destBufferSize) {
+ return MetadataWriter{destBuffer, destBufferSize}.write(value).desiredSize();
+ }
+
+ [[nodiscard]] static std::optional<std::string> decode(const void* _Nonnull metadata,
+ size_t metadataSize) {
+ auto reader = MetadataReader{metadata, metadataSize};
+ auto result = reader.readString();
+ return reader.ok() ? std::optional<std::string>{result} : std::nullopt;
+ }
+};
+
+template <>
+struct MetadataValue<ExtendableType> {
+ static_assert(sizeof(int64_t) == sizeof(ExtendableType::value));
+
+ [[nodiscard]] static int32_t encode(const ExtendableType& value, void* _Nullable destBuffer,
+ size_t destBufferSize) {
+ return MetadataWriter{destBuffer, destBufferSize}.write(value).desiredSize();
+ }
+
+ [[nodiscard]] static std::optional<ExtendableType> decode(const void* _Nonnull metadata,
+ size_t metadataSize) {
+ return MetadataReader{metadata, metadataSize}.readExtendable();
+ }
+};
+
+template <>
+struct MetadataValue<std::vector<PlaneLayout>> {
+ [[nodiscard]] static int32_t encode(const std::vector<PlaneLayout>& values,
+ void* _Nullable destBuffer, size_t destBufferSize) {
+ MetadataWriter writer{destBuffer, destBufferSize};
+ writer.write<int64_t>(values.size());
+ for (const auto& value : values) {
+ writer.write<int64_t>(value.components.size());
+ for (const auto& component : value.components) {
+ writer.write(component.type)
+ .write<int64_t>(component.offsetInBits)
+ .write<int64_t>(component.sizeInBits);
+ }
+ writer.write<int64_t>(value.offsetInBytes)
+ .write<int64_t>(value.sampleIncrementInBits)
+ .write<int64_t>(value.strideInBytes)
+ .write<int64_t>(value.widthInSamples)
+ .write<int64_t>(value.heightInSamples)
+ .write<int64_t>(value.totalSizeInBytes)
+ .write<int64_t>(value.horizontalSubsampling)
+ .write<int64_t>(value.verticalSubsampling);
+ }
+ return writer.desiredSize();
+ }
+
+ using DecodeResult = std::optional<std::vector<PlaneLayout>>;
+ [[nodiscard]] static DecodeResult decode(const void* _Nonnull metadata, size_t metadataSize) {
+ std::vector<PlaneLayout> values;
+ MetadataReader reader{metadata, metadataSize};
+ auto numPlanes = reader.readInt<int64_t>().value_or(0);
+ values.reserve(numPlanes);
+ for (int i = 0; i < numPlanes && reader.ok(); i++) {
+ PlaneLayout& value = values.emplace_back();
+ auto numPlaneComponents = reader.readInt<int64_t>().value_or(0);
+ value.components.reserve(numPlaneComponents);
+ for (int i = 0; i < numPlaneComponents && reader.ok(); i++) {
+ PlaneLayoutComponent& component = value.components.emplace_back();
+ reader.read(component.type)
+ .read<int64_t>(component.offsetInBits)
+ .read<int64_t>(component.sizeInBits);
+ }
+ reader.read<int64_t>(value.offsetInBytes)
+ .read<int64_t>(value.sampleIncrementInBits)
+ .read<int64_t>(value.strideInBytes)
+ .read<int64_t>(value.widthInSamples)
+ .read<int64_t>(value.heightInSamples)
+ .read<int64_t>(value.totalSizeInBytes)
+ .read<int64_t>(value.horizontalSubsampling)
+ .read<int64_t>(value.verticalSubsampling);
+ }
+ return reader.ok() ? DecodeResult{std::move(values)} : std::nullopt;
+ }
+};
+
+template <>
+struct MetadataValue<std::vector<Rect>> {
+ [[nodiscard]] static int32_t encode(const std::vector<Rect>& value, void* _Nullable destBuffer,
+ size_t destBufferSize) {
+ MetadataWriter writer{destBuffer, destBufferSize};
+ writer.write<int64_t>(value.size());
+ for (auto& rect : value) {
+ writer.write<int32_t>(rect.left)
+ .write<int32_t>(rect.top)
+ .write<int32_t>(rect.right)
+ .write<int32_t>(rect.bottom);
+ }
+ return writer.desiredSize();
+ }
+
+ using DecodeResult = std::optional<std::vector<Rect>>;
+ [[nodiscard]] static DecodeResult decode(const void* _Nonnull metadata, size_t metadataSize) {
+ MetadataReader reader{metadata, metadataSize};
+ std::vector<Rect> value;
+ auto numRects = reader.readInt<int64_t>().value_or(0);
+ value.reserve(numRects);
+ for (int i = 0; i < numRects && reader.ok(); i++) {
+ Rect& rect = value.emplace_back();
+ reader.read<int32_t>(rect.left)
+ .read<int32_t>(rect.top)
+ .read<int32_t>(rect.right)
+ .read<int32_t>(rect.bottom);
+ }
+ return reader.ok() ? DecodeResult{std::move(value)} : std::nullopt;
+ }
+};
+
+template <>
+struct MetadataValue<std::optional<Smpte2086>> {
+ [[nodiscard]] static int32_t encode(const std::optional<Smpte2086>& optValue,
+ void* _Nullable destBuffer, size_t destBufferSize) {
+ if (optValue.has_value()) {
+ const auto& value = *optValue;
+ return MetadataWriter{destBuffer, destBufferSize}
+ .write(value.primaryRed)
+ .write(value.primaryGreen)
+ .write(value.primaryBlue)
+ .write(value.whitePoint)
+ .write(value.maxLuminance)
+ .write(value.minLuminance)
+ .desiredSize();
+ } else {
+ return 0;
+ }
+ }
+
+ // Double optional because the value type itself is an optional<>
+ using DecodeResult = std::optional<std::optional<Smpte2086>>;
+ [[nodiscard]] static DecodeResult decode(const void* _Nullable metadata, size_t metadataSize) {
+ std::optional<Smpte2086> optValue{std::nullopt};
+ if (metadataSize > 0) {
+ Smpte2086 value;
+ MetadataReader reader{metadata, metadataSize};
+ reader.read(value.primaryRed)
+ .read(value.primaryGreen)
+ .read(value.primaryBlue)
+ .read(value.whitePoint)
+ .read(value.maxLuminance)
+ .read(value.minLuminance);
+ if (reader.ok()) {
+ optValue = std::move(value);
+ } else {
+ return std::nullopt;
+ }
+ }
+ return DecodeResult{std::move(optValue)};
+ }
+};
+
+template <>
+struct MetadataValue<std::optional<Cta861_3>> {
+ [[nodiscard]] static int32_t encode(const std::optional<Cta861_3>& optValue,
+ void* _Nullable destBuffer, size_t destBufferSize) {
+ if (optValue.has_value()) {
+ const auto& value = *optValue;
+ return MetadataWriter{destBuffer, destBufferSize}
+ .write(value.maxContentLightLevel)
+ .write(value.maxFrameAverageLightLevel)
+ .desiredSize();
+ } else {
+ return 0;
+ }
+ }
+
+ // Double optional because the value type itself is an optional<>
+ using DecodeResult = std::optional<std::optional<Cta861_3>>;
+ [[nodiscard]] static DecodeResult decode(const void* _Nullable metadata, size_t metadataSize) {
+ std::optional<Cta861_3> optValue{std::nullopt};
+ if (metadataSize > 0) {
+ MetadataReader reader{metadata, metadataSize};
+ Cta861_3 value;
+ reader.read(value.maxContentLightLevel).read(value.maxFrameAverageLightLevel);
+ if (reader.ok()) {
+ optValue = std::move(value);
+ } else {
+ return std::nullopt;
+ }
+ }
+ return DecodeResult{std::move(optValue)};
+ }
+};
+
+template <>
+struct MetadataValue<std::optional<std::vector<uint8_t>>> {
+ [[nodiscard]] static int32_t encode(const std::optional<std::vector<uint8_t>>& value,
+ void* _Nullable destBuffer, size_t destBufferSize) {
+ if (!value.has_value()) {
+ return 0;
+ }
+ return MetadataWriter{destBuffer, destBufferSize}.write(*value).desiredSize();
+ }
+
+ using DecodeResult = std::optional<std::optional<std::vector<uint8_t>>>;
+ [[nodiscard]] static DecodeResult decode(const void* _Nonnull metadata, size_t metadataSize) {
+ std::optional<std::vector<uint8_t>> optValue;
+ if (metadataSize > 0) {
+ MetadataReader reader{metadata, metadataSize};
+ auto value = reader.readBuffer();
+ if (reader.ok()) {
+ optValue = std::move(value);
+ } else {
+ return std::nullopt;
+ }
+ }
+ return DecodeResult{std::move(optValue)};
+ }
+};
+
+template <StandardMetadataType>
+struct StandardMetadata {};
+
+#define DEFINE_TYPE(name, typeArg) \
+ template <> \
+ struct StandardMetadata<StandardMetadataType::name> { \
+ using value_type = typeArg; \
+ using value = MetadataValue<value_type>; \
+ static_assert( \
+ StandardMetadataType::name == \
+ ndk::internal::enum_values<StandardMetadataType>[static_cast<size_t>( \
+ StandardMetadataType::name)], \
+ "StandardMetadataType must have equivalent value to index"); \
+ }
+
+DEFINE_TYPE(BUFFER_ID, uint64_t);
+DEFINE_TYPE(NAME, std::string);
+DEFINE_TYPE(WIDTH, uint64_t);
+DEFINE_TYPE(HEIGHT, uint64_t);
+DEFINE_TYPE(LAYER_COUNT, uint64_t);
+DEFINE_TYPE(PIXEL_FORMAT_REQUESTED, PixelFormat);
+DEFINE_TYPE(PIXEL_FORMAT_FOURCC, uint32_t);
+DEFINE_TYPE(PIXEL_FORMAT_MODIFIER, uint64_t);
+DEFINE_TYPE(USAGE, BufferUsage);
+DEFINE_TYPE(ALLOCATION_SIZE, uint64_t);
+DEFINE_TYPE(PROTECTED_CONTENT, uint64_t);
+DEFINE_TYPE(COMPRESSION, ExtendableType);
+DEFINE_TYPE(INTERLACED, ExtendableType);
+DEFINE_TYPE(CHROMA_SITING, ExtendableType);
+DEFINE_TYPE(PLANE_LAYOUTS, std::vector<PlaneLayout>);
+DEFINE_TYPE(CROP, std::vector<Rect>);
+DEFINE_TYPE(DATASPACE, Dataspace);
+DEFINE_TYPE(BLEND_MODE, BlendMode);
+DEFINE_TYPE(SMPTE2086, std::optional<Smpte2086>);
+DEFINE_TYPE(CTA861_3, std::optional<Cta861_3>);
+DEFINE_TYPE(SMPTE2094_10, std::optional<std::vector<uint8_t>>);
+DEFINE_TYPE(SMPTE2094_40, std::optional<std::vector<uint8_t>>);
+
+#undef DEFINE_TYPE
+
+template <typename F, std::size_t... I>
+void invokeWithStandardMetadata(F&& f, StandardMetadataType type, std::index_sequence<I...>) {
+ // Setup the jump table, mapping from each type to a springboard that invokes the template
+ // function with the appropriate concrete type
+ using F_PTR = decltype(&f);
+ using THUNK = void (*)(F_PTR);
+ static constexpr auto jump = std::array<THUNK, sizeof...(I)>{[](F_PTR fp) {
+ constexpr StandardMetadataType type = ndk::internal::enum_values<StandardMetadataType>[I];
+ if constexpr (type != StandardMetadataType::INVALID) {
+ (*fp)(StandardMetadata<type>{});
+ }
+ }...};
+
+ auto index = static_cast<size_t>(type);
+ if (index >= 0 && index < jump.size()) {
+ jump[index](&f);
+ }
+}
+
+template <typename F, typename StandardMetadataSequence = std::make_index_sequence<
+ ndk::internal::enum_values<StandardMetadataType>.size()>>
+int32_t provideStandardMetadata(StandardMetadataType type, void* _Nullable destBuffer,
+ size_t destBufferSize, F&& f) {
+ int32_t retVal = -AIMAPPER_ERROR_UNSUPPORTED;
+ invokeWithStandardMetadata(
+ [&]<StandardMetadataType T>(StandardMetadata<T>) {
+ retVal = f.template operator()<T>(
+ [&](const typename StandardMetadata<T>::value_type& value) -> int32_t {
+ return StandardMetadata<T>::value::encode(value, destBuffer,
+ destBufferSize);
+ });
+ },
+ type, StandardMetadataSequence{});
+ return retVal;
+}
+
+template <typename F, typename StandardMetadataSequence = std::make_index_sequence<
+ ndk::internal::enum_values<StandardMetadataType>.size()>>
+AIMapper_Error applyStandardMetadata(StandardMetadataType type, const void* _Nonnull metadata,
+ size_t metadataSize, F&& f) {
+ AIMapper_Error retVal = AIMAPPER_ERROR_UNSUPPORTED;
+ invokeWithStandardMetadata(
+ [&]<StandardMetadataType T>(StandardMetadata<T>) {
+ auto value = StandardMetadata<T>::value::decode(metadata, metadataSize);
+ if (value.has_value()) {
+ retVal = f.template operator()<T>(std::move(*value));
+ } else {
+ retVal = AIMAPPER_ERROR_BAD_VALUE;
+ }
+ },
+ type, StandardMetadataSequence{});
+ return retVal;
+}
+
+} // namespace android::hardware::graphics::mapper
\ No newline at end of file
diff --git a/graphics/mapper/stable-c/implutils/include/android/hardware/graphics/mapper/utils/IMapperProvider.h b/graphics/mapper/stable-c/implutils/include/android/hardware/graphics/mapper/utils/IMapperProvider.h
new file mode 100644
index 0000000..957fdc9
--- /dev/null
+++ b/graphics/mapper/stable-c/implutils/include/android/hardware/graphics/mapper/utils/IMapperProvider.h
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android-base/unique_fd.h>
+#include <android/hardware/graphics/mapper/IMapper.h>
+#include <log/log.h>
+
+#include <mutex>
+#include <optional>
+#include <type_traits>
+
+/**
+ * Helper utilities for providing an IMapper-StableC implementation.
+ */
+
+namespace vendor::mapper {
+
+/**
+ * Extend from this interface to provide Version 5 of the IMapper interface
+ */
+struct IMapperV5Impl {
+ static const auto version = AIMAPPER_VERSION_5;
+ virtual ~IMapperV5Impl() = default;
+
+ virtual AIMapper_Error importBuffer(const native_handle_t* _Nonnull handle,
+ buffer_handle_t _Nullable* _Nonnull outBufferHandle) = 0;
+
+ virtual AIMapper_Error freeBuffer(buffer_handle_t _Nonnull buffer) = 0;
+
+ virtual AIMapper_Error getTransportSize(buffer_handle_t _Nonnull buffer,
+ uint32_t* _Nonnull outNumFds,
+ uint32_t* _Nonnull outNumInts) = 0;
+
+ virtual AIMapper_Error lock(buffer_handle_t _Nonnull buffer, uint64_t cpuUsage,
+ ARect accessRegion, int acquireFence,
+ void* _Nullable* _Nonnull outData) = 0;
+
+ virtual AIMapper_Error unlock(buffer_handle_t _Nonnull buffer, int* _Nonnull releaseFence) = 0;
+
+ virtual AIMapper_Error flushLockedBuffer(buffer_handle_t _Nonnull buffer) = 0;
+
+ virtual AIMapper_Error rereadLockedBuffer(buffer_handle_t _Nonnull buffer) = 0;
+
+ virtual int32_t getMetadata(buffer_handle_t _Nonnull buffer, AIMapper_MetadataType metadataType,
+ void* _Nullable destBuffer, size_t destBufferSize) = 0;
+
+ virtual int32_t getStandardMetadata(buffer_handle_t _Nonnull buffer,
+ int64_t standardMetadataType, void* _Nullable destBuffer,
+ size_t destBufferSize) = 0;
+
+ virtual AIMapper_Error setMetadata(buffer_handle_t _Nonnull buffer,
+ AIMapper_MetadataType metadataType,
+ const void* _Nonnull metadata, size_t metadataSize) = 0;
+
+ virtual AIMapper_Error setStandardMetadata(buffer_handle_t _Nonnull buffer,
+ int64_t standardMetadataType,
+ const void* _Nonnull metadata,
+ size_t metadataSize) = 0;
+
+ virtual AIMapper_Error listSupportedMetadataTypes(
+ const AIMapper_MetadataTypeDescription* _Nullable* _Nonnull outDescriptionList,
+ size_t* _Nonnull outNumberOfDescriptions) = 0;
+
+ virtual AIMapper_Error dumpBuffer(buffer_handle_t _Nonnull bufferHandle,
+ AIMapper_DumpBufferCallback _Nonnull dumpBufferCallback,
+ void* _Null_unspecified context) = 0;
+
+ virtual AIMapper_Error dumpAllBuffers(
+ AIMapper_BeginDumpBufferCallback _Nonnull beginDumpBufferCallback,
+ AIMapper_DumpBufferCallback _Nonnull dumpBufferCallback,
+ void* _Null_unspecified context) = 0;
+
+ virtual AIMapper_Error getReservedRegion(buffer_handle_t _Nonnull buffer,
+ void* _Nullable* _Nonnull outReservedRegion,
+ uint64_t* _Nonnull outReservedSize) = 0;
+};
+
+namespace provider {
+#ifndef __cpp_inline_variables
+#error "Only C++17 & newer is supported; inline variables is missing"
+#endif
+
+inline void* _Nullable sIMapperInstance = nullptr;
+} // namespace provider
+
+template <typename IMPL>
+class IMapperProvider {
+ private:
+ static_assert(IMPL::version >= AIMAPPER_VERSION_5, "Must be at least AIMAPPER_VERSION_5");
+ static_assert(std::is_final_v<IMPL>, "Implementation must be final");
+ static_assert(std::is_constructible_v<IMPL>, "Implementation must have a no-args constructor");
+
+ std::once_flag mLoadOnceFlag;
+ std::optional<IMPL> mImpl;
+ AIMapper mMapper = {};
+
+ static IMPL& impl() {
+ return *reinterpret_cast<IMapperProvider<IMPL>*>(provider::sIMapperInstance)->mImpl;
+ }
+
+ void bindV5() {
+ mMapper.v5 = {
+ .importBuffer = [](const native_handle_t* _Nonnull handle,
+ buffer_handle_t _Nullable* _Nonnull outBufferHandle)
+ -> AIMapper_Error { return impl().importBuffer(handle, outBufferHandle); },
+
+ .freeBuffer = [](buffer_handle_t _Nonnull buffer) -> AIMapper_Error {
+ return impl().freeBuffer(buffer);
+ },
+
+ .getTransportSize = [](buffer_handle_t _Nonnull buffer,
+ uint32_t* _Nonnull outNumFds,
+ uint32_t* _Nonnull outNumInts) -> AIMapper_Error {
+ return impl().getTransportSize(buffer, outNumFds, outNumInts);
+ },
+
+ .lock = [](buffer_handle_t _Nonnull buffer, uint64_t cpuUsage, ARect accessRegion,
+ int acquireFence, void* _Nullable* _Nonnull outData) -> AIMapper_Error {
+ return impl().lock(buffer, cpuUsage, accessRegion, acquireFence, outData);
+ },
+
+ .unlock = [](buffer_handle_t _Nonnull buffer, int* _Nonnull releaseFence)
+ -> AIMapper_Error { return impl().unlock(buffer, releaseFence); },
+
+ .flushLockedBuffer = [](buffer_handle_t _Nonnull buffer) -> AIMapper_Error {
+ return impl().flushLockedBuffer(buffer);
+ },
+
+ .rereadLockedBuffer = [](buffer_handle_t _Nonnull buffer) -> AIMapper_Error {
+ return impl().rereadLockedBuffer(buffer);
+ },
+
+ .getMetadata = [](buffer_handle_t _Nonnull buffer,
+ AIMapper_MetadataType metadataType, void* _Nullable destBuffer,
+ size_t destBufferSize) -> int32_t {
+ return impl().getMetadata(buffer, metadataType, destBuffer, destBufferSize);
+ },
+
+ .getStandardMetadata = [](buffer_handle_t _Nonnull buffer,
+ int64_t standardMetadataType, void* _Nullable destBuffer,
+ size_t destBufferSize) -> int32_t {
+ return impl().getStandardMetadata(buffer, standardMetadataType, destBuffer,
+ destBufferSize);
+ },
+
+ .setMetadata = [](buffer_handle_t _Nonnull buffer,
+ AIMapper_MetadataType metadataType, const void* _Nonnull metadata,
+ size_t metadataSize) -> AIMapper_Error {
+ return impl().setMetadata(buffer, metadataType, metadata, metadataSize);
+ },
+
+ .setStandardMetadata =
+ [](buffer_handle_t _Nonnull buffer, int64_t standardMetadataType,
+ const void* _Nonnull metadata, size_t metadataSize) -> AIMapper_Error {
+ return impl().setStandardMetadata(buffer, standardMetadataType, metadata,
+ metadataSize);
+ },
+
+ .listSupportedMetadataTypes =
+ [](const AIMapper_MetadataTypeDescription* _Nullable* _Nonnull outDescriptionList,
+ size_t* _Nonnull outNumberOfDescriptions) -> AIMapper_Error {
+ return impl().listSupportedMetadataTypes(outDescriptionList,
+ outNumberOfDescriptions);
+ },
+
+ .dumpBuffer = [](buffer_handle_t _Nonnull bufferHandle,
+ AIMapper_DumpBufferCallback _Nonnull dumpBufferCallback,
+ void* _Null_unspecified context) -> AIMapper_Error {
+ return impl().dumpBuffer(bufferHandle, dumpBufferCallback, context);
+ },
+
+ .dumpAllBuffers =
+ [](AIMapper_BeginDumpBufferCallback _Nonnull beginDumpBufferCallback,
+ AIMapper_DumpBufferCallback _Nonnull dumpBufferCallback,
+ void* _Null_unspecified context) {
+ return impl().dumpAllBuffers(beginDumpBufferCallback,
+ dumpBufferCallback, context);
+ },
+
+ .getReservedRegion = [](buffer_handle_t _Nonnull buffer,
+ void* _Nullable* _Nonnull outReservedRegion,
+ uint64_t* _Nonnull outReservedSize) -> AIMapper_Error {
+ return impl().getReservedRegion(buffer, outReservedRegion, outReservedSize);
+ },
+ };
+ }
+
+ public:
+ explicit IMapperProvider() = default;
+
+ AIMapper_Error load(AIMapper* _Nullable* _Nonnull outImplementation) {
+ std::call_once(mLoadOnceFlag, [this] {
+ LOG_ALWAYS_FATAL_IF(provider::sIMapperInstance != nullptr,
+ "AIMapper implementation already loaded!");
+ provider::sIMapperInstance = this;
+ mImpl.emplace();
+ mMapper.version = IMPL::version;
+ if (IMPL::version >= AIMAPPER_VERSION_5) {
+ bindV5();
+ }
+ });
+ *outImplementation = &mMapper;
+ return AIMAPPER_ERROR_NONE;
+ }
+};
+
+} // namespace vendor::mapper
diff --git a/graphics/mapper/stable-c/include/android/hardware/graphics/mapper/IMapper.h b/graphics/mapper/stable-c/include/android/hardware/graphics/mapper/IMapper.h
new file mode 100644
index 0000000..f27b0f4
--- /dev/null
+++ b/graphics/mapper/stable-c/include/android/hardware/graphics/mapper/IMapper.h
@@ -0,0 +1,689 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * IMapper Stable-C HAL interface
+ *
+ * This file represents the sphal interface between libui & the IMapper HAL implementation.
+ * A vendor implementation of this interface is retrieved by looking up the vendor imapper
+ * implementation library via the IAllocator AIDL interface.
+ *
+ * This interface is not intended for general use.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+#include <cinttypes>
+#include <cstddef>
+#include <type_traits>
+
+#include <android/rect.h>
+#include <cutils/native_handle.h>
+
+__BEGIN_DECLS
+
+/**
+ * AIMapper versioning
+ *
+ * IMapper versions 0-1 are pre-treble
+ * IMapper versions 2-4 are HIDL
+ * C-style AIMapper API starts at 5
+ */
+enum AIMapper_Version : uint32_t {
+ AIMAPPER_VERSION_5 = 5,
+};
+
+/**
+ * Possible AIMapper errors
+ * Values are the same as IMapper 4.0's Error type for simplicity
+ */
+enum AIMapper_Error : int32_t {
+ /**
+ * No error.
+ */
+ AIMAPPER_ERROR_NONE = 0,
+ /**
+ * Invalid BufferDescriptor.
+ */
+ AIMAPPER_ERROR_BAD_DESCRIPTOR = 1,
+ /**
+ * Invalid buffer handle.
+ */
+ AIMAPPER_ERROR_BAD_BUFFER = 2,
+ /**
+ * Invalid HardwareBufferDescription.
+ */
+ AIMAPPER_ERROR_BAD_VALUE = 3,
+ /**
+ * Resource unavailable.
+ */
+ AIMAPPER_ERROR_NO_RESOURCES = 5,
+ /**
+ * Permanent failure.
+ */
+ AIMAPPER_ERROR_UNSUPPORTED = 7,
+};
+
+/**
+ * MetadataType represents the different types of buffer metadata that could be
+ * associated with a buffer. It is used by IMapper to help get and set buffer metadata
+ * on the buffer's native handle.
+ *
+ * Standard buffer metadata will have the name field set to
+ * "android.hardware.graphics.common.StandardMetadataType" and will contain values
+ * from StandardMetadataType.aidl.
+ *
+ * Vendor-provided metadata should be prefixed with a "vendor.mycompanyname.*" namespace. It is
+ * recommended that the metadata follows the pattern of StandardMetadaType.aidl. That is, an
+ * aidl-defined enum with @VendorStability on it and the naming then matching that type such
+ * as "vendor.mycompanyname.graphics.common.MetadataType" with the value field then set to the
+ * aidl's enum value.
+ *
+ * Each company should create their own enum & namespace. The name
+ * field prevents values from different companies from colliding.
+ */
+typedef struct AIMapper_MetadataType {
+ const char* _Nonnull name;
+ int64_t value;
+} AIMapper_MetadataType;
+
+typedef struct AIMapper_MetadataTypeDescription {
+ /**
+ * The `name` of the metadataType must be valid for the lifetime of the process
+ */
+ AIMapper_MetadataType metadataType;
+ /**
+ * description should contain a string representation of the MetadataType.
+ *
+ * For example: "MyExampleMetadataType is a 64-bit timestamp in nanoseconds
+ * that indicates when a buffer is decoded. It is set by the media HAL after
+ * a buffer is decoded. It is used by the display HAL for hardware
+ * synchronization".
+ *
+ * This field is required for any non-StandardMetadataTypes. For StandardMetadataTypes this
+ * field may be null. The lifetime of this pointer must be valid for the duration of the
+ * process (that is, a static const char*).
+ */
+ const char* _Nullable description;
+ /**
+ * isGettable represents if the MetadataType can be get.
+ */
+ bool isGettable;
+ /**
+ * isSettable represents if the MetadataType can be set.
+ */
+ bool isSettable;
+
+ /** Reserved for future use; must be zero-initialized currently */
+ uint8_t reserved[32];
+} AIMapper_MetadataTypeDescription;
+
+/**
+ * Callback that is passed to dumpBuffer.
+ *
+ * @param context The caller-provided void* that was passed to dumpBuffer.
+ * @param metadataType The type of the metadata passed to the callback
+ * @param value A pointer to the value of the metadata. The lifetime of this pointer is only
+ * valid for the duration of the call
+ * @param valueSize The size of the value buffer.
+ */
+typedef void (*AIMapper_DumpBufferCallback)(void* _Null_unspecified context,
+ AIMapper_MetadataType metadataType,
+ const void* _Nonnull value, size_t valueSize);
+
+/**
+ * Callback that is passed to dumpAllBuffers.
+ *
+ * Indicates that a buffer is about to be dumped. Will be followed by N calls to
+ * AIMapper_DumpBufferCallback for all the metadata for this buffer.
+ *
+ * @param context The caller-provided void* that was passed to dumpAllBuffers.
+ */
+typedef void (*AIMapper_BeginDumpBufferCallback)(void* _Null_unspecified context);
+
+/**
+ * Implementation of AIMAPPER_VERSION_5
+ * All functions must not be null & must provide a valid implementation.
+ */
+typedef struct AIMapperV5 {
+ /**
+ * Imports a raw buffer handle to create an imported buffer handle for use
+ * with the rest of the mapper or with other in-process libraries.
+ *
+ * A buffer handle is considered raw when it is cloned (e.g., with
+ * `native_handle_clone()`) from another buffer handle locally, or when it
+ * is received from another HAL server/client or another process. A raw
+ * buffer handle must not be used to access the underlying graphic
+ * buffer. It must be imported to create an imported handle first.
+ *
+ * This function must at least validate the raw handle before creating the
+ * imported handle. It must also support importing the same raw handle
+ * multiple times to create multiple imported handles. The imported handle
+ * must be considered valid everywhere in the process, including in
+ * another instance of the mapper.
+ *
+ * Because of passthrough HALs, a raw buffer handle received from a HAL
+ * may actually have been imported in the process. importBuffer() must treat
+ * such a handle as if it is raw and must not return `BAD_BUFFER`. The
+ * returned handle is independent from the input handle as usual, and
+ * freeBuffer() must be called on it when it is no longer needed.
+ *
+ * @param handle Raw buffer handle to import.
+ * @param outBufferHandle The resulting imported buffer handle.
+ * @return Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `BAD_BUFFER` if the raw handle is invalid.
+ * - `NO_RESOURCES` if the raw handle cannot be imported due to
+ * unavailability of resources.
+ */
+ AIMapper_Error (*_Nonnull importBuffer)(const native_handle_t* _Nonnull handle,
+ buffer_handle_t _Nullable* _Nonnull outBufferHandle);
+
+ /**
+ * Frees a buffer handle. Buffer handles returned by importBuffer() must be
+ * freed with this function when no longer needed.
+ *
+ * This function must free up all resources allocated by importBuffer() for
+ * the imported handle. For example, if the imported handle was created
+ * with `native_handle_create()`, this function must call
+ * `native_handle_close()` and `native_handle_delete()`.
+ *
+ * @param buffer Imported buffer handle.
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `BAD_BUFFER` if the buffer is invalid.
+ */
+ AIMapper_Error (*_Nonnull freeBuffer)(buffer_handle_t _Nonnull buffer);
+
+ /**
+ * Calculates the transport size of a buffer. An imported buffer handle is a
+ * raw buffer handle with the process-local runtime data appended. This
+ * function, for example, allows a caller to omit the process-local runtime
+ * data at the tail when serializing the imported buffer handle.
+ *
+ * Note that a client might or might not omit the process-local runtime data
+ * when sending an imported buffer handle. The mapper must support both
+ * cases on the receiving end.
+ *
+ * @param buffer Buffer to get the transport size from.
+ * @param outNumFds The number of file descriptors needed for transport.
+ * @param outNumInts The number of integers needed for transport.
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `BAD_BUFFER` if the buffer is invalid.
+ */
+ AIMapper_Error (*_Nonnull getTransportSize)(buffer_handle_t _Nonnull buffer,
+ uint32_t* _Nonnull outNumFds,
+ uint32_t* _Nonnull outNumInts);
+
+ /**
+ * Locks the given buffer for the specified CPU usage.
+ *
+ * Locking the same buffer simultaneously from multiple threads is
+ * permitted, but if any of the threads attempt to lock the buffer for
+ * writing, the behavior is undefined, except that it must not cause
+ * process termination or block the client indefinitely. Leaving the
+ * buffer content in an indeterminate state or returning an error are both
+ * acceptable.
+ *
+ * 1D buffers (width = size in bytes, height = 1, pixel_format = BLOB) must
+ * "lock in place". The buffers must be directly accessible via mapping.
+ *
+ * The client must not modify the content of the buffer outside of
+ * @p accessRegion, and the device need not guarantee that content outside
+ * of @p accessRegion is valid for reading. The result of reading or writing
+ * outside of @p accessRegion is undefined, except that it must not cause
+ * process termination.
+ *
+ * An accessRegion of all-zeros means the entire buffer. That is, it is
+ * equivalent to '(0,0)-(buffer width, buffer height)'.
+ *
+ * This function can lock both single-planar and multi-planar formats. The caller
+ * should use get() to get information about the buffer they are locking.
+ * get() can be used to get information about the planes, offsets, stride,
+ * etc.
+ *
+ * This function must also work on buffers with
+ * `AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_*` if supported by the device, as well
+ * as with any other formats requested by multimedia codecs when they are
+ * configured with a flexible-YUV-compatible color format.
+ *
+ * On success, @p data must be filled with a pointer to the locked buffer
+ * memory. This address will represent the top-left corner of the entire
+ * buffer, even if @p accessRegion does not begin at the top-left corner.
+ *
+ * The locked buffer must adhere to the format requested at allocation time
+ * in the BufferDescriptorInfo.
+ *
+ * @param buffer Buffer to lock.
+ * @param cpuUsage CPU usage flags to request. See BufferUsage.aidl for possible values.
+ * @param accessRegion Portion of the buffer that the client intends to
+ * access.
+ * @param acquireFence Handle containing a file descriptor referring to a
+ * sync fence object, which will be signaled when it is safe for the
+ * mapper to lock the buffer. @p acquireFence may be an empty fence (-1) if
+ * it is already safe to lock. Ownership is passed to the callee and it is the
+ * implementations responsibility to ensure it is closed even when an error
+ * occurs.
+ * @param outData CPU-accessible pointer to the buffer data.
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `BAD_BUFFER` if the buffer is invalid or is incompatible with this
+ * function.
+ * - `BAD_VALUE` if @p cpuUsage is 0, contains non-CPU usage flags, or
+ * is incompatible with the buffer. Also if the @p accessRegion is
+ * outside the bounds of the buffer or the accessRegion is invalid.
+ * - `NO_RESOURCES` if the buffer cannot be locked at this time. Note
+ * that locking may succeed at a later time.
+ * @return data CPU-accessible pointer to the buffer data.
+ */
+ AIMapper_Error (*_Nonnull lock)(buffer_handle_t _Nonnull buffer, uint64_t cpuUsage,
+ ARect accessRegion, int acquireFence,
+ void* _Nullable* _Nonnull outData);
+
+ /**
+ * Unlocks a buffer to indicate all CPU accesses to the buffer have
+ * completed.
+ *
+ * @param buffer Buffer to unlock.
+ * @param releaseFence Handle containing a file descriptor referring to a
+ * sync fence object. The sync fence object will be signaled when the
+ * mapper has completed any pending work. @p releaseFence may be an
+ * empty fence (-1).
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `BAD_BUFFER` if the buffer is invalid or not locked.
+ */
+ AIMapper_Error (*_Nonnull unlock)(buffer_handle_t _Nonnull buffer, int* _Nonnull releaseFence);
+
+ /**
+ * Flushes the contents of a locked buffer.
+ *
+ * This function flushes the CPUs caches for the range of all the buffer's
+ * planes and metadata. This should behave similarly to unlock() except the
+ * buffer should remain mapped to the CPU.
+ *
+ * The client is still responsible for calling unlock() when it is done
+ * with all CPU accesses to the buffer.
+ *
+ * If non-CPU blocks are simultaneously writing the buffer, the locked
+ * copy should still be flushed but what happens is undefined except that
+ * it should not cause any crashes.
+ *
+ * @param buffer Buffer to flush.
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `BAD_BUFFER` if the buffer is invalid or not locked.
+ */
+ AIMapper_Error (*_Nonnull flushLockedBuffer)(buffer_handle_t _Nonnull buffer);
+
+ /**
+ * Rereads the contents of a locked buffer.
+ *
+ * This should fetch the most recent copy of the locked buffer.
+ *
+ * It may reread locked copies of the buffer in other processes.
+ *
+ * The client is still responsible for calling unlock() when it is done
+ * with all CPU accesses to the buffer.
+ *
+ * @param buffer Buffer to reread.
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `BAD_BUFFER` if the buffer is invalid or not locked.
+ * - `NO_RESOURCES` if the buffer cannot be reread at this time. Note
+ * that rereading may succeed at a later time.
+ */
+ AIMapper_Error (*_Nonnull rereadLockedBuffer)(buffer_handle_t _Nonnull buffer);
+
+ /**
+ * Description for get(...), set(...) and getFromBufferDescriptorInfo(...)
+ *
+ * ------------ Overview -----------------------------------
+ * Gralloc 4 adds support for getting and setting buffer metadata on a buffer.
+ *
+ * To get buffer metadata, the client passes in a buffer handle and a token that
+ * represents the type of buffer metadata they would like to get. IMapper returns
+ * a byte stream that contains the buffer metadata. To set the buffer metadata, the
+ * client passes in a buffer handle and a token that represents the type of buffer
+ * metadata they would like to set and a byte stream that contains the buffer metadata
+ * they are setting.
+ *
+ * Buffer metadata is global for a buffer. When the metadata is set on the buffer
+ * in a process, the updated metadata should be available to all other processes.
+ * Please see "Storing and Propagating Metadata" below for more details.
+ *
+ * The getter and setter functions have been optimized for easy vendor extension.
+ * They do not require a formal extension to add support for getting and setting
+ * vendor defined buffer metadata. See "Buffer Metadata Token" and
+ * "Buffer Metadata Stream" below for more details.
+ *
+ * ------------ Storing and Propagating Metadata -----------
+ * Buffer metadata must be global. Any changes to the metadata must be propagated
+ * to all other processes immediately. Vendors may chose how they would like support
+ * this functionality.
+ *
+ * We recommend supporting this functionality by allocating an extra page of shared
+ * memory and storing it in the buffer's native_handle_t. The buffer metadata can
+ * be stored in the extra page of shared memory. Set operations are automatically
+ * propagated to all other processes.
+ *
+ * ------------ Buffer Metadata Synchronization ------------
+ * There are no explicit buffer metadata synchronization primitives. Many devices
+ * before gralloc 4 already support getting and setting of global buffer metadata
+ * with no explicit synchronization primitives. Adding synchronization primitives
+ * would just add unnecessary complexity.
+ *
+ * The general rule is if a process has permission to write to a buffer, they
+ * have permission to write to the buffer's writable metadata. If a process has permission
+ * to read from a buffer, they have permission to read the buffer's metadata.
+ *
+ * There is one exception to this rule. Fences CANNOT be used to protect a buffer's
+ * metadata. A process should finish writing to a buffer's metadata before
+ * sending the buffer to another process that will read or write to the buffer.
+ * This exception is needed because sometimes userspace needs to read the
+ * buffer's metadata before the buffer's contents are ready.
+ *
+ * As a simple example: an app renders to a buffer and then displays the buffer.
+ * In this example when the app renders to the buffer, both the buffer and its
+ * metadata need to be updated. The app's process queues up its work on the GPU
+ * and gets back an acquire fence. The app's process must update the buffer's
+ * metadata before enqueuing the buffer to SurfaceFlinger. The app process CANNOT
+ * update the buffer's metadata after enqueuing the buffer. When HardwareComposer
+ * receives the buffer, it is immediately safe to read the buffer's metadata
+ * and use it to program the display driver. To read the buffer's contents,
+ * display driver must still wait on the acquire fence.
+ *
+ * ------------ Buffer Metadata Token ----------------------
+ * In order to allow arbitrary vendor defined metadata, the token used to access
+ * metadata is defined defined as a struct that has a string representing
+ * the enum type and an int that represents the enum value. The string protects
+ * different enum values from colliding.
+ *
+ * The token struct (MetadataType) is defined as a C struct since it
+ * is passed into a C function. The standard buffer metadata types are NOT
+ * defined as a C enum but instead as an AIDL enum to allow for broader usage across
+ * other HALs and libraries. By putting the enum in the
+ * stable AIDL (hardware/interfaces/graphics/common/aidl/android/hardware/
+ * graphics/common/StandardMetadataType.aidl), vendors will be able to optionally
+ * choose to support future standard buffer metadata types without upgrading
+ * IMapper versions. For more information see the description of "struct MetadataType".
+ *
+ * ------------ Buffer Metadata Stream ---------------------
+ * The buffer metadata is get and set as a void* buffer. By getting
+ * and setting buffer metadata as a generic buffer, vendors can use the standard
+ * getters and setter functions defined here. Vendors do NOT need to add their own
+ * getters and setter functions for each new type of buffer metadata.
+ *
+ * Converting buffer metadata into a byte stream can be non-trivial. For the standard
+ * buffer metadata types defined in StandardMetadataType.aidl, there are also
+ * support functions that will encode the buffer metadata into a byte stream
+ * and decode the buffer metadata from a byte stream. We STRONGLY recommend using
+ * these support functions. The framework will use them when getting and setting
+ * metadata. The support functions are defined in
+ * frameworks/native/libs/gralloc/types/include/gralloctypes/Gralloc4.h.
+ */
+
+ /**
+ * Gets the buffer metadata for a given MetadataType.
+ *
+ * Buffer metadata can be changed after allocation so clients should avoid "caching"
+ * the buffer metadata. For example, if the video resolution changes and the buffers
+ * are not reallocated, several buffer metadata values may change without warning.
+ * Clients should not expect the values to be constant. They should requery them every
+ * frame. The only exception is buffer metadata that is determined at allocation
+ * time. For StandardMetadataType values, only BUFFER_ID, NAME, WIDTH,
+ * HEIGHT, LAYER_COUNT, PIXEL_FORMAT_REQUESTED and USAGE are safe to cache because
+ * they are determined at allocation time.
+ *
+ * @param buffer Buffer containing desired metadata
+ * @param metadataType MetadataType for the metadata value being queried
+ * @param destBuffer Pointer to a buffer in which to store the result of the get() call; if
+ * null, the computed output size or error must still be returned.
+ * @param destBufferSize How large the destBuffer buffer is. If destBuffer is null this must be
+ * 0.
+ * @return The number of bytes written to `destBuffer` or which would have been written
+ * if `destBufferSize` was large enough.
+ * A negative value indicates an error, which may be
+ * - `BAD_BUFFER` if the raw handle is invalid.
+ * - `UNSUPPORTED` when metadataType is unknown/unsupported.
+ * IMapper must support getting all StandardMetadataType.aidl values defined
+ * at the time the device first launches.
+ */
+ int32_t (*_Nonnull getMetadata)(buffer_handle_t _Nonnull buffer,
+ AIMapper_MetadataType metadataType, void* _Nullable destBuffer,
+ size_t destBufferSize);
+
+ /**
+ * Gets the buffer metadata for a StandardMetadataType.
+ *
+ * This is equivalent to `getMetadata` when passed an AIMapper_MetadataType with name
+ * set to "android.hardware.graphics.common.StandardMetadataType"
+ *
+ * Buffer metadata can be changed after allocation so clients should avoid "caching"
+ * the buffer metadata. For example, if the video resolution changes and the buffers
+ * are not reallocated, several buffer metadata values may change without warning.
+ * Clients should not expect the values to be constant. They should requery them every
+ * frame. The only exception is buffer metadata that is determined at allocation
+ * time. For StandardMetadataType values, only BUFFER_ID, NAME, WIDTH,
+ * HEIGHT, LAYER_COUNT, PIXEL_FORMAT_REQUESTED and USAGE are safe to cache because
+ * they are determined at allocation time.
+ *
+ * @param buffer Buffer containing desired metadata
+ * @param standardMetadataType StandardMetadataType for the metadata value being queried
+ * @param destBuffer Pointer to a buffer in which to store the result of the get() call; if
+ * null, the computed output size or error must still be returned.
+ * @param destBufferSize How large the destBuffer buffer is. If destBuffer is null this must be
+ * 0.
+ * @return The number of bytes written to `destBuffer` or which would have been written
+ * if `destBufferSize` was large enough.
+ * A negative value indicates an error, which may be
+ * - `BAD_BUFFER` if the raw handle is invalid.
+ * - `UNSUPPORTED` when metadataType is unknown/unsupported.
+ * IMapper must support getting all StandardMetadataType.aidl values defined
+ * at the time the device first launches.
+ */
+ int32_t (*_Nonnull getStandardMetadata)(buffer_handle_t _Nonnull buffer,
+ int64_t standardMetadataType,
+ void* _Nullable destBuffer, size_t destBufferSize);
+
+ /**
+ * Sets the global value for a given MetadataType.
+ *
+ * Metadata fields are not required to be settable. This function can
+ * return Error::UNSUPPORTED whenever it doesn't support setting a
+ * particular Metadata field.
+ *
+ * The framework will attempt to set the following StandardMetadataType
+ * values: DATASPACE, SMPTE2086, CTA861_3, SMPTE2094_40 and BLEND_MODE.
+ * We require everyone to support setting those fields. If a device's Composer
+ * implementation supports a field, it should be supported here. Over time these
+ * metadata fields will be moved out of Composer/BufferQueue/etc. and into the
+ * buffer's Metadata fields.
+ *
+ * @param buffer Buffer receiving desired metadata
+ * @param metadataType MetadataType for the metadata value being set
+ * @param metadata Pointer to a buffer of bytes representing the value associated with
+ * @param metadataSize The size of the metadata buffer
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `BAD_BUFFER` if the raw handle is invalid.
+ * - `BAD_VALUE` when the field is constant and can never be set (such as
+ * BUFFER_ID, NAME, WIDTH, HEIGHT, LAYER_COUNT, PIXEL_FORMAT_REQUESTED and
+ * USAGE)
+ * - `NO_RESOURCES` if the set cannot be fulfilled due to unavailability of
+ * resources.
+ * - `UNSUPPORTED` when metadataType is unknown/unsupported or setting
+ * it is unsupported. Unsupported should also be returned if the metadata
+ * is malformed.
+ */
+ AIMapper_Error (*_Nonnull setMetadata)(buffer_handle_t _Nonnull buffer,
+ AIMapper_MetadataType metadataType,
+ const void* _Nonnull metadata, size_t metadataSize);
+
+ /**
+ * Sets the global value for a given MetadataType.
+ *
+ * This is equivalent to `setMetadata` when passed an AIMapper_MetadataType with name
+ * set to "android.hardware.graphics.common.StandardMetadataType"
+ *
+ * Metadata fields are not required to be settable. This function can
+ * return Error::UNSUPPORTED whenever it doesn't support setting a
+ * particular Metadata field.
+ *
+ * The framework will attempt to set the following StandardMetadataType
+ * values: DATASPACE, SMPTE2086, CTA861_3, SMPTE2094_40 and BLEND_MODE.
+ * We require everyone to support setting those fields. If a device's Composer
+ * implementation supports a field, it should be supported here. Over time these
+ * metadata fields will be moved out of Composer/BufferQueue/etc. and into the
+ * buffer's Metadata fields.
+ *
+ * @param buffer Buffer receiving desired metadata
+ * @param standardMetadataType StandardMetadataType for the metadata value being set
+ * @param metadata Pointer to a buffer of bytes representing the value associated with
+ * @param metadataSize The size of the metadata buffer
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `BAD_BUFFER` if the raw handle is invalid.
+ * - `BAD_VALUE` when the field is constant and can never be set (such as
+ * BUFFER_ID, NAME, WIDTH, HEIGHT, LAYER_COUNT, PIXEL_FORMAT_REQUESTED and
+ * USAGE)
+ * - `NO_RESOURCES` if the set cannot be fulfilled due to unavailability of
+ * resources.
+ * - `UNSUPPORTED` when metadataType is unknown/unsupported or setting
+ * it is unsupported. Unsupported should also be returned if the metadata
+ * is malformed.
+ */
+ AIMapper_Error (*_Nonnull setStandardMetadata)(buffer_handle_t _Nonnull buffer,
+ int64_t standardMetadataType,
+ const void* _Nonnull metadata,
+ size_t metadataSize);
+
+ /**
+ * Lists all the MetadataTypes supported by IMapper as well as a description
+ * of each supported MetadataType. For StandardMetadataTypes, the description
+ * string can be left empty.
+ *
+ * This list is expected to be static & thus the returned array must be valid for the
+ * lifetime of the process.
+ *
+ * @param outDescriptionList The list of descriptions
+ * @param outNumberOfDescriptions How many descriptions are in `outDescriptionList`
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `UNSUPPORTED` if there's any error
+ */
+ AIMapper_Error (*_Nonnull listSupportedMetadataTypes)(
+ const AIMapper_MetadataTypeDescription* _Nullable* _Nonnull outDescriptionList,
+ size_t* _Nonnull outNumberOfDescriptions);
+
+ /**
+ * Dumps a buffer's metadata.
+ *
+ * @param buffer The buffer to dump the metadata for
+ * @param dumpBufferCallback Callback that will be invoked for each of the metadata fields
+ * @param context A caller-provided context to be passed to the dumpBufferCallback
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `BAD_BUFFER` if the raw handle is invalid.
+ * - `NO_RESOURCES` if the get cannot be fulfilled due to unavailability of
+ * resources.
+ */
+ AIMapper_Error (*_Nonnull dumpBuffer)(buffer_handle_t _Nonnull buffer,
+ AIMapper_DumpBufferCallback _Nonnull dumpBufferCallback,
+ void* _Null_unspecified context);
+
+ /**
+ * Dump the metadata for all imported buffers in the current process
+ *
+ * The HAL implementation should invoke beginDumpCallback before dumping a buffer's metadata,
+ * followed by N calls to dumpBufferCallback for that buffer's metadata fields. The call
+ * sequence should follow this pseudocode:
+ *
+ * for (auto buffer : gListOfImportedBuffers) {
+ * beginDumpCallback(context);
+ * for (auto metadata : buffer->allMetadata()) {
+ * dumpBufferCallback(context, metadata...);
+ * }
+ * }
+ *
+ * @param beginDumpCallback Signals that a buffer is about to be dumped
+ * @param dumpBufferCallback Callback that will be invoked for each of the metadata fields
+ * @param context A caller-provided context to be passed to beginDumpCallback and
+ * dumpBufferCallback
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `BAD_BUFFER` if the raw handle is invalid.
+ * - `NO_RESOURCES` if the get cannot be fulfilled due to unavailability of
+ * resources.
+ */
+ AIMapper_Error (*_Nonnull dumpAllBuffers)(
+ AIMapper_BeginDumpBufferCallback _Nonnull beginDumpCallback,
+ AIMapper_DumpBufferCallback _Nonnull dumpBufferCallback,
+ void* _Null_unspecified context);
+
+ /**
+ * Returns the region of shared memory associated with the buffer that is
+ * reserved for client use.
+ *
+ * The shared memory may be allocated from any shared memory allocator.
+ * The shared memory must be CPU-accessible and virtually contiguous. The
+ * starting address must be word-aligned.
+ *
+ * This function may only be called after importBuffer() has been called by the
+ * client. The reserved region must remain accessible until freeBuffer() has
+ * been called. After freeBuffer() has been called, the client must not access
+ * the reserved region.
+ *
+ * This reserved memory may be used in future versions of Android to
+ * help clients implement backwards compatible features without requiring
+ * IAllocator/IMapper updates.
+ *
+ * @param buffer Imported buffer handle.
+ * @param outReservedRegion CPU-accessible pointer to the reserved region
+ * @param outReservedSize the size of the reservedRegion that was requested
+ * in the BufferDescriptorInfo.
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `BAD_BUFFER` if the buffer is invalid.
+ */
+ AIMapper_Error (*_Nonnull getReservedRegion)(buffer_handle_t _Nonnull buffer,
+ void* _Nullable* _Nonnull outReservedRegion,
+ uint64_t* _Nonnull outReservedSize);
+
+} AIMapperV5;
+
+/**
+ * Return value for AIMapper_loadIMapper
+ *
+ * Note: This struct's size is not fixed and callers must never store it by-value as a result.
+ * Only fields up to those covered by `version` are allowed to be accessed.
+ */
+typedef struct AIMapper {
+ alignas(alignof(max_align_t)) AIMapper_Version version;
+ AIMapperV5 v5;
+} AIMapper;
+
+/**
+ * Loads the vendor-provided implementation of AIMapper
+ * @return Error status of the call.
+ * - `NONE` upon success
+ * - `UNSUPPORTED` if no implementation is available
+ */
+AIMapper_Error AIMapper_loadIMapper(AIMapper* _Nullable* _Nonnull outImplementation);
+
+__END_DECLS
\ No newline at end of file
diff --git a/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp b/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp
new file mode 100644
index 0000000..6ab11a3
--- /dev/null
+++ b/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp
@@ -0,0 +1,1565 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "VtsHalGraphicsMapperStableC_TargetTest"
+
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/graphics/allocator/AllocationError.h>
+#include <aidl/android/hardware/graphics/allocator/AllocationResult.h>
+#include <aidl/android/hardware/graphics/allocator/IAllocator.h>
+#include <aidl/android/hardware/graphics/common/BufferUsage.h>
+#include <aidl/android/hardware/graphics/common/PixelFormat.h>
+#include <aidlcommonsupport/NativeHandle.h>
+#include <android/binder_manager.h>
+#include <android/dlext.h>
+#include <android/hardware/graphics/mapper/IMapper.h>
+#include <android/hardware/graphics/mapper/utils/IMapperMetadataTypes.h>
+#include <gralloctypes/Gralloc4.h>
+#include <hidl/GtestPrinter.h>
+#include <system/graphics.h>
+
+#include <dlfcn.h>
+#include <drm/drm_fourcc.h>
+#include <gtest/gtest.h>
+#include <vndksupport/linker.h>
+#include <initializer_list>
+#include <optional>
+#include <string>
+#include <tuple>
+#include <vector>
+
+using namespace aidl::android::hardware::graphics::allocator;
+using namespace aidl::android::hardware::graphics::common;
+using namespace android;
+using namespace android::hardware;
+using namespace ::android::hardware::graphics::mapper;
+
+typedef AIMapper_Error (*AIMapper_loadIMapperFn)(AIMapper* _Nullable* _Nonnull outImplementation);
+
+inline constexpr BufferUsage operator|(BufferUsage lhs, BufferUsage rhs) {
+ using T = std::underlying_type_t<BufferUsage>;
+ return static_cast<BufferUsage>(static_cast<T>(lhs) | static_cast<T>(rhs));
+}
+
+inline BufferUsage& operator|=(BufferUsage& lhs, BufferUsage rhs) {
+ lhs = lhs | rhs;
+ return lhs;
+}
+
+struct YCbCr {
+ android_ycbcr yCbCr;
+ int64_t horizontalSubSampling;
+ int64_t verticalSubSampling;
+};
+
+class BufferHandle {
+ AIMapper* mIMapper;
+ buffer_handle_t mHandle = nullptr;
+
+ public:
+ explicit BufferHandle(AIMapper* mapper, native_handle_t* rawHandle) : mIMapper(mapper) {
+ EXPECT_EQ(AIMAPPER_ERROR_NONE, mIMapper->v5.importBuffer(rawHandle, &mHandle));
+ }
+
+ explicit BufferHandle(BufferHandle&& other) { *this = std::move(other); }
+
+ BufferHandle& operator=(BufferHandle&& other) noexcept {
+ reset();
+ mIMapper = other.mIMapper;
+ mHandle = other.mHandle;
+ other.mHandle = nullptr;
+ return *this;
+ }
+
+ ~BufferHandle() { reset(); }
+
+ constexpr explicit operator bool() const noexcept { return mHandle != nullptr; }
+
+ buffer_handle_t operator*() const noexcept { return mHandle; }
+
+ void reset() {
+ if (mHandle != nullptr) {
+ EXPECT_EQ(AIMAPPER_ERROR_NONE, mIMapper->v5.freeBuffer(mHandle));
+ mHandle = nullptr;
+ }
+ }
+};
+
+class BufferAllocation {
+ AIMapper* mIMapper;
+ native_handle_t* mRawHandle;
+ uint32_t mStride;
+ const BufferDescriptorInfo mInfo;
+
+ public:
+ BufferAllocation(const BufferAllocation&) = delete;
+ void operator=(const BufferAllocation&) = delete;
+
+ BufferAllocation(AIMapper* mapper, native_handle_t* handle, uint32_t stride,
+ const BufferDescriptorInfo& info)
+ : mIMapper(mapper), mRawHandle(handle), mStride(stride), mInfo(info) {}
+
+ ~BufferAllocation() {
+ if (mRawHandle == nullptr) return;
+
+ native_handle_close(mRawHandle);
+ native_handle_delete(mRawHandle);
+ }
+
+ uint32_t stride() const { return mStride; }
+ const BufferDescriptorInfo& info() const { return mInfo; }
+
+ BufferHandle import() { return BufferHandle{mIMapper, mRawHandle}; }
+
+ const native_handle_t* rawHandle() const { return mRawHandle; }
+};
+
+class GraphicsTestsBase {
+ private:
+ friend class BufferAllocation;
+ int32_t mIAllocatorVersion = 1;
+ std::shared_ptr<IAllocator> mAllocator;
+ AIMapper* mIMapper = nullptr;
+ AIMapper_loadIMapperFn mIMapperLoader;
+
+ protected:
+ void Initialize(std::shared_ptr<IAllocator> allocator) {
+ mAllocator = allocator;
+ ASSERT_NE(nullptr, mAllocator.get()) << "failed to get allocator service";
+ ASSERT_TRUE(mAllocator->getInterfaceVersion(&mIAllocatorVersion).isOk());
+ ASSERT_GE(mIAllocatorVersion, 2);
+ std::string mapperSuffix;
+ auto status = mAllocator->getIMapperLibrarySuffix(&mapperSuffix);
+ ASSERT_TRUE(status.isOk()) << "Failed to get IMapper library suffix";
+ std::string lib_name = "mapper." + mapperSuffix + ".so";
+ void* so = android_load_sphal_library(lib_name.c_str(), RTLD_LOCAL | RTLD_NOW);
+ ASSERT_NE(nullptr, so) << "Failed to load " << lib_name;
+ mIMapperLoader = (AIMapper_loadIMapperFn)dlsym(so, "AIMapper_loadIMapper");
+ ASSERT_NE(nullptr, mIMapperLoader) << "AIMapper_locaIMapper missing from " << lib_name;
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mIMapperLoader(&mIMapper));
+ ASSERT_NE(mIMapper, nullptr);
+ }
+
+ public:
+ AIMapper_loadIMapperFn getIMapperLoader() const { return mIMapperLoader; }
+
+ std::unique_ptr<BufferAllocation> allocate(const BufferDescriptorInfo& descriptorInfo) {
+ AllocationResult result;
+ ::ndk::ScopedAStatus status = mAllocator->allocate2(descriptorInfo, 1, &result);
+ if (!status.isOk()) {
+ status_t error = status.getExceptionCode();
+ if (error == EX_SERVICE_SPECIFIC) {
+ error = status.getServiceSpecificError();
+ EXPECT_NE(OK, error) << "Failed to set error properly";
+ } else {
+ EXPECT_EQ(OK, error) << "Allocation transport failure";
+ }
+ return nullptr;
+ } else {
+ return std::make_unique<BufferAllocation>(mIMapper, dupFromAidl(result.buffers[0]),
+ result.stride, descriptorInfo);
+ }
+ }
+
+ std::unique_ptr<BufferAllocation> allocateGeneric() {
+ return allocate({
+ .name = {"VTS_TEMP"},
+ .width = 64,
+ .height = 64,
+ .layerCount = 1,
+ .format = PixelFormat::RGBA_8888,
+ .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
+ .reservedSize = 0,
+ });
+ }
+
+ bool isSupported(const BufferDescriptorInfo& descriptorInfo) {
+ bool ret = false;
+ EXPECT_TRUE(mAllocator->isSupported(descriptorInfo, &ret).isOk());
+ return ret;
+ }
+
+ AIMapper* mapper() const { return mIMapper; }
+
+ template <StandardMetadataType T>
+ auto getStandardMetadata(buffer_handle_t bufferHandle)
+ -> decltype(StandardMetadata<T>::value::decode(nullptr, 0)) {
+ using Value = typename StandardMetadata<T>::value;
+ std::vector<uint8_t> buffer;
+ // Initial guess
+ buffer.resize(512);
+ int32_t sizeRequired = mapper()->v5.getStandardMetadata(
+ bufferHandle, static_cast<int64_t>(T), buffer.data(), buffer.size());
+ if (sizeRequired < 0) {
+ EXPECT_EQ(-AIMAPPER_ERROR_UNSUPPORTED, sizeRequired)
+ << "Received something other than UNSUPPORTED from valid getStandardMetadata "
+ "call";
+ return std::nullopt;
+ }
+ if (sizeRequired > buffer.size()) {
+ buffer.resize(sizeRequired);
+ sizeRequired = mapper()->v5.getStandardMetadata(bufferHandle, static_cast<int64_t>(T),
+ buffer.data(), buffer.size());
+ }
+ if (sizeRequired < 0 || sizeRequired >= buffer.size()) {
+ ADD_FAILURE() << "getStandardMetadata failed, received " << sizeRequired
+ << " with buffer size " << buffer.size();
+ // Generate a fail type
+ return std::nullopt;
+ }
+ return Value::decode(buffer.data(), sizeRequired);
+ }
+
+ template <StandardMetadataType T>
+ AIMapper_Error setStandardMetadata(buffer_handle_t bufferHandle,
+ const typename StandardMetadata<T>::value_type& value) {
+ using Value = typename StandardMetadata<T>::value;
+ int32_t sizeRequired = Value::encode(value, nullptr, 0);
+ if (sizeRequired < 0) {
+ EXPECT_GE(sizeRequired, 0) << "Failed to calculate required size";
+ return static_cast<AIMapper_Error>(-sizeRequired);
+ }
+ std::vector<uint8_t> buffer;
+ buffer.resize(sizeRequired);
+ sizeRequired = Value::encode(value, buffer.data(), buffer.size());
+ if (sizeRequired < 0 || sizeRequired > buffer.size()) {
+ ADD_FAILURE() << "Failed to encode with calculated size " << sizeRequired
+ << "; buffer size" << buffer.size();
+ return static_cast<AIMapper_Error>(-sizeRequired);
+ }
+ return mapper()->v5.setStandardMetadata(bufferHandle, static_cast<int64_t>(T),
+ buffer.data(), sizeRequired);
+ }
+
+ void verifyRGBA8888PlaneLayouts(const std::vector<PlaneLayout>& planeLayouts) {
+ ASSERT_EQ(1, planeLayouts.size());
+
+ const auto& planeLayout = planeLayouts.front();
+
+ ASSERT_EQ(4, planeLayout.components.size());
+
+ int64_t offsetInBitsR = -1;
+ int64_t offsetInBitsG = -1;
+ int64_t offsetInBitsB = -1;
+ int64_t offsetInBitsA = -1;
+
+ for (const auto& component : planeLayout.components) {
+ if (!gralloc4::isStandardPlaneLayoutComponentType(component.type)) {
+ continue;
+ }
+ EXPECT_EQ(8, component.sizeInBits);
+ if (component.type.value == gralloc4::PlaneLayoutComponentType_R.value) {
+ offsetInBitsR = component.offsetInBits;
+ }
+ if (component.type.value == gralloc4::PlaneLayoutComponentType_G.value) {
+ offsetInBitsG = component.offsetInBits;
+ }
+ if (component.type.value == gralloc4::PlaneLayoutComponentType_B.value) {
+ offsetInBitsB = component.offsetInBits;
+ }
+ if (component.type.value == gralloc4::PlaneLayoutComponentType_A.value) {
+ offsetInBitsA = component.offsetInBits;
+ }
+ }
+
+ EXPECT_EQ(0, offsetInBitsR);
+ EXPECT_EQ(8, offsetInBitsG);
+ EXPECT_EQ(16, offsetInBitsB);
+ EXPECT_EQ(24, offsetInBitsA);
+
+ EXPECT_EQ(0, planeLayout.offsetInBytes);
+ EXPECT_EQ(32, planeLayout.sampleIncrementInBits);
+ // Skip testing stride because any stride is valid
+ EXPECT_LE(planeLayout.widthInSamples * planeLayout.heightInSamples * 4,
+ planeLayout.totalSizeInBytes);
+ EXPECT_EQ(1, planeLayout.horizontalSubsampling);
+ EXPECT_EQ(1, planeLayout.verticalSubsampling);
+ }
+
+ void fillRGBA8888(uint8_t* data, uint32_t height, size_t strideInBytes, size_t widthInBytes) {
+ for (uint32_t y = 0; y < height; y++) {
+ memset(data, y, widthInBytes);
+ data += strideInBytes;
+ }
+ }
+
+ void verifyRGBA8888(const buffer_handle_t bufferHandle, const uint8_t* data, uint32_t height,
+ size_t strideInBytes, size_t widthInBytes) {
+ auto decodeResult = getStandardMetadata<StandardMetadataType::PLANE_LAYOUTS>(bufferHandle);
+ ASSERT_TRUE(decodeResult.has_value());
+ const auto& planeLayouts = *decodeResult;
+ ASSERT_TRUE(planeLayouts.size() > 0);
+
+ verifyRGBA8888PlaneLayouts(planeLayouts);
+
+ for (uint32_t y = 0; y < height; y++) {
+ for (size_t i = 0; i < widthInBytes; i++) {
+ EXPECT_EQ(static_cast<uint8_t>(y), data[i]);
+ }
+ data += strideInBytes;
+ }
+ }
+
+ void traverseYCbCrData(const android_ycbcr& yCbCr, int32_t width, int32_t height,
+ int64_t hSubsampling, int64_t vSubsampling,
+ std::function<void(uint8_t*, uint8_t)> traverseFuncion) {
+ auto yData = static_cast<uint8_t*>(yCbCr.y);
+ auto cbData = static_cast<uint8_t*>(yCbCr.cb);
+ auto crData = static_cast<uint8_t*>(yCbCr.cr);
+ auto yStride = yCbCr.ystride;
+ auto cStride = yCbCr.cstride;
+ auto chromaStep = yCbCr.chroma_step;
+
+ for (uint32_t y = 0; y < height; y++) {
+ for (uint32_t x = 0; x < width; x++) {
+ auto val = static_cast<uint8_t>(height * y + x);
+
+ traverseFuncion(yData + yStride * y + x, val);
+
+ if (y % vSubsampling == 0 && x % hSubsampling == 0) {
+ uint32_t subSampleX = x / hSubsampling;
+ uint32_t subSampleY = y / vSubsampling;
+ const auto subSampleOffset = cStride * subSampleY + chromaStep * subSampleX;
+ const auto subSampleVal =
+ static_cast<uint8_t>(height * subSampleY + subSampleX);
+
+ traverseFuncion(cbData + subSampleOffset, subSampleVal);
+ traverseFuncion(crData + subSampleOffset, subSampleVal + 1);
+ }
+ }
+ }
+ }
+
+ void fillYCbCrData(const android_ycbcr& yCbCr, int32_t width, int32_t height,
+ int64_t hSubsampling, int64_t vSubsampling) {
+ traverseYCbCrData(yCbCr, width, height, hSubsampling, vSubsampling,
+ [](auto address, auto fillingData) { *address = fillingData; });
+ }
+
+ void verifyYCbCrData(const android_ycbcr& yCbCr, int32_t width, int32_t height,
+ int64_t hSubsampling, int64_t vSubsampling) {
+ traverseYCbCrData(
+ yCbCr, width, height, hSubsampling, vSubsampling,
+ [](auto address, auto expectedData) { EXPECT_EQ(*address, expectedData); });
+ }
+
+ constexpr uint64_t bitsToBytes(int64_t bits) { return bits / 8; }
+ constexpr uint64_t bytesToBits(int64_t bytes) { return bytes * 8; }
+
+ void getAndroidYCbCr(buffer_handle_t bufferHandle, uint8_t* data, android_ycbcr* outYCbCr,
+ int64_t* hSubsampling, int64_t* vSubsampling) {
+ auto decodeResult = getStandardMetadata<StandardMetadataType::PLANE_LAYOUTS>(bufferHandle);
+ ASSERT_TRUE(decodeResult.has_value());
+ const auto& planeLayouts = *decodeResult;
+ ASSERT_TRUE(planeLayouts.size() > 0);
+
+ outYCbCr->y = nullptr;
+ outYCbCr->cb = nullptr;
+ outYCbCr->cr = nullptr;
+ outYCbCr->ystride = 0;
+ outYCbCr->cstride = 0;
+ outYCbCr->chroma_step = 0;
+
+ for (const auto& planeLayout : planeLayouts) {
+ for (const auto& planeLayoutComponent : planeLayout.components) {
+ if (!gralloc4::isStandardPlaneLayoutComponentType(planeLayoutComponent.type)) {
+ continue;
+ }
+ ASSERT_EQ(0, planeLayoutComponent.offsetInBits % 8);
+
+ uint8_t* tmpData = data + planeLayout.offsetInBytes +
+ bitsToBytes(planeLayoutComponent.offsetInBits);
+ uint64_t sampleIncrementInBytes;
+
+ auto type = static_cast<PlaneLayoutComponentType>(planeLayoutComponent.type.value);
+ switch (type) {
+ case PlaneLayoutComponentType::Y:
+ ASSERT_EQ(nullptr, outYCbCr->y);
+ ASSERT_EQ(8, planeLayoutComponent.sizeInBits);
+ ASSERT_EQ(8, planeLayout.sampleIncrementInBits);
+ outYCbCr->y = tmpData;
+ outYCbCr->ystride = planeLayout.strideInBytes;
+ break;
+
+ case PlaneLayoutComponentType::CB:
+ case PlaneLayoutComponentType::CR:
+ ASSERT_EQ(0, planeLayout.sampleIncrementInBits % 8);
+
+ sampleIncrementInBytes = planeLayout.sampleIncrementInBits / 8;
+ ASSERT_TRUE(sampleIncrementInBytes == 1 || sampleIncrementInBytes == 2);
+
+ if (outYCbCr->cstride == 0 && outYCbCr->chroma_step == 0) {
+ outYCbCr->cstride = planeLayout.strideInBytes;
+ outYCbCr->chroma_step = sampleIncrementInBytes;
+ } else {
+ ASSERT_EQ(outYCbCr->cstride, planeLayout.strideInBytes);
+ ASSERT_EQ(outYCbCr->chroma_step, sampleIncrementInBytes);
+ }
+
+ if (*hSubsampling == 0 && *vSubsampling == 0) {
+ *hSubsampling = planeLayout.horizontalSubsampling;
+ *vSubsampling = planeLayout.verticalSubsampling;
+ } else {
+ ASSERT_EQ(*hSubsampling, planeLayout.horizontalSubsampling);
+ ASSERT_EQ(*vSubsampling, planeLayout.verticalSubsampling);
+ }
+
+ if (type == PlaneLayoutComponentType::CB) {
+ ASSERT_EQ(nullptr, outYCbCr->cb);
+ outYCbCr->cb = tmpData;
+ } else {
+ ASSERT_EQ(nullptr, outYCbCr->cr);
+ outYCbCr->cr = tmpData;
+ }
+ break;
+ default:
+ break;
+ };
+ }
+ }
+
+ ASSERT_NE(nullptr, outYCbCr->y);
+ ASSERT_NE(nullptr, outYCbCr->cb);
+ ASSERT_NE(nullptr, outYCbCr->cr);
+ }
+
+ YCbCr getAndroidYCbCr_P010(const native_handle_t* bufferHandle, uint8_t* data) {
+ YCbCr yCbCr_P010;
+ auto decodeResult = getStandardMetadata<StandardMetadataType::PLANE_LAYOUTS>(bufferHandle);
+ if (!decodeResult.has_value()) {
+ ADD_FAILURE() << "failed to get plane layout";
+ return YCbCr{};
+ }
+ const auto& planeLayouts = *decodeResult;
+ EXPECT_EQ(2, planeLayouts.size());
+ EXPECT_EQ(1, planeLayouts[0].components.size());
+ EXPECT_EQ(2, planeLayouts[1].components.size());
+
+ yCbCr_P010.yCbCr.y = nullptr;
+ yCbCr_P010.yCbCr.cb = nullptr;
+ yCbCr_P010.yCbCr.cr = nullptr;
+ yCbCr_P010.yCbCr.ystride = 0;
+ yCbCr_P010.yCbCr.cstride = 0;
+ yCbCr_P010.yCbCr.chroma_step = 0;
+ int64_t cb_offset = 0;
+ int64_t cr_offset = 0;
+
+ for (const auto& planeLayout : planeLayouts) {
+ for (const auto& planeLayoutComponent : planeLayout.components) {
+ if (!gralloc4::isStandardPlaneLayoutComponentType(planeLayoutComponent.type)) {
+ continue;
+ }
+
+ uint8_t* tmpData = data + planeLayout.offsetInBytes +
+ bitsToBytes(planeLayoutComponent.offsetInBits);
+ uint64_t sampleIncrementInBytes = 0;
+ auto type = static_cast<PlaneLayoutComponentType>(planeLayoutComponent.type.value);
+ switch (type) {
+ case PlaneLayoutComponentType::Y:
+ // For specs refer:
+ // https://docs.microsoft.com/en-us/windows/win32/medfound/10-bit-and-16-bit-yuv-video-formats
+ EXPECT_EQ(6, planeLayoutComponent.offsetInBits);
+ EXPECT_EQ(nullptr, yCbCr_P010.yCbCr.y);
+ EXPECT_EQ(10, planeLayoutComponent.sizeInBits);
+ EXPECT_EQ(16, planeLayout.sampleIncrementInBits);
+
+ yCbCr_P010.yCbCr.y = tmpData;
+ yCbCr_P010.yCbCr.ystride = planeLayout.strideInBytes;
+ break;
+
+ case PlaneLayoutComponentType::CB:
+ case PlaneLayoutComponentType::CR:
+ sampleIncrementInBytes = bitsToBytes(planeLayout.sampleIncrementInBits);
+ EXPECT_EQ(4, sampleIncrementInBytes);
+
+ if (yCbCr_P010.yCbCr.cstride == 0 && yCbCr_P010.yCbCr.chroma_step == 0) {
+ yCbCr_P010.yCbCr.cstride = planeLayout.strideInBytes;
+ yCbCr_P010.yCbCr.chroma_step = sampleIncrementInBytes;
+ } else {
+ EXPECT_EQ(yCbCr_P010.yCbCr.cstride, planeLayout.strideInBytes);
+ EXPECT_EQ(yCbCr_P010.yCbCr.chroma_step, sampleIncrementInBytes);
+ }
+
+ if (yCbCr_P010.horizontalSubSampling == 0 &&
+ yCbCr_P010.verticalSubSampling == 0) {
+ yCbCr_P010.horizontalSubSampling = planeLayout.horizontalSubsampling;
+ yCbCr_P010.verticalSubSampling = planeLayout.verticalSubsampling;
+ } else {
+ EXPECT_EQ(yCbCr_P010.horizontalSubSampling,
+ planeLayout.horizontalSubsampling);
+ EXPECT_EQ(yCbCr_P010.verticalSubSampling,
+ planeLayout.verticalSubsampling);
+ }
+
+ if (type == PlaneLayoutComponentType::CB) {
+ EXPECT_EQ(nullptr, yCbCr_P010.yCbCr.cb);
+ yCbCr_P010.yCbCr.cb = tmpData;
+ cb_offset = planeLayoutComponent.offsetInBits;
+ } else {
+ EXPECT_EQ(nullptr, yCbCr_P010.yCbCr.cr);
+ yCbCr_P010.yCbCr.cr = tmpData;
+ cr_offset = planeLayoutComponent.offsetInBits;
+ }
+ break;
+ default:
+ break;
+ };
+ }
+ }
+
+ EXPECT_EQ(cb_offset + bytesToBits(2), cr_offset);
+ EXPECT_NE(nullptr, yCbCr_P010.yCbCr.y);
+ EXPECT_NE(nullptr, yCbCr_P010.yCbCr.cb);
+ EXPECT_NE(nullptr, yCbCr_P010.yCbCr.cr);
+ return yCbCr_P010;
+ }
+};
+
+class GraphicsMapperStableCTests
+ : public GraphicsTestsBase,
+ public ::testing::TestWithParam<std::tuple<std::string, std::shared_ptr<IAllocator>>> {
+ public:
+ void SetUp() override { Initialize(std::get<1>(GetParam())); }
+
+ void TearDown() override {}
+};
+
+TEST_P(GraphicsMapperStableCTests, AllV5CallbacksDefined) {
+ ASSERT_GE(mapper()->version, AIMAPPER_VERSION_5);
+
+ EXPECT_TRUE(mapper()->v5.importBuffer);
+ EXPECT_TRUE(mapper()->v5.freeBuffer);
+ EXPECT_TRUE(mapper()->v5.getTransportSize);
+ EXPECT_TRUE(mapper()->v5.lock);
+ EXPECT_TRUE(mapper()->v5.unlock);
+ EXPECT_TRUE(mapper()->v5.flushLockedBuffer);
+ EXPECT_TRUE(mapper()->v5.rereadLockedBuffer);
+ EXPECT_TRUE(mapper()->v5.getMetadata);
+ EXPECT_TRUE(mapper()->v5.getStandardMetadata);
+ EXPECT_TRUE(mapper()->v5.setMetadata);
+ EXPECT_TRUE(mapper()->v5.setStandardMetadata);
+ EXPECT_TRUE(mapper()->v5.listSupportedMetadataTypes);
+ EXPECT_TRUE(mapper()->v5.dumpBuffer);
+ EXPECT_TRUE(mapper()->v5.getReservedRegion);
+}
+
+TEST_P(GraphicsMapperStableCTests, DualLoadIsIdentical) {
+ ASSERT_GE(mapper()->version, AIMAPPER_VERSION_5);
+ AIMapper* secondMapper;
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, getIMapperLoader()(&secondMapper));
+
+ EXPECT_EQ(secondMapper->v5.importBuffer, mapper()->v5.importBuffer);
+ EXPECT_EQ(secondMapper->v5.freeBuffer, mapper()->v5.freeBuffer);
+ EXPECT_EQ(secondMapper->v5.getTransportSize, mapper()->v5.getTransportSize);
+ EXPECT_EQ(secondMapper->v5.lock, mapper()->v5.lock);
+ EXPECT_EQ(secondMapper->v5.unlock, mapper()->v5.unlock);
+ EXPECT_EQ(secondMapper->v5.flushLockedBuffer, mapper()->v5.flushLockedBuffer);
+ EXPECT_EQ(secondMapper->v5.rereadLockedBuffer, mapper()->v5.rereadLockedBuffer);
+ EXPECT_EQ(secondMapper->v5.getMetadata, mapper()->v5.getMetadata);
+ EXPECT_EQ(secondMapper->v5.getStandardMetadata, mapper()->v5.getStandardMetadata);
+ EXPECT_EQ(secondMapper->v5.setMetadata, mapper()->v5.setMetadata);
+ EXPECT_EQ(secondMapper->v5.setStandardMetadata, mapper()->v5.setStandardMetadata);
+ EXPECT_EQ(secondMapper->v5.listSupportedMetadataTypes, mapper()->v5.listSupportedMetadataTypes);
+ EXPECT_EQ(secondMapper->v5.dumpBuffer, mapper()->v5.dumpBuffer);
+ EXPECT_EQ(secondMapper->v5.getReservedRegion, mapper()->v5.getReservedRegion);
+}
+
+TEST_P(GraphicsMapperStableCTests, CanAllocate) {
+ auto buffer = allocate({
+ .name = {"VTS_TEMP"},
+ .width = 64,
+ .height = 64,
+ .layerCount = 1,
+ .format = PixelFormat::RGBA_8888,
+ .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
+ .reservedSize = 0,
+ });
+ ASSERT_NE(nullptr, buffer.get());
+ EXPECT_GE(buffer->stride(), 64);
+}
+
+TEST_P(GraphicsMapperStableCTests, ImportFreeBuffer) {
+ auto buffer = allocate({
+ .name = {"VTS_TEMP"},
+ .width = 64,
+ .height = 64,
+ .layerCount = 1,
+ .format = PixelFormat::RGBA_8888,
+ .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
+ .reservedSize = 0,
+ });
+ ASSERT_NE(nullptr, buffer.get());
+ EXPECT_GE(buffer->stride(), 64);
+
+ {
+ auto import1 = buffer->import();
+ auto import2 = buffer->import();
+ EXPECT_TRUE(import1);
+ EXPECT_TRUE(import2);
+ EXPECT_NE(*import1, *import2);
+ }
+}
+
+/**
+ * Test IMapper::importBuffer and IMapper::freeBuffer cross mapper instances.
+ */
+TEST_P(GraphicsMapperStableCTests, ImportFreeBufferSingleton) {
+ auto buffer = allocate({
+ .name = {"VTS_TEMP"},
+ .width = 64,
+ .height = 64,
+ .layerCount = 1,
+ .format = PixelFormat::RGBA_8888,
+ .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
+ .reservedSize = 0,
+ });
+ ASSERT_NE(nullptr, buffer.get());
+ EXPECT_GE(buffer->stride(), 64);
+
+ buffer_handle_t bufferHandle = nullptr;
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.importBuffer(buffer->rawHandle(), &bufferHandle));
+ ASSERT_NE(nullptr, bufferHandle);
+
+ AIMapper* secondMapper;
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, getIMapperLoader()(&secondMapper));
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, secondMapper->v5.freeBuffer(bufferHandle));
+}
+
+/**
+ * Test IMapper::importBuffer with invalid buffers.
+ */
+TEST_P(GraphicsMapperStableCTests, ImportBufferNegative) {
+ native_handle_t* invalidHandle = nullptr;
+ buffer_handle_t bufferHandle = nullptr;
+ EXPECT_EQ(AIMAPPER_ERROR_BAD_BUFFER, mapper()->v5.importBuffer(invalidHandle, &bufferHandle))
+ << "importBuffer with nullptr did not fail with BAD_BUFFER";
+
+ invalidHandle = native_handle_create(0, 0);
+ EXPECT_EQ(AIMAPPER_ERROR_BAD_BUFFER, mapper()->v5.importBuffer(invalidHandle, &bufferHandle))
+ << "importBuffer with invalid handle did not fail with BAD_BUFFER";
+ native_handle_delete(invalidHandle);
+}
+
+/**
+ * Test IMapper::freeBuffer with invalid buffers.
+ */
+TEST_P(GraphicsMapperStableCTests, FreeBufferNegative) {
+ native_handle_t* bufferHandle = nullptr;
+ EXPECT_EQ(AIMAPPER_ERROR_BAD_BUFFER, mapper()->v5.freeBuffer(bufferHandle))
+ << "freeBuffer with nullptr did not fail with BAD_BUFFER";
+
+ bufferHandle = native_handle_create(0, 0);
+ EXPECT_EQ(AIMAPPER_ERROR_BAD_BUFFER, mapper()->v5.freeBuffer(bufferHandle))
+ << "freeBuffer with invalid handle did not fail with BAD_BUFFER";
+ native_handle_delete(bufferHandle);
+
+ auto buffer = allocateGeneric();
+ EXPECT_EQ(AIMAPPER_ERROR_BAD_BUFFER, mapper()->v5.freeBuffer(buffer->rawHandle()))
+ << "freeBuffer with un-imported handle did not fail with BAD_BUFFER";
+}
+
+/**
+ * Test IMapper::lock and IMapper::unlock.
+ */
+TEST_P(GraphicsMapperStableCTests, LockUnlockBasic) {
+ constexpr auto usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN;
+ auto buffer = allocate({
+ .name = {"VTS_TEMP"},
+ .width = 64,
+ .height = 64,
+ .layerCount = 1,
+ .format = PixelFormat::RGBA_8888,
+ .usage = usage,
+ .reservedSize = 0,
+ });
+ ASSERT_NE(nullptr, buffer.get());
+
+ // lock buffer for writing
+ const auto& info = buffer->info();
+ const auto stride = buffer->stride();
+ const ARect region{0, 0, info.width, info.height};
+ auto handle = buffer->import();
+ uint8_t* data = nullptr;
+ ASSERT_EQ(AIMAPPER_ERROR_NONE,
+ mapper()->v5.lock(*handle, static_cast<int64_t>(usage), region, -1, (void**)&data));
+
+ // RGBA_8888
+ fillRGBA8888(data, info.height, stride * 4, info.width * 4);
+
+ int releaseFence = -1;
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*handle, &releaseFence));
+
+ // lock again for reading
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.lock(*handle, static_cast<int64_t>(usage), region,
+ releaseFence, (void**)&data));
+ releaseFence = -1;
+
+ ASSERT_NO_FATAL_FAILURE(verifyRGBA8888(*handle, data, info.height, stride * 4, info.width * 4));
+
+ releaseFence = -1;
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*handle, &releaseFence));
+ if (releaseFence != -1) {
+ close(releaseFence);
+ }
+}
+
+/**
+ * Test multiple operations associated with different color formats
+ */
+TEST_P(GraphicsMapperStableCTests, Lock_YCRCB_420_SP) {
+ BufferDescriptorInfo info{
+ .name = {"VTS_TEMP"},
+ .width = 64,
+ .height = 64,
+ .layerCount = 1,
+ .format = PixelFormat::YCRCB_420_SP,
+ .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
+ .reservedSize = 0,
+ };
+ auto buffer = allocate(info);
+ if (!buffer) {
+ ASSERT_FALSE(isSupported(info));
+ GTEST_SUCCEED() << "YCRCB_420_SP format is unsupported";
+ return;
+ }
+
+ // lock buffer for writing
+ const ARect region{0, 0, info.width, info.height};
+ auto handle = buffer->import();
+ uint8_t* data = nullptr;
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.lock(*handle, static_cast<int64_t>(info.usage),
+ region, -1, (void**)&data));
+
+ android_ycbcr yCbCr;
+ int64_t hSubsampling = 0;
+ int64_t vSubsampling = 0;
+ ASSERT_NO_FATAL_FAILURE(getAndroidYCbCr(*handle, data, &yCbCr, &hSubsampling, &vSubsampling));
+
+ constexpr uint32_t kCbCrSubSampleFactor = 2;
+ ASSERT_EQ(kCbCrSubSampleFactor, hSubsampling);
+ ASSERT_EQ(kCbCrSubSampleFactor, vSubsampling);
+
+ auto cbData = static_cast<uint8_t*>(yCbCr.cb);
+ auto crData = static_cast<uint8_t*>(yCbCr.cr);
+ ASSERT_EQ(crData + 1, cbData);
+ ASSERT_EQ(2, yCbCr.chroma_step);
+
+ fillYCbCrData(yCbCr, info.width, info.height, hSubsampling, vSubsampling);
+
+ int releaseFence = -1;
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*handle, &releaseFence));
+
+ // lock again for reading
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.lock(*handle, static_cast<int64_t>(info.usage),
+ region, releaseFence, (void**)&data));
+ releaseFence = -1;
+
+ ASSERT_NO_FATAL_FAILURE(getAndroidYCbCr(*handle, data, &yCbCr, &hSubsampling, &vSubsampling));
+
+ verifyYCbCrData(yCbCr, info.width, info.height, hSubsampling, vSubsampling);
+
+ releaseFence = -1;
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*handle, &releaseFence));
+ if (releaseFence != -1) {
+ close(releaseFence);
+ }
+}
+
+TEST_P(GraphicsMapperStableCTests, YV12SubsampleMetadata) {
+ BufferDescriptorInfo info{
+ .name = {"VTS_TEMP"},
+ .width = 64,
+ .height = 64,
+ .layerCount = 1,
+ .format = PixelFormat::YV12,
+ .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
+ .reservedSize = 0,
+ };
+ auto buffer = allocate(info);
+ ASSERT_NE(nullptr, buffer.get());
+
+ // lock buffer for writing
+ const ARect region{0, 0, info.width, info.height};
+ auto handle = buffer->import();
+ uint8_t* data = nullptr;
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.lock(*handle, static_cast<int64_t>(info.usage),
+ region, -1, (void**)&data));
+
+ auto decodeResult = getStandardMetadata<StandardMetadataType::PLANE_LAYOUTS>(*handle);
+ ASSERT_TRUE(decodeResult.has_value());
+ const auto& planeLayouts = *decodeResult;
+
+ ASSERT_EQ(3, planeLayouts.size());
+
+ auto yPlane = planeLayouts[0];
+ auto crPlane = planeLayouts[1];
+ auto cbPlane = planeLayouts[2];
+
+ constexpr uint32_t kCbCrSubSampleFactor = 2;
+ EXPECT_EQ(kCbCrSubSampleFactor, crPlane.horizontalSubsampling);
+ EXPECT_EQ(kCbCrSubSampleFactor, crPlane.verticalSubsampling);
+
+ EXPECT_EQ(kCbCrSubSampleFactor, cbPlane.horizontalSubsampling);
+ EXPECT_EQ(kCbCrSubSampleFactor, cbPlane.verticalSubsampling);
+
+ const long chromaSampleWidth = info.width / kCbCrSubSampleFactor;
+ const long chromaSampleHeight = info.height / kCbCrSubSampleFactor;
+
+ EXPECT_EQ(info.width, yPlane.widthInSamples);
+ EXPECT_EQ(info.height, yPlane.heightInSamples);
+
+ EXPECT_EQ(chromaSampleWidth, crPlane.widthInSamples);
+ EXPECT_EQ(chromaSampleHeight, crPlane.heightInSamples);
+
+ EXPECT_EQ(chromaSampleWidth, cbPlane.widthInSamples);
+ EXPECT_EQ(chromaSampleHeight, cbPlane.heightInSamples);
+
+ EXPECT_LE(crPlane.widthInSamples, crPlane.strideInBytes);
+ EXPECT_LE(cbPlane.widthInSamples, cbPlane.strideInBytes);
+
+ int releaseFence = -1;
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*handle, &releaseFence));
+ if (releaseFence != -1) {
+ close(releaseFence);
+ }
+}
+
+TEST_P(GraphicsMapperStableCTests, Lock_YV12) {
+ BufferDescriptorInfo info{
+ .name = {"VTS_TEMP"},
+ .width = 64,
+ .height = 64,
+ .layerCount = 1,
+ .format = PixelFormat::YV12,
+ .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
+ .reservedSize = 0,
+ };
+ auto buffer = allocate(info);
+ ASSERT_NE(nullptr, buffer.get());
+
+ // lock buffer for writing
+ const ARect region{0, 0, info.width, info.height};
+ auto handle = buffer->import();
+ uint8_t* data = nullptr;
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.lock(*handle, static_cast<int64_t>(info.usage),
+ region, -1, (void**)&data));
+
+ android_ycbcr yCbCr;
+ int64_t hSubsampling = 0;
+ int64_t vSubsampling = 0;
+ ASSERT_NO_FATAL_FAILURE(getAndroidYCbCr(*handle, data, &yCbCr, &hSubsampling, &vSubsampling));
+
+ constexpr uint32_t kCbCrSubSampleFactor = 2;
+ ASSERT_EQ(kCbCrSubSampleFactor, hSubsampling);
+ ASSERT_EQ(kCbCrSubSampleFactor, vSubsampling);
+
+ auto cbData = static_cast<uint8_t*>(yCbCr.cb);
+ auto crData = static_cast<uint8_t*>(yCbCr.cr);
+ ASSERT_EQ(crData + yCbCr.cstride * info.height / vSubsampling, cbData);
+ ASSERT_EQ(1, yCbCr.chroma_step);
+
+ fillYCbCrData(yCbCr, info.width, info.height, hSubsampling, vSubsampling);
+
+ int releaseFence = -1;
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*handle, &releaseFence));
+
+ // lock again for reading
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.lock(*handle, static_cast<int64_t>(info.usage),
+ region, releaseFence, (void**)&data));
+ releaseFence = -1;
+
+ ASSERT_NO_FATAL_FAILURE(getAndroidYCbCr(*handle, data, &yCbCr, &hSubsampling, &vSubsampling));
+
+ verifyYCbCrData(yCbCr, info.width, info.height, hSubsampling, vSubsampling);
+
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*handle, &releaseFence));
+ if (releaseFence != -1) {
+ close(releaseFence);
+ }
+}
+
+TEST_P(GraphicsMapperStableCTests, Lock_YCBCR_420_888) {
+ BufferDescriptorInfo info{
+ .name = {"VTS_TEMP"},
+ .width = 64,
+ .height = 64,
+ .layerCount = 1,
+ .format = PixelFormat::YCBCR_420_888,
+ .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
+ .reservedSize = 0,
+ };
+ auto buffer = allocate(info);
+ ASSERT_NE(nullptr, buffer.get());
+
+ // lock buffer for writing
+ const ARect region{0, 0, info.width, info.height};
+ auto handle = buffer->import();
+ uint8_t* data = nullptr;
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.lock(*handle, static_cast<int64_t>(info.usage),
+ region, -1, (void**)&data));
+
+ android_ycbcr yCbCr;
+ int64_t hSubsampling = 0;
+ int64_t vSubsampling = 0;
+ ASSERT_NO_FATAL_FAILURE(getAndroidYCbCr(*handle, data, &yCbCr, &hSubsampling, &vSubsampling));
+
+ constexpr uint32_t kCbCrSubSampleFactor = 2;
+ ASSERT_EQ(kCbCrSubSampleFactor, hSubsampling);
+ ASSERT_EQ(kCbCrSubSampleFactor, vSubsampling);
+
+ fillYCbCrData(yCbCr, info.width, info.height, hSubsampling, vSubsampling);
+
+ int releaseFence = -1;
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*handle, &releaseFence));
+
+ // lock again for reading
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.lock(*handle, static_cast<int64_t>(info.usage),
+ region, releaseFence, (void**)&data));
+ releaseFence = -1;
+
+ ASSERT_NO_FATAL_FAILURE(getAndroidYCbCr(*handle, data, &yCbCr, &hSubsampling, &vSubsampling));
+
+ verifyYCbCrData(yCbCr, info.width, info.height, hSubsampling, vSubsampling);
+
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*handle, &releaseFence));
+ if (releaseFence != -1) {
+ close(releaseFence);
+ }
+}
+
+TEST_P(GraphicsMapperStableCTests, Lock_RAW10) {
+ BufferDescriptorInfo info{
+ .name = {"VTS_TEMP"},
+ .width = 64,
+ .height = 64,
+ .layerCount = 1,
+ .format = PixelFormat::RAW10,
+ .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
+ .reservedSize = 0,
+ };
+ auto buffer = allocate(info);
+ if (!buffer) {
+ ASSERT_FALSE(isSupported(info));
+ GTEST_SUCCEED() << "RAW10 format is unsupported";
+ return;
+ }
+
+ // lock buffer for writing
+ const ARect region{0, 0, info.width, info.height};
+ auto handle = buffer->import();
+ uint8_t* data = nullptr;
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.lock(*handle, static_cast<int64_t>(info.usage),
+ region, -1, (void**)&data));
+
+ auto decodeResult = getStandardMetadata<StandardMetadataType::PLANE_LAYOUTS>(*handle);
+ ASSERT_TRUE(decodeResult.has_value());
+ const auto& planeLayouts = *decodeResult;
+
+ ASSERT_EQ(1, planeLayouts.size());
+ auto planeLayout = planeLayouts[0];
+
+ EXPECT_EQ(0, planeLayout.sampleIncrementInBits);
+ EXPECT_EQ(1, planeLayout.horizontalSubsampling);
+ EXPECT_EQ(1, planeLayout.verticalSubsampling);
+
+ ASSERT_EQ(1, planeLayout.components.size());
+ auto planeLayoutComponent = planeLayout.components[0];
+
+ EXPECT_EQ(PlaneLayoutComponentType::RAW,
+ static_cast<PlaneLayoutComponentType>(planeLayoutComponent.type.value));
+ EXPECT_EQ(0, planeLayoutComponent.offsetInBits % 8);
+ EXPECT_EQ(-1, planeLayoutComponent.sizeInBits);
+
+ int releaseFence = -1;
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*handle, &releaseFence));
+ if (releaseFence != -1) {
+ close(releaseFence);
+ }
+}
+
+TEST_P(GraphicsMapperStableCTests, Lock_RAW12) {
+ BufferDescriptorInfo info{
+ .name = {"VTS_TEMP"},
+ .width = 64,
+ .height = 64,
+ .layerCount = 1,
+ .format = PixelFormat::RAW12,
+ .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
+ .reservedSize = 0,
+ };
+ auto buffer = allocate(info);
+ if (!buffer) {
+ ASSERT_FALSE(isSupported(info));
+ GTEST_SUCCEED() << "RAW12 format is unsupported";
+ return;
+ }
+
+ // lock buffer for writing
+ const ARect region{0, 0, info.width, info.height};
+ auto handle = buffer->import();
+ uint8_t* data = nullptr;
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.lock(*handle, static_cast<int64_t>(info.usage),
+ region, -1, (void**)&data));
+
+ auto decodeResult = getStandardMetadata<StandardMetadataType::PLANE_LAYOUTS>(*handle);
+ ASSERT_TRUE(decodeResult.has_value());
+ const auto& planeLayouts = *decodeResult;
+
+ ASSERT_EQ(1, planeLayouts.size());
+ auto planeLayout = planeLayouts[0];
+
+ EXPECT_EQ(0, planeLayout.sampleIncrementInBits);
+ EXPECT_EQ(1, planeLayout.horizontalSubsampling);
+ EXPECT_EQ(1, planeLayout.verticalSubsampling);
+
+ ASSERT_EQ(1, planeLayout.components.size());
+ auto planeLayoutComponent = planeLayout.components[0];
+
+ EXPECT_EQ(PlaneLayoutComponentType::RAW,
+ static_cast<PlaneLayoutComponentType>(planeLayoutComponent.type.value));
+ EXPECT_EQ(0, planeLayoutComponent.offsetInBits % 8);
+ EXPECT_EQ(-1, planeLayoutComponent.sizeInBits);
+
+ int releaseFence = -1;
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*handle, &releaseFence));
+ if (releaseFence != -1) {
+ close(releaseFence);
+ }
+}
+
+TEST_P(GraphicsMapperStableCTests, Lock_YCBCR_P010) {
+ BufferDescriptorInfo info{
+ .name = {"VTS_TEMP"},
+ .width = 64,
+ .height = 64,
+ .layerCount = 1,
+ .format = PixelFormat::YCBCR_P010,
+ .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
+ .reservedSize = 0,
+ };
+ auto buffer = allocate(info);
+ if (!buffer) {
+ ASSERT_FALSE(isSupported(info));
+ GTEST_SUCCEED() << "YCBCR_P010 format is unsupported";
+ return;
+ }
+
+ // lock buffer for writing
+ const ARect region{0, 0, info.width, info.height};
+ auto handle = buffer->import();
+ uint8_t* data = nullptr;
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.lock(*handle, static_cast<int64_t>(info.usage),
+ region, -1, (void**)&data));
+
+ YCbCr yCbCr;
+ ASSERT_NO_FATAL_FAILURE(yCbCr = getAndroidYCbCr_P010(*handle, data));
+
+ constexpr uint32_t kCbCrSubSampleFactor = 2;
+ ASSERT_EQ(kCbCrSubSampleFactor, yCbCr.horizontalSubSampling);
+ ASSERT_EQ(kCbCrSubSampleFactor, yCbCr.verticalSubSampling);
+
+ ASSERT_EQ(0, info.height % 2);
+
+ // fill the data
+ fillYCbCrData(yCbCr.yCbCr, info.width, info.height, yCbCr.horizontalSubSampling,
+ yCbCr.verticalSubSampling);
+ // verify the YCbCr data
+ verifyYCbCrData(yCbCr.yCbCr, info.width, info.height, yCbCr.horizontalSubSampling,
+ yCbCr.verticalSubSampling);
+
+ int releaseFence = -1;
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*handle, &releaseFence));
+ if (releaseFence != -1) {
+ close(releaseFence);
+ }
+}
+
+TEST_P(GraphicsMapperStableCTests, LockBadAccessRegion) {
+ auto buffer = allocateGeneric();
+ ASSERT_NE(nullptr, buffer);
+ const auto& info = buffer->info();
+
+ // lock buffer for writing
+ const ARect region{0, 0, info.width * 2, info.height * 2};
+ auto handle = buffer->import();
+ uint8_t* data = nullptr;
+ EXPECT_EQ(AIMAPPER_ERROR_BAD_VALUE, mapper()->v5.lock(*handle, static_cast<int64_t>(info.usage),
+ region, -1, (void**)&data));
+}
+
+TEST_P(GraphicsMapperStableCTests, UnlockNegative) {
+ native_handle_t* invalidHandle = nullptr;
+ int releaseFence = -1;
+ EXPECT_EQ(AIMAPPER_ERROR_BAD_BUFFER, mapper()->v5.unlock(invalidHandle, &releaseFence))
+ << "unlock with nullptr did not fail with BAD_BUFFER";
+
+ invalidHandle = native_handle_create(0, 0);
+ EXPECT_EQ(AIMAPPER_ERROR_BAD_BUFFER, mapper()->v5.unlock(invalidHandle, &releaseFence))
+ << "unlock with invalid handle did not fail with BAD_BUFFER";
+ native_handle_delete(invalidHandle);
+
+ auto buffer = allocateGeneric();
+ EXPECT_EQ(AIMAPPER_ERROR_BAD_BUFFER, mapper()->v5.unlock(buffer->rawHandle(), &releaseFence))
+ << "unlock with un-imported handle did not fail with BAD_BUFFER";
+}
+
+TEST_P(GraphicsMapperStableCTests, UnlockNotImported) {
+ int releaseFence = -1;
+ auto buffer = allocateGeneric();
+ ASSERT_TRUE(buffer);
+ EXPECT_EQ(AIMAPPER_ERROR_BAD_BUFFER, mapper()->v5.unlock(buffer->rawHandle(), &releaseFence))
+ << "unlock with un-imported handle did not fail with BAD_BUFFER";
+}
+
+TEST_P(GraphicsMapperStableCTests, UnlockNotLocked) {
+ int releaseFence = -1;
+ auto buffer = allocateGeneric();
+ ASSERT_TRUE(buffer);
+ auto bufferHandle = buffer->import();
+ ASSERT_TRUE(bufferHandle);
+ EXPECT_EQ(AIMAPPER_ERROR_BAD_BUFFER, mapper()->v5.unlock(*bufferHandle, &releaseFence))
+ << "unlock with unlocked handle did not fail with BAD_BUFFER";
+}
+
+TEST_P(GraphicsMapperStableCTests, LockUnlockNested) {
+ auto buffer = allocateGeneric();
+ ASSERT_TRUE(buffer);
+ auto bufferHandle = buffer->import();
+ ASSERT_TRUE(bufferHandle);
+ const ARect region{0, 0, buffer->info().width, buffer->info().height};
+ auto usage = static_cast<int64_t>(buffer->info().usage);
+ auto handle = buffer->import();
+ uint8_t* data = nullptr;
+ EXPECT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.lock(*handle, usage, region, -1, (void**)&data));
+ EXPECT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.lock(*handle, usage, region, -1, (void**)&data))
+ << "Second lock failed";
+ int releaseFence = -1;
+ EXPECT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*handle, &releaseFence));
+ if (releaseFence != -1) {
+ close(releaseFence);
+ releaseFence = -1;
+ }
+ EXPECT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*handle, &releaseFence))
+ << "Second unlock failed";
+ if (releaseFence != -1) {
+ close(releaseFence);
+ releaseFence = -1;
+ }
+ EXPECT_EQ(AIMAPPER_ERROR_BAD_BUFFER, mapper()->v5.unlock(*handle, &releaseFence))
+ << "Third, unmatched, unlock should have failed with BAD_BUFFER";
+}
+
+TEST_P(GraphicsMapperStableCTests, FlushRereadBasic) {
+ auto buffer = allocateGeneric();
+ ASSERT_TRUE(buffer);
+ auto bufferHandle = buffer->import();
+ ASSERT_TRUE(bufferHandle);
+ const auto& info = buffer->info();
+ const auto stride = buffer->stride();
+ const ARect region{0, 0, buffer->info().width, buffer->info().height};
+
+ auto writeHandle = buffer->import();
+ auto readHandle = buffer->import();
+ ASSERT_TRUE(writeHandle && readHandle);
+
+ // lock buffer for writing
+
+ uint8_t* writeData;
+ EXPECT_EQ(AIMAPPER_ERROR_NONE,
+ mapper()->v5.lock(*writeHandle, static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN),
+ region, -1, (void**)&writeData));
+
+ uint8_t* readData;
+ EXPECT_EQ(AIMAPPER_ERROR_NONE,
+ mapper()->v5.lock(*readHandle, static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN),
+ region, -1, (void**)&readData));
+
+ fillRGBA8888(writeData, info.height, stride * 4, info.width * 4);
+
+ EXPECT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.flushLockedBuffer(*writeHandle));
+ EXPECT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.rereadLockedBuffer(*readHandle));
+
+ ASSERT_NO_FATAL_FAILURE(
+ verifyRGBA8888(*readHandle, readData, info.height, stride * 4, info.width * 4));
+
+ int releaseFence = -1;
+
+ EXPECT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*readHandle, &releaseFence));
+ if (releaseFence != -1) {
+ close(releaseFence);
+ releaseFence = -1;
+ }
+
+ EXPECT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*writeHandle, &releaseFence));
+ if (releaseFence != -1) {
+ close(releaseFence);
+ releaseFence = -1;
+ }
+}
+
+TEST_P(GraphicsMapperStableCTests, FlushLockedBufferBadBuffer) {
+ // Amazingly this is enough to make the compiler happy even though flushLockedBuffer
+ // is _Nonnull :shrug:
+ buffer_handle_t badBuffer = nullptr;
+ EXPECT_EQ(AIMAPPER_ERROR_BAD_BUFFER, mapper()->v5.flushLockedBuffer(badBuffer));
+}
+
+TEST_P(GraphicsMapperStableCTests, RereadLockedBufferBadBuffer) {
+ buffer_handle_t badBuffer = nullptr;
+ EXPECT_EQ(AIMAPPER_ERROR_BAD_BUFFER, mapper()->v5.rereadLockedBuffer(badBuffer));
+}
+
+TEST_P(GraphicsMapperStableCTests, GetBufferId) {
+ auto buffer = allocateGeneric();
+ auto bufferHandle = buffer->import();
+ auto bufferId = getStandardMetadata<StandardMetadataType::BUFFER_ID>(*bufferHandle);
+ ASSERT_TRUE(bufferId.has_value());
+
+ auto buffer2 = allocateGeneric();
+ auto bufferHandle2 = buffer2->import();
+ auto bufferId2 = getStandardMetadata<StandardMetadataType::BUFFER_ID>(*bufferHandle2);
+ ASSERT_TRUE(bufferId2.has_value());
+
+ EXPECT_NE(*bufferId, *bufferId2);
+}
+
+TEST_P(GraphicsMapperStableCTests, GetName) {
+ auto buffer = allocate({
+ .name = {"Hello, World!"},
+ .width = 64,
+ .height = 64,
+ .layerCount = 1,
+ .format = PixelFormat::RGBA_8888,
+ .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
+ .reservedSize = 0,
+ });
+ auto bufferHandle = buffer->import();
+ auto name = getStandardMetadata<StandardMetadataType::NAME>(*bufferHandle);
+ ASSERT_TRUE(name.has_value());
+ EXPECT_EQ(*name, "Hello, World!");
+}
+
+TEST_P(GraphicsMapperStableCTests, GetWidthHeight) {
+ auto buffer = allocate({
+ .name = {"Hello, World!"},
+ .width = 64,
+ .height = 128,
+ .layerCount = 1,
+ .format = PixelFormat::RGBA_8888,
+ .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
+ .reservedSize = 0,
+ });
+ auto bufferHandle = buffer->import();
+ auto value = getStandardMetadata<StandardMetadataType::WIDTH>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(*value, 64);
+ value = getStandardMetadata<StandardMetadataType::HEIGHT>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(*value, 128);
+}
+
+TEST_P(GraphicsMapperStableCTests, GetLayerCount) {
+ auto buffer = allocateGeneric();
+ auto bufferHandle = buffer->import();
+ auto value = getStandardMetadata<StandardMetadataType::LAYER_COUNT>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(*value, buffer->info().layerCount);
+}
+
+TEST_P(GraphicsMapperStableCTests, GetPixelFormatRequested) {
+ auto buffer = allocateGeneric();
+ auto bufferHandle = buffer->import();
+ auto value = getStandardMetadata<StandardMetadataType::PIXEL_FORMAT_REQUESTED>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(*value, buffer->info().format);
+}
+
+TEST_P(GraphicsMapperStableCTests, GetPixelFormatFourCC) {
+ auto buffer = allocate({
+ .name = {"Hello, World!"},
+ .width = 64,
+ .height = 128,
+ .layerCount = 1,
+ .format = PixelFormat::RGBA_8888,
+ .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
+ .reservedSize = 0,
+ });
+ {
+ auto bufferHandle = buffer->import();
+ auto value = getStandardMetadata<StandardMetadataType::PIXEL_FORMAT_FOURCC>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(*value, DRM_FORMAT_ABGR8888);
+ }
+
+ buffer = allocate({
+ .name = {"yv12"},
+ .width = 64,
+ .height = 128,
+ .layerCount = 1,
+ .format = PixelFormat::YV12,
+ .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
+ .reservedSize = 0,
+ });
+ {
+ auto bufferHandle = buffer->import();
+ auto value = getStandardMetadata<StandardMetadataType::PIXEL_FORMAT_FOURCC>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(*value, DRM_FORMAT_YVU420);
+ }
+}
+
+TEST_P(GraphicsMapperStableCTests, GetPixelFormatModifier) {
+ auto buffer = allocateGeneric();
+ auto bufferHandle = buffer->import();
+ auto value = getStandardMetadata<StandardMetadataType::PIXEL_FORMAT_MODIFIER>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ // Only the upper 8-bits are defined and is just the vendor ID, the lower 56 bits are
+ // then vendor specific. So there's not anything useful to assert here beyond just that
+ // we successfully queried a value
+}
+
+TEST_P(GraphicsMapperStableCTests, GetUsage) {
+ auto buffer = allocateGeneric();
+ auto bufferHandle = buffer->import();
+ auto value = getStandardMetadata<StandardMetadataType::USAGE>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(buffer->info().usage, *value);
+}
+
+TEST_P(GraphicsMapperStableCTests, GetAllocationSize) {
+ auto buffer = allocateGeneric();
+ auto bufferHandle = buffer->import();
+ auto value = getStandardMetadata<StandardMetadataType::ALLOCATION_SIZE>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ const auto estimatedSize = buffer->stride() * buffer->info().height * 4;
+ // This buffer has CPU usage, so we expect at least stride * height * 4 since it should be
+ // generally linear uncompressed.
+ EXPECT_GE(*value, estimatedSize)
+ << "Expected allocation size to be at least stride * height * 4bpp";
+ // Might need refining, but hopefully this a generous-enough upper-bound?
+ EXPECT_LT(*value, estimatedSize * 2)
+ << "Expected allocation size to less than double stride * height * 4bpp";
+}
+
+TEST_P(GraphicsMapperStableCTests, GetProtectedContent) {
+ const BufferDescriptorInfo info{
+ .name = {"prot8888"},
+ .width = 64,
+ .height = 64,
+ .layerCount = 1,
+ .format = PixelFormat::RGBA_8888,
+ .usage = BufferUsage::PROTECTED | BufferUsage::COMPOSER_OVERLAY,
+ .reservedSize = 0,
+ };
+ auto buffer = allocate(info);
+ if (!buffer) {
+ ASSERT_FALSE(isSupported(info))
+ << "Allocation of trivial sized buffer failed, so isSupported() must be false";
+ GTEST_SUCCEED() << "PROTECTED RGBA_8888 is unsupported";
+ return;
+ }
+ auto bufferHandle = buffer->import();
+ auto value = getStandardMetadata<StandardMetadataType::PROTECTED_CONTENT>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(*value, 1);
+}
+
+TEST_P(GraphicsMapperStableCTests, GetCompression) {
+ auto buffer = allocateGeneric();
+ ASSERT_TRUE(buffer);
+ auto bufferHandle = buffer->import();
+ ASSERT_TRUE(bufferHandle);
+ auto value = getStandardMetadata<StandardMetadataType::COMPRESSION>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(gralloc4::Compression_None.name, value->name);
+ EXPECT_EQ(gralloc4::Compression_None.value, value->value);
+}
+
+TEST_P(GraphicsMapperStableCTests, GetInterlaced) {
+ auto buffer = allocateGeneric();
+ ASSERT_TRUE(buffer);
+ auto bufferHandle = buffer->import();
+ ASSERT_TRUE(bufferHandle);
+ auto value = getStandardMetadata<StandardMetadataType::INTERLACED>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(gralloc4::Interlaced_None.name, value->name);
+ EXPECT_EQ(gralloc4::Interlaced_None.value, value->value);
+}
+
+TEST_P(GraphicsMapperStableCTests, GetChromaSiting) {
+ auto buffer = allocateGeneric();
+ ASSERT_TRUE(buffer);
+ auto bufferHandle = buffer->import();
+ ASSERT_TRUE(bufferHandle);
+ auto value = getStandardMetadata<StandardMetadataType::CHROMA_SITING>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(gralloc4::ChromaSiting_None.name, value->name);
+ EXPECT_EQ(gralloc4::ChromaSiting_None.value, value->value);
+}
+
+TEST_P(GraphicsMapperStableCTests, GetPlaneLayouts) {
+ auto buffer = allocateGeneric();
+ ASSERT_TRUE(buffer);
+ auto bufferHandle = buffer->import();
+ ASSERT_TRUE(bufferHandle);
+ auto value = getStandardMetadata<StandardMetadataType::PLANE_LAYOUTS>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ ASSERT_NO_FATAL_FAILURE(verifyRGBA8888PlaneLayouts(*value));
+}
+
+TEST_P(GraphicsMapperStableCTests, GetCrop) {
+ auto buffer = allocateGeneric();
+ ASSERT_TRUE(buffer);
+ auto bufferHandle = buffer->import();
+ ASSERT_TRUE(bufferHandle);
+ auto value = getStandardMetadata<StandardMetadataType::CROP>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(1, value->size());
+ const Rect expected{0, 0, buffer->info().width, buffer->info().height};
+ EXPECT_EQ(expected, value->at(0));
+}
+
+TEST_P(GraphicsMapperStableCTests, GetSetDataspace) {
+ auto buffer = allocateGeneric();
+ ASSERT_TRUE(buffer);
+ auto bufferHandle = buffer->import();
+ ASSERT_TRUE(bufferHandle);
+ auto value = getStandardMetadata<StandardMetadataType::DATASPACE>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(Dataspace::UNKNOWN, *value);
+ EXPECT_EQ(AIMAPPER_ERROR_NONE, setStandardMetadata<StandardMetadataType::DATASPACE>(
+ *bufferHandle, Dataspace::DISPLAY_P3));
+ value = getStandardMetadata<StandardMetadataType::DATASPACE>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(Dataspace::DISPLAY_P3, *value);
+}
+
+TEST_P(GraphicsMapperStableCTests, GetSetBlendMode) {
+ auto buffer = allocateGeneric();
+ ASSERT_TRUE(buffer);
+ auto bufferHandle = buffer->import();
+ ASSERT_TRUE(bufferHandle);
+ auto value = getStandardMetadata<StandardMetadataType::BLEND_MODE>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(BlendMode::INVALID, *value);
+ EXPECT_EQ(AIMAPPER_ERROR_NONE, setStandardMetadata<StandardMetadataType::BLEND_MODE>(
+ *bufferHandle, BlendMode::COVERAGE));
+ value = getStandardMetadata<StandardMetadataType::BLEND_MODE>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(BlendMode::COVERAGE, *value);
+}
+
+TEST_P(GraphicsMapperStableCTests, GetSetSmpte2086) {
+ auto buffer = allocateGeneric();
+ ASSERT_TRUE(buffer);
+ auto bufferHandle = buffer->import();
+ ASSERT_TRUE(bufferHandle);
+ auto value = getStandardMetadata<StandardMetadataType::SMPTE2086>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_FALSE(value->has_value());
+
+ // TODO: Maybe use something resembling real values, but validation isn't supposed to happen
+ // here anyway so :shrug:
+ const Smpte2086 awesomeHdr{
+ XyColor{1.f, 1.f}, XyColor{2.f, 2.f}, XyColor{3.f, 3.f},
+ XyColor{400.f, 1000.f}, 100000.0f, 0.0001f,
+ };
+ EXPECT_EQ(AIMAPPER_ERROR_NONE,
+ setStandardMetadata<StandardMetadataType::SMPTE2086>(*bufferHandle, awesomeHdr));
+ value = getStandardMetadata<StandardMetadataType::SMPTE2086>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ ASSERT_TRUE(value->has_value());
+ EXPECT_EQ(awesomeHdr, *value);
+
+ EXPECT_EQ(AIMAPPER_ERROR_NONE,
+ setStandardMetadata<StandardMetadataType::SMPTE2086>(*bufferHandle, std::nullopt));
+ value = getStandardMetadata<StandardMetadataType::SMPTE2086>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_FALSE(value->has_value());
+}
+
+TEST_P(GraphicsMapperStableCTests, GetCta861_3) {
+ auto buffer = allocateGeneric();
+ ASSERT_TRUE(buffer);
+ auto bufferHandle = buffer->import();
+ ASSERT_TRUE(bufferHandle);
+ auto value = getStandardMetadata<StandardMetadataType::CTA861_3>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_FALSE(value->has_value());
+
+ const Cta861_3 genericHlgish{1000.f, 140.f};
+ EXPECT_EQ(AIMAPPER_ERROR_NONE,
+ setStandardMetadata<StandardMetadataType::CTA861_3>(*bufferHandle, genericHlgish));
+ value = getStandardMetadata<StandardMetadataType::CTA861_3>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ ASSERT_TRUE(value->has_value());
+ EXPECT_EQ(genericHlgish, *value);
+
+ EXPECT_EQ(AIMAPPER_ERROR_NONE,
+ setStandardMetadata<StandardMetadataType::CTA861_3>(*bufferHandle, std::nullopt));
+ value = getStandardMetadata<StandardMetadataType::CTA861_3>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_FALSE(value->has_value());
+}
+
+TEST_P(GraphicsMapperStableCTests, GetSmpte2094_10) {
+ auto buffer = allocateGeneric();
+ ASSERT_TRUE(buffer);
+ auto bufferHandle = buffer->import();
+ ASSERT_TRUE(bufferHandle);
+ auto value = getStandardMetadata<StandardMetadataType::SMPTE2094_10>(*bufferHandle);
+ if (value.has_value()) {
+ EXPECT_FALSE(value->has_value());
+ }
+}
+
+TEST_P(GraphicsMapperStableCTests, GetSmpte2094_40) {
+ auto buffer = allocateGeneric();
+ ASSERT_TRUE(buffer);
+ auto bufferHandle = buffer->import();
+ ASSERT_TRUE(bufferHandle);
+ auto value = getStandardMetadata<StandardMetadataType::SMPTE2094_40>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_FALSE(value->has_value());
+}
+
+std::vector<std::tuple<std::string, std::shared_ptr<IAllocator>>> getIAllocatorsAtLeastVersion(
+ int32_t minVersion) {
+ auto instanceNames = getAidlHalInstanceNames(IAllocator::descriptor);
+ std::vector<std::tuple<std::string, std::shared_ptr<IAllocator>>> filteredInstances;
+ filteredInstances.reserve(instanceNames.size());
+ for (const auto& name : instanceNames) {
+ auto allocator =
+ IAllocator::fromBinder(ndk::SpAIBinder(AServiceManager_checkService(name.c_str())));
+ int32_t version = 0;
+ if (allocator->getInterfaceVersion(&version).isOk()) {
+ if (version >= minVersion) {
+ filteredInstances.emplace_back(name, std::move(allocator));
+ }
+ }
+ }
+ return filteredInstances;
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsMapperStableCTests);
+INSTANTIATE_TEST_CASE_P(PerInstance, GraphicsMapperStableCTests,
+ testing::ValuesIn(getIAllocatorsAtLeastVersion(2)),
+ [](auto info) -> std::string {
+ std::string name =
+ std::to_string(info.index) + "/" + std::get<0>(info.param);
+ return Sanitize(name);
+ });
\ No newline at end of file
diff --git a/health/aidl/Android.bp b/health/aidl/Android.bp
index f0cd33f..a4d4ace 100644
--- a/health/aidl/Android.bp
+++ b/health/aidl/Android.bp
@@ -36,11 +36,6 @@
enabled: true,
sdk_version: "module_current",
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
versions_with_info: [
{
diff --git a/health/aidl/default/Android.bp b/health/aidl/default/Android.bp
index 8eab997..4eb3cb1 100644
--- a/health/aidl/default/Android.bp
+++ b/health/aidl/default/Android.bp
@@ -159,3 +159,51 @@
init_rc: ["android.hardware.health-service.example_recovery.rc"],
overrides: ["charger.recovery"],
}
+
+// AIDL Fuzz version of libhealth2impl.
+cc_library_static {
+ name: "fuzz_libhealth_aidl_impl",
+ defaults: [
+ "libhealth_aidl_common_defaults",
+ "libhealth_aidl_charger_defaults",
+ ],
+ recovery_available: true,
+ export_include_dirs: ["include"],
+ export_static_lib_headers: [
+ "libbatterymonitor",
+ ],
+ srcs: [
+ "ChargerUtils.cpp",
+ "health-convert.cpp",
+ "HalHealthLoop.cpp",
+ "Health.cpp",
+ "LinkedCallback.cpp",
+ ],
+ target: {
+ recovery: {
+ exclude_srcs: [
+ "ChargerUtils.cpp",
+ ],
+ },
+ },
+}
+
+cc_fuzz {
+ name: "android.hardware.health-service.aidl_fuzzer",
+ defaults: [
+ "libhealth_aidl_impl_user",
+ "service_fuzzer_defaults",
+ ],
+ static_libs: [
+ "android.hardware.health-V1-ndk",
+ "libbase",
+ "liblog",
+ "fuzz_libhealth_aidl_impl",
+ ],
+ srcs: ["fuzzer.cpp"],
+ fuzz_config: {
+ cc: [
+ "hamzeh@google.com",
+ ],
+ },
+}
diff --git a/health/aidl/default/fuzzer.cpp b/health/aidl/default/fuzzer.cpp
new file mode 100644
index 0000000..b7c6d39
--- /dev/null
+++ b/health/aidl/default/fuzzer.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <fuzzbinder/libbinder_ndk_driver.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+#include <android-base/logging.h>
+#include <android/binder_interface_utils.h>
+#include <health-impl/Health.h>
+#include <health/utils.h>
+
+using aidl::android::hardware::health::Health;
+using android::fuzzService;
+using ndk::SharedRefBase;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ auto config = std::make_unique<healthd_config>();
+ ::android::hardware::health::InitHealthdConfig(config.get());
+ auto binder = ndk::SharedRefBase::make<Health>("default", std::move(config));
+
+ fuzzService(binder->asBinder().get(), FuzzedDataProvider(data, size));
+
+ return 0;
+}
\ No newline at end of file
diff --git a/health/storage/aidl/Android.bp b/health/storage/aidl/Android.bp
index 4cd9263..c614efb 100644
--- a/health/storage/aidl/Android.bp
+++ b/health/storage/aidl/Android.bp
@@ -33,11 +33,6 @@
java: {
enabled: false,
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
versions: ["1"],
}
diff --git a/identity/aidl/Android.bp b/identity/aidl/Android.bp
index 920a4b9..2090473 100644
--- a/identity/aidl/Android.bp
+++ b/identity/aidl/Android.bp
@@ -14,18 +14,16 @@
"android/hardware/identity/*.aidl",
],
imports: [
- "android.hardware.keymaster",
- "android.hardware.security.keymint",
+ "android.hardware.keymaster-V3",
+ "android.hardware.security.rkp-V3",
],
stability: "vintf",
+ frozen: true,
backend: {
java: {
platform_apis: true,
},
ndk: {
- vndk: {
- enabled: true,
- },
apps_enabled: false,
},
},
@@ -34,31 +32,55 @@
version: "1",
imports: [
"android.hardware.keymaster-V3",
- "android.hardware.security.keymint-V1",
+ "android.hardware.security.rkp-V1",
],
},
{
version: "2",
imports: [
"android.hardware.keymaster-V3",
- "android.hardware.security.keymint-V1",
+ "android.hardware.security.rkp-V1",
],
},
{
version: "3",
imports: [
"android.hardware.keymaster-V3",
- "android.hardware.security.keymint-V1",
+ "android.hardware.security.rkp-V1",
],
},
{
version: "4",
imports: [
"android.hardware.keymaster-V3",
- "android.hardware.security.keymint-V2",
+ "android.hardware.security.rkp-V3",
],
},
],
}
+
+// cc_defaults that includes the latest Identity AIDL library.
+// Modules that depend on Identity directly can include this cc_defaults to
+// avoid managing dependency versions explicitly.
+cc_defaults {
+ name: "identity_use_latest_hal_aidl_ndk_static",
+ static_libs: [
+ "android.hardware.identity-V4-ndk",
+ ],
+}
+
+cc_defaults {
+ name: "identity_use_latest_hal_aidl_ndk_shared",
+ shared_libs: [
+ "android.hardware.identity-V4-ndk",
+ ],
+}
+
+cc_defaults {
+ name: "identity_use_latest_hal_aidl_cpp_static",
+ static_libs: [
+ "android.hardware.identity-V4-cpp",
+ ],
+}
diff --git a/identity/aidl/default/Android.bp b/identity/aidl/default/Android.bp
index 31ab400..7bc3c8d 100644
--- a/identity/aidl/default/Android.bp
+++ b/identity/aidl/default/Android.bp
@@ -10,6 +10,10 @@
cc_library_static {
name: "android.hardware.identity-libeic-hal-common",
vendor_available: true,
+ defaults: [
+ "identity_use_latest_hal_aidl_ndk_static",
+ "keymint_use_latest_hal_aidl_ndk_static",
+ ],
srcs: [
"common/IdentityCredential.cpp",
"common/IdentityCredentialStore.cpp",
@@ -40,9 +44,8 @@
"libsoft_attestation_cert",
"libpuresoftkeymasterdevice",
"android.hardware.identity-support-lib",
- "android.hardware.identity-V4-ndk",
"android.hardware.keymaster-V3-ndk",
- "android.hardware.security.keymint-V2-ndk",
+ "android.hardware.security.rkp-V3-ndk",
],
}
@@ -83,6 +86,7 @@
vintf_fragments: ["identity-default.xml"],
vendor: true,
defaults: [
+ "identity_use_latest_hal_aidl_ndk_static",
"keymint_use_latest_hal_aidl_ndk_static",
],
cflags: [
@@ -106,10 +110,10 @@
"libsoft_attestation_cert",
"libpuresoftkeymasterdevice",
"android.hardware.identity-support-lib",
- "android.hardware.identity-V4-ndk",
"android.hardware.keymaster-V3-ndk",
"android.hardware.identity-libeic-hal-common",
"android.hardware.identity-libeic-library",
+ "android.hardware.security.rkp-V3-ndk",
],
srcs: [
"service.cpp",
diff --git a/identity/aidl/default/EicOpsImpl.cc b/identity/aidl/default/EicOpsImpl.cc
index 3fd9f1d..803df64 100644
--- a/identity/aidl/default/EicOpsImpl.cc
+++ b/identity/aidl/default/EicOpsImpl.cc
@@ -100,6 +100,7 @@
if (size != EIC_SHA256_DIGEST_SIZE) {
LOG(ERROR) << "Expected 32 bytes from HMAC_Final, got " << size;
}
+ HMAC_CTX_cleanup(realCtx);
}
void eicOpsSha256Init(EicSha256Ctx* ctx) {
@@ -394,14 +395,17 @@
}
if (BN_bn2binpad(sig->r, signature, 32) != 32) {
+ ECDSA_SIG_free(sig);
eicDebug("Error encoding r");
return false;
}
if (BN_bn2binpad(sig->s, signature + 32, 32) != 32) {
+ ECDSA_SIG_free(sig);
eicDebug("Error encoding s");
return false;
}
+ ECDSA_SIG_free(sig);
return true;
}
@@ -485,7 +489,7 @@
}
bool eicOpsEcdh(const uint8_t publicKey[EIC_P256_PUB_KEY_SIZE],
- const uint8_t privateKey[EIC_P256_PUB_KEY_SIZE],
+ const uint8_t privateKey[EIC_P256_PRIV_KEY_SIZE],
uint8_t sharedSecret[EIC_P256_COORDINATE_SIZE]) {
vector<uint8_t> pubKeyVec(EIC_P256_PUB_KEY_SIZE + 1);
pubKeyVec[0] = 0x04;
diff --git a/identity/aidl/default/android.hardware.identity_credential.xml b/identity/aidl/default/android.hardware.identity_credential.xml
index 20b2710..a49ddca 100644
--- a/identity/aidl/default/android.hardware.identity_credential.xml
+++ b/identity/aidl/default/android.hardware.identity_credential.xml
@@ -14,5 +14,5 @@
limitations under the License.
-->
<permissions>
- <feature name="android.hardware.identity_credential" version="202201" />
+ <feature name="android.hardware.identity_credential" version="202301" />
</permissions>
diff --git a/identity/aidl/vts/Android.bp b/identity/aidl/vts/Android.bp
index 51ab110..5e303bb 100644
--- a/identity/aidl/vts/Android.bp
+++ b/identity/aidl/vts/Android.bp
@@ -11,6 +11,7 @@
name: "VtsHalIdentityTargetTest",
defaults: [
"VtsHalTargetTestDefaults",
+ "identity_use_latest_hal_aidl_cpp_static",
"keymint_use_latest_hal_aidl_cpp_static",
"keymint_use_latest_hal_aidl_ndk_static",
"use_libaidlvintf_gtest_helper_static",
@@ -38,6 +39,8 @@
"libcrypto",
],
static_libs: [
+ "android.hardware.security.rkp-V3-cpp",
+ "android.hardware.security.rkp-V3-ndk",
"android.hardware.security.secureclock-V1-ndk",
"libcppbor_external",
"libcppcose_rkp",
@@ -46,7 +49,6 @@
"libpuresoftkeymasterdevice",
"android.hardware.keymaster@4.0",
"android.hardware.identity-support-lib",
- "android.hardware.identity-V4-cpp",
"android.hardware.keymaster-V3-cpp",
"android.hardware.keymaster-V3-ndk",
"libkeymaster4support",
@@ -59,3 +61,16 @@
],
require_root: true,
}
+
+java_test_host {
+ name: "IdentityCredentialImplementedTest",
+ libs: [
+ "tradefed",
+ "vts-core-tradefed-harness",
+ ],
+ srcs: ["src/**/*.java"],
+ test_suites: [
+ "vts",
+ ],
+ test_config: "IdentityCredentialImplementedTest.xml",
+}
diff --git a/identity/aidl/vts/AndroidTest.xml b/identity/aidl/vts/AndroidTest.xml
new file mode 100644
index 0000000..67132b0
--- /dev/null
+++ b/identity/aidl/vts/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?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 VtsHalIdentityTargetTest.">
+ <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="VtsHalIdentityTargetTest->/data/local/tmp/VtsHalIdentityTargetTest" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="VtsHalIdentityTargetTest" />
+ <option name="native-test-timeout" value="300000"/>
+ </test>
+</configuration>
diff --git a/identity/aidl/vts/IdentityCredentialImplementedTest.xml b/identity/aidl/vts/IdentityCredentialImplementedTest.xml
new file mode 100644
index 0000000..4276ae6
--- /dev/null
+++ b/identity/aidl/vts/IdentityCredentialImplementedTest.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<configuration description="Runs IdentityCredentialImplementedTest">
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
+
+ <test class="com.android.tradefed.testtype.HostTest" >
+ <option name="jar" value="IdentityCredentialImplementedTest.jar" />
+ </test>
+</configuration>
diff --git a/identity/aidl/vts/src/com/android/tests/security/identity/IdentityCredentialImplementedTest.java b/identity/aidl/vts/src/com/android/tests/security/identity/IdentityCredentialImplementedTest.java
new file mode 100644
index 0000000..4936f8c
--- /dev/null
+++ b/identity/aidl/vts/src/com/android/tests/security/identity/IdentityCredentialImplementedTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tests.security.identity;
+
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
+
+import android.platform.test.annotations.RequiresDevice;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+// This is a host-test which executes shell commands on the device. It would be
+// nicer to have this be a Device test (like CTS) but this is currently not
+// possible, see https://source.android.com/docs/core/tests/vts
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class IdentityCredentialImplementedTest extends BaseHostJUnit4Test {
+ // Returns the ro.vendor.api_level or 0 if not set.
+ //
+ // Throws NumberFormatException if ill-formatted.
+ //
+ // Throws DeviceNotAvailableException if device is not available.
+ //
+ private int getVendorApiLevel() throws NumberFormatException, DeviceNotAvailableException {
+ String vendorApiLevelString =
+ getDevice().executeShellCommand("getprop ro.vendor.api_level").trim();
+ if (vendorApiLevelString.isEmpty()) {
+ return 0;
+ }
+ return Integer.parseInt(vendorApiLevelString);
+ }
+
+ // As of Android 14 VSR (vendor API level 34), Identity Credential is required at feature
+ // version 202301 or later.
+ @RequiresDevice
+ @Test
+ public void testIdentityCredentialIsImplemented() throws Exception {
+ int vendorApiLevel = getVendorApiLevel();
+ assumeTrue(vendorApiLevel >= 34);
+
+ final String minimumFeatureVersionNeeded = "202301";
+
+ String result = getDevice().executeShellCommand(
+ "pm has-feature android.hardware.identity_credential "
+ + minimumFeatureVersionNeeded);
+ if (!result.trim().equals("true")) {
+ fail("Identity Credential feature version " + minimumFeatureVersionNeeded
+ + " required but not found");
+ }
+ }
+}
diff --git a/input/common/aidl/Android.bp b/input/common/aidl/Android.bp
index 390d8b5..95a14b2 100644
--- a/input/common/aidl/Android.bp
+++ b/input/common/aidl/Android.bp
@@ -9,6 +9,7 @@
aidl_interface {
name: "android.hardware.input.common",
+ host_supported: true,
vendor_available: true,
srcs: ["android/hardware/input/common/*.aidl"],
stability: "vintf",
diff --git a/input/processor/aidl/Android.bp b/input/processor/aidl/Android.bp
index 354816e..773bb49 100644
--- a/input/processor/aidl/Android.bp
+++ b/input/processor/aidl/Android.bp
@@ -9,6 +9,7 @@
aidl_interface {
name: "android.hardware.input.processor",
+ host_supported: true,
vendor_available: true,
srcs: ["android/hardware/input/processor/*.aidl"],
imports: [
diff --git a/ir/aidl/Android.bp b/ir/aidl/Android.bp
index 2485f5b..25f6c8f 100644
--- a/ir/aidl/Android.bp
+++ b/ir/aidl/Android.bp
@@ -33,11 +33,6 @@
java: {
sdk_version: "module_current",
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
versions_with_info: [
{
diff --git a/ir/aidl/default/Android.bp b/ir/aidl/default/Android.bp
index a4fb439..a8096c2 100644
--- a/ir/aidl/default/Android.bp
+++ b/ir/aidl/default/Android.bp
@@ -36,6 +36,7 @@
"liblog",
"libutils",
"android.hardware.ir-V1-ndk",
+ "libhardware"
],
srcs: ["main.cpp"],
diff --git a/ir/aidl/default/android.hardware.ir-service.example.rc b/ir/aidl/default/android.hardware.ir-service.example.rc
index 56def64..d27f282 100644
--- a/ir/aidl/default/android.hardware.ir-service.example.rc
+++ b/ir/aidl/default/android.hardware.ir-service.example.rc
@@ -1,4 +1,4 @@
service vendor.ir-default /vendor/bin/hw/android.hardware.ir-service.example
class hal
- user nobody
- group nobody
+ user system
+ group system
diff --git a/ir/aidl/default/main.cpp b/ir/aidl/default/main.cpp
index 7c4a816..92376fc 100644
--- a/ir/aidl/default/main.cpp
+++ b/ir/aidl/default/main.cpp
@@ -15,49 +15,77 @@
*/
#include <aidl/android/hardware/ir/BnConsumerIr.h>
+#include <aidl/android/hardware/ir/ConsumerIrFreqRange.h>
#include <android-base/logging.h>
#include <android/binder_interface_utils.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
+#include <hardware/consumerir.h>
#include <numeric>
+#include <log/log.h>
+
+using ::aidl::android::hardware::ir::ConsumerIrFreqRange;
+
namespace aidl::android::hardware::ir {
-const std::vector<ConsumerIrFreqRange> kSupportedFreqs = {
- {2000, 4000},
- {10000, 30000},
-};
-
class ConsumerIr : public BnConsumerIr {
+ public:
+ ConsumerIr();
+ private:
::ndk::ScopedAStatus getCarrierFreqs(std::vector<ConsumerIrFreqRange>* _aidl_return) override;
::ndk::ScopedAStatus transmit(int32_t in_carrierFreqHz,
const std::vector<int32_t>& in_pattern) override;
+ consumerir_device_t *mDevice = nullptr;
};
-::ndk::ScopedAStatus ConsumerIr::getCarrierFreqs(std::vector<ConsumerIrFreqRange>* _aidl_return) {
- *_aidl_return = kSupportedFreqs;
- return ::ndk::ScopedAStatus::ok();
+ConsumerIr::ConsumerIr() {
+ const hw_module_t *hw_module = NULL;
+
+ int ret = hw_get_module(CONSUMERIR_HARDWARE_MODULE_ID, &hw_module);
+ if (ret != 0) {
+ ALOGE("hw_get_module %s failed: %d", CONSUMERIR_HARDWARE_MODULE_ID, ret);
+ return;
+ }
+ ret = hw_module->methods->open(hw_module, CONSUMERIR_TRANSMITTER, (hw_device_t **) &mDevice);
+ if (ret < 0) {
+ // note - may want to make this a fatal error - otherwise the service will crash when it's used
+ ALOGE("Can't open consumer IR transmitter, error: %d", ret);
+ // in case it's modified
+ mDevice = nullptr;
+ }
}
-bool isSupportedFreq(int32_t freq) {
- for (const auto& range : kSupportedFreqs) {
- if (freq >= range.minHz && freq <= range.maxHz) return true;
+::ndk::ScopedAStatus ConsumerIr::getCarrierFreqs(std::vector<ConsumerIrFreqRange>* _aidl_return) {
+ int32_t len = mDevice->get_num_carrier_freqs(mDevice);
+ if (len < 0) {
+ (*_aidl_return).clear();
+ return ::ndk::ScopedAStatus::ok();
}
- return false;
+
+ consumerir_freq_range_t *rangeAr = new consumerir_freq_range_t[len];
+ bool success = (mDevice->get_carrier_freqs(mDevice, len, rangeAr) >= 0);
+ if (!success) {
+ (*_aidl_return).clear();
+ return ::ndk::ScopedAStatus::ok();
+ }
+
+ (*_aidl_return).resize(len);
+ for (int32_t i = 0; i < len; i++) {
+ (*_aidl_return)[i].minHz = static_cast<uint32_t>(rangeAr[i].min);
+ (*_aidl_return)[i].maxHz = static_cast<uint32_t>(rangeAr[i].max);
+ }
+ return ::ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus ConsumerIr::transmit(int32_t in_carrierFreqHz,
const std::vector<int32_t>& in_pattern) {
- if (isSupportedFreq(in_carrierFreqHz)) {
- // trasmit the pattern, each integer is number of microseconds in an
- // alternating on/off state.
- usleep(std::accumulate(in_pattern.begin(), in_pattern.end(), 0));
+ if (in_carrierFreqHz > 0) {
+ mDevice->transmit(mDevice, in_carrierFreqHz, in_pattern.data(), in_pattern.size());
return ::ndk::ScopedAStatus::ok();
} else {
- // unsupported operation
return ::ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
- return ::ndk::ScopedAStatus::ok();
}
} // namespace aidl::android::hardware::ir
diff --git a/keymaster/3.0/default/OWNERS b/keymaster/3.0/default/OWNERS
deleted file mode 100644
index 335660d..0000000
--- a/keymaster/3.0/default/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-jdanis@google.com
-swillden@google.com
diff --git a/keymaster/3.0/vts/OWNERS b/keymaster/3.0/vts/OWNERS
deleted file mode 100644
index 846bb84..0000000
--- a/keymaster/3.0/vts/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-drysdale@google.com
-jdanis@google.com
-swillden@google.com
-yim@google.com
-yuexima@google.com
diff --git a/keymaster/3.0/vts/functional/OWNERS b/keymaster/3.0/vts/functional/OWNERS
deleted file mode 100644
index 2ef9086..0000000
--- a/keymaster/3.0/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 189335
-swillden@google.com
diff --git a/keymaster/4.0/default/OWNERS b/keymaster/4.0/default/OWNERS
deleted file mode 100644
index 335660d..0000000
--- a/keymaster/4.0/default/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-jdanis@google.com
-swillden@google.com
diff --git a/keymaster/4.0/support/OWNERS b/keymaster/4.0/support/OWNERS
deleted file mode 100644
index a9efe66..0000000
--- a/keymaster/4.0/support/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-jdanis@google.com
-swillden@google.com
-jbires@google.com
diff --git a/keymaster/4.0/vts/OWNERS b/keymaster/4.0/vts/OWNERS
deleted file mode 100644
index 0d6fa6c..0000000
--- a/keymaster/4.0/vts/OWNERS
+++ /dev/null
@@ -1,6 +0,0 @@
-drysdale@google.com
-jbires@google.com
-jdanis@google.com
-swillden@google.com
-yim@google.com
-yuexima@google.com
diff --git a/keymaster/4.0/vts/functional/OWNERS b/keymaster/4.0/vts/functional/OWNERS
deleted file mode 100644
index 2ef9086..0000000
--- a/keymaster/4.0/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 189335
-swillden@google.com
diff --git a/keymaster/4.1/default/OWNERS b/keymaster/4.1/default/OWNERS
deleted file mode 100644
index 2b2ad2a..0000000
--- a/keymaster/4.1/default/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-jbires@google.com
-jdanis@google.com
-swillden@google.com
-zeuthen@google.com
\ No newline at end of file
diff --git a/keymaster/4.1/support/OWNERS b/keymaster/4.1/support/OWNERS
deleted file mode 100644
index 2b2ad2a..0000000
--- a/keymaster/4.1/support/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-jbires@google.com
-jdanis@google.com
-swillden@google.com
-zeuthen@google.com
\ No newline at end of file
diff --git a/keymaster/4.1/vts/OWNERS b/keymaster/4.1/vts/OWNERS
deleted file mode 100644
index 24ed042..0000000
--- a/keymaster/4.1/vts/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-drysdale@google.com
-jbires@google.com
-jdanis@google.com
-swillden@google.com
-zeuthen@google.com
\ No newline at end of file
diff --git a/keymaster/4.1/vts/functional/OWNERS b/keymaster/4.1/vts/functional/OWNERS
deleted file mode 100644
index 2ef9086..0000000
--- a/keymaster/4.1/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 189335
-swillden@google.com
diff --git a/keymaster/OWNERS b/keymaster/OWNERS
new file mode 100644
index 0000000..ac8bd83
--- /dev/null
+++ b/keymaster/OWNERS
@@ -0,0 +1,14 @@
+# Bug component: 1084733
+
+# Please assign all bugs related to /hardware/interfaces/keymaster to the team alias:
+#
+# android-hardware-security@google.com
+#
+# This will get them auto-assigned to the on-call triage engineer, ensuring quickest response.
+
+drysdale@google.com
+eranm@google.com
+hasinitg@google.com
+jbires@google.com
+swillden@google.com
+zeuthen@google.com
diff --git a/keymaster/aidl/Android.bp b/keymaster/aidl/Android.bp
index c4b6740..a3800c1 100644
--- a/keymaster/aidl/Android.bp
+++ b/keymaster/aidl/Android.bp
@@ -18,15 +18,19 @@
java: {
platform_apis: true,
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
- versions: [
- "1",
- "2",
- "3",
+ versions_with_info: [
+ {
+ version: "1",
+ imports: [],
+ },
+ {
+ version: "2",
+ imports: [],
+ },
+ {
+ version: "3",
+ imports: [],
+ },
],
}
diff --git a/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/HardwareAuthToken.aidl b/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/HardwareAuthToken.aidl
index 4f21cba..6e84e98 100644
--- a/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/HardwareAuthToken.aidl
+++ b/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/HardwareAuthToken.aidl
@@ -1,14 +1,30 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
-// edit this file. It looks like you are doing that because you have modified
-// an AIDL interface in a backward-incompatible way, e.g., deleting a function
-// from an interface or a field from a parcelable and it broke the build. That
-// breakage is intended.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
@@ -16,6 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.keymaster;
+/* @hide */
@VintfStability
parcelable HardwareAuthToken {
long challenge;
diff --git a/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/HardwareAuthenticatorType.aidl b/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/HardwareAuthenticatorType.aidl
index 924567f..0a40549 100644
--- a/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/HardwareAuthenticatorType.aidl
+++ b/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/HardwareAuthenticatorType.aidl
@@ -1,14 +1,30 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
-// edit this file. It looks like you are doing that because you have modified
-// an AIDL interface in a backward-incompatible way, e.g., deleting a function
-// from an interface or a field from a parcelable and it broke the build. That
-// breakage is intended.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
@@ -16,6 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.keymaster;
+/* @hide */
@Backing(type="int") @VintfStability
enum HardwareAuthenticatorType {
NONE = 0,
diff --git a/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/SecurityLevel.aidl b/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/SecurityLevel.aidl
index 127c1bf..d32ef68 100644
--- a/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/SecurityLevel.aidl
+++ b/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/SecurityLevel.aidl
@@ -1,14 +1,30 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
-// edit this file. It looks like you are doing that because you have modified
-// an AIDL interface in a backward-incompatible way, e.g., deleting a function
-// from an interface or a field from a parcelable and it broke the build. That
-// breakage is intended.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
@@ -16,6 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.keymaster;
+/* @hide */
@Backing(type="int") @VintfStability
enum SecurityLevel {
SOFTWARE = 0,
diff --git a/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/Timestamp.aidl b/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/Timestamp.aidl
index 45fa1ae..5b7b37a 100644
--- a/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/Timestamp.aidl
+++ b/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/Timestamp.aidl
@@ -1,14 +1,30 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
-// edit this file. It looks like you are doing that because you have modified
-// an AIDL interface in a backward-incompatible way, e.g., deleting a function
-// from an interface or a field from a parcelable and it broke the build. That
-// breakage is intended.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
@@ -16,6 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.keymaster;
+/* @hide */
@VintfStability
parcelable Timestamp {
long milliSeconds;
diff --git a/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/VerificationToken.aidl b/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/VerificationToken.aidl
index b116dac..10fa5e1 100644
--- a/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/VerificationToken.aidl
+++ b/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/VerificationToken.aidl
@@ -1,14 +1,30 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
-// edit this file. It looks like you are doing that because you have modified
-// an AIDL interface in a backward-incompatible way, e.g., deleting a function
-// from an interface or a field from a parcelable and it broke the build. That
-// breakage is intended.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
@@ -16,6 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.keymaster;
+/* @hide */
@VintfStability
parcelable VerificationToken {
long challenge;
diff --git a/keymaster/aidl/android/hardware/keymaster/HardwareAuthToken.aidl b/keymaster/aidl/android/hardware/keymaster/HardwareAuthToken.aidl
index 99b036a..427c192 100644
--- a/keymaster/aidl/android/hardware/keymaster/HardwareAuthToken.aidl
+++ b/keymaster/aidl/android/hardware/keymaster/HardwareAuthToken.aidl
@@ -16,8 +16,8 @@
package android.hardware.keymaster;
-import android.hardware.keymaster.Timestamp;
import android.hardware.keymaster.HardwareAuthenticatorType;
+import android.hardware.keymaster.Timestamp;
/**
* HardwareAuthToken is used to prove successful user authentication, to unlock the use of a key.
@@ -27,10 +27,10 @@
* begin(), update(), and finish() to prove that authentication occurred. See those methods for
* more details. It is up to the caller to determine which of the generated auth tokens is
* appropriate for a given key operation.
+ * @hide
*/
@VintfStability
parcelable HardwareAuthToken {
-
/**
* challenge is a value that's used to enable authentication tokens to authorize specific
* events. The primary use case for challenge is to authorize an IKeymasterDevice cryptographic
@@ -49,7 +49,7 @@
* but is created in an authentication application in the secure environment, such as the
* Fingerprint application.
*/
- long authenticatorId; // Secure authenticator ID.
+ long authenticatorId; // Secure authenticator ID.
/**
* authenticatorType describes the type of authentication that took place, e.g. password or
diff --git a/keymaster/aidl/android/hardware/keymaster/HardwareAuthenticatorType.aidl b/keymaster/aidl/android/hardware/keymaster/HardwareAuthenticatorType.aidl
index 3141858..7a303a7 100644
--- a/keymaster/aidl/android/hardware/keymaster/HardwareAuthenticatorType.aidl
+++ b/keymaster/aidl/android/hardware/keymaster/HardwareAuthenticatorType.aidl
@@ -20,6 +20,7 @@
* Hardware authentication type, used by HardwareAuthTokens to specify the mechanism used to
* authentiate the user, and in KeyCharacteristics to specify the allowable mechanisms for
* authenticating to activate a key.
+ * @hide
*/
@VintfStability
@Backing(type="int")
diff --git a/keymaster/aidl/android/hardware/keymaster/SecurityLevel.aidl b/keymaster/aidl/android/hardware/keymaster/SecurityLevel.aidl
index 00578a4..0b84392 100644
--- a/keymaster/aidl/android/hardware/keymaster/SecurityLevel.aidl
+++ b/keymaster/aidl/android/hardware/keymaster/SecurityLevel.aidl
@@ -18,6 +18,7 @@
/**
* Device security levels.
+ * @hide
*/
@VintfStability
@Backing(type="int")
diff --git a/keymaster/aidl/android/hardware/keymaster/Timestamp.aidl b/keymaster/aidl/android/hardware/keymaster/Timestamp.aidl
index 19ea944..0b0c36f 100644
--- a/keymaster/aidl/android/hardware/keymaster/Timestamp.aidl
+++ b/keymaster/aidl/android/hardware/keymaster/Timestamp.aidl
@@ -16,14 +16,13 @@
package android.hardware.keymaster;
-
/**
* Time in milliseconds since some arbitrary point in time. Time must be monotonically increasing,
* and a secure environment's notion of "current time" must not repeat until the Android device
* reboots, or until at least 50 million years have elapsed (note that this requirement is satisfied
* by setting the clock to zero during each boot, and then counting time accurately).
+ * @hide
*/
-
@VintfStability
parcelable Timestamp {
long milliSeconds;
diff --git a/keymaster/aidl/android/hardware/keymaster/VerificationToken.aidl b/keymaster/aidl/android/hardware/keymaster/VerificationToken.aidl
index 5efd937..ceee941 100644
--- a/keymaster/aidl/android/hardware/keymaster/VerificationToken.aidl
+++ b/keymaster/aidl/android/hardware/keymaster/VerificationToken.aidl
@@ -24,6 +24,7 @@
*
* This version of the parcelable currently don't use the parametersVerified field since it's not
* needed for time-based verification. This can be added in a later version, if needed.
+ * @hide
*/
@VintfStability
parcelable VerificationToken {
@@ -39,7 +40,6 @@
*/
Timestamp timestamp;
-
/**
* SecurityLevel of the secure environment that generated the token.
*/
diff --git a/light/aidl/Android.bp b/light/aidl/Android.bp
index 6f478d7..c11934f 100644
--- a/light/aidl/Android.bp
+++ b/light/aidl/Android.bp
@@ -18,11 +18,6 @@
java: {
sdk_version: "module_current",
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
versions_with_info: [
{
diff --git a/light/aidl/default/Lights.cpp b/light/aidl/default/Lights.cpp
index 74747d5..9bf3b20 100644
--- a/light/aidl/default/Lights.cpp
+++ b/light/aidl/default/Lights.cpp
@@ -23,12 +23,21 @@
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;
- return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ 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*/) {
+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();
}
diff --git a/light/aidl/default/Lights.h b/light/aidl/default/Lights.h
index 8cba5a1..cba147f 100644
--- a/light/aidl/default/Lights.h
+++ b/light/aidl/default/Lights.h
@@ -23,10 +23,10 @@
namespace hardware {
namespace light {
-// Default implementation that reports no supported lights.
+// 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>* types) override;
+ ndk::ScopedAStatus getLights(std::vector<HwLight>* lights) override;
};
} // namespace light
diff --git a/memtrack/aidl/Android.bp b/memtrack/aidl/Android.bp
index 79effcb..0d1c241 100644
--- a/memtrack/aidl/Android.bp
+++ b/memtrack/aidl/Android.bp
@@ -39,5 +39,6 @@
},
},
},
+ frozen: true,
versions: ["1"],
}
diff --git a/neuralnetworks/1.0/vts/functional/Android.bp b/neuralnetworks/1.0/vts/functional/Android.bp
index 29b31d2..8048e62 100644
--- a/neuralnetworks/1.0/vts/functional/Android.bp
+++ b/neuralnetworks/1.0/vts/functional/Android.bp
@@ -27,7 +27,6 @@
name: "neuralnetworks_vts_functional_defaults",
defaults: [
"VtsHalTargetTestDefaults",
- "neuralnetworks_float16",
],
}
@@ -90,7 +89,6 @@
"libneuralnetworks_headers",
],
test_suites: [
- "general-tests",
"vts",
],
}
diff --git a/neuralnetworks/1.0/vts/functional/ValidateModel.cpp b/neuralnetworks/1.0/vts/functional/ValidateModel.cpp
index 5ffbd43..34bc962 100644
--- a/neuralnetworks/1.0/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.0/vts/functional/ValidateModel.cpp
@@ -232,26 +232,24 @@
// currently 1Mb, which is shared by all transactions in progress
// for the process."
//
-// Will our representation fit under this limit? There are two complications:
+// Will our representation fit under this limit? There are three complications:
// - Our representation size is just approximate (see sizeForBinder()).
-// - This object may not be the only occupant of the Binder transaction buffer.
+// - This object may not be the only occupant of the Binder transaction buffer
+// (although our VTS test suite should not be putting multiple objects in the
+// buffer at once).
+// - IBinder.MAX_IPC_SIZE recommends limiting a transaction to 64 * 1024 bytes.
// So we'll be very conservative: We want the representation size to be no
-// larger than half the transaction buffer size.
+// larger than half the recommended limit.
//
// If our representation grows large enough that it still fits within
// the transaction buffer but combined with other transactions may
// exceed the buffer size, then we may see intermittent HAL transport
// errors.
static bool exceedsBinderSizeLimit(size_t representationSize) {
- // Instead of using this fixed buffer size, we might instead be able to use
- // ProcessState::self()->getMmapSize(). However, this has a potential
- // problem: The binder/mmap size of the current process does not necessarily
- // indicate the binder/mmap size of the service (i.e., the other process).
- // The only way it would be a good indication is if both the current process
- // and the service use the default size.
- static const size_t kHalfBufferSize = 1024 * 1024 / 2;
+ // There is no C++ API to retrieve the value of the Java variable IBinder.MAX_IPC_SIZE.
+ static const size_t kHalfMaxIPCSize = 64 * 1024 / 2;
- return representationSize > kHalfBufferSize;
+ return representationSize > kHalfMaxIPCSize;
}
///////////////////////// VALIDATE EXECUTION ORDER ////////////////////////////
diff --git a/neuralnetworks/1.1/vts/functional/Android.bp b/neuralnetworks/1.1/vts/functional/Android.bp
index e9d4b76..7c1c118 100644
--- a/neuralnetworks/1.1/vts/functional/Android.bp
+++ b/neuralnetworks/1.1/vts/functional/Android.bp
@@ -58,7 +58,6 @@
"libneuralnetworks_headers",
],
test_suites: [
- "general-tests",
"vts",
],
}
diff --git a/neuralnetworks/1.1/vts/functional/ValidateModel.cpp b/neuralnetworks/1.1/vts/functional/ValidateModel.cpp
index 1f4e4ed..dbabbaf 100644
--- a/neuralnetworks/1.1/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.1/vts/functional/ValidateModel.cpp
@@ -252,26 +252,24 @@
// currently 1Mb, which is shared by all transactions in progress
// for the process."
//
-// Will our representation fit under this limit? There are two complications:
+// Will our representation fit under this limit? There are three complications:
// - Our representation size is just approximate (see sizeForBinder()).
-// - This object may not be the only occupant of the Binder transaction buffer.
+// - This object may not be the only occupant of the Binder transaction buffer
+// (although our VTS test suite should not be putting multiple objects in the
+// buffer at once).
+// - IBinder.MAX_IPC_SIZE recommends limiting a transaction to 64 * 1024 bytes.
// So we'll be very conservative: We want the representation size to be no
-// larger than half the transaction buffer size.
+// larger than half the recommended limit.
//
// If our representation grows large enough that it still fits within
// the transaction buffer but combined with other transactions may
// exceed the buffer size, then we may see intermittent HAL transport
// errors.
static bool exceedsBinderSizeLimit(size_t representationSize) {
- // Instead of using this fixed buffer size, we might instead be able to use
- // ProcessState::self()->getMmapSize(). However, this has a potential
- // problem: The binder/mmap size of the current process does not necessarily
- // indicate the binder/mmap size of the service (i.e., the other process).
- // The only way it would be a good indication is if both the current process
- // and the service use the default size.
- static const size_t kHalfBufferSize = 1024 * 1024 / 2;
+ // There is no C++ API to retrieve the value of the Java variable IBinder.MAX_IPC_SIZE.
+ static const size_t kHalfMaxIPCSize = 64 * 1024 / 2;
- return representationSize > kHalfBufferSize;
+ return representationSize > kHalfMaxIPCSize;
}
///////////////////////// VALIDATE EXECUTION ORDER ////////////////////////////
diff --git a/neuralnetworks/1.2/vts/functional/Android.bp b/neuralnetworks/1.2/vts/functional/Android.bp
index 2177924..7e4b5bb 100644
--- a/neuralnetworks/1.2/vts/functional/Android.bp
+++ b/neuralnetworks/1.2/vts/functional/Android.bp
@@ -85,7 +85,6 @@
"libneuralnetworks_headers",
],
test_suites: [
- "general-tests",
"vts",
],
}
diff --git a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
index 3d783d9..fe38e61 100644
--- a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
+++ b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
@@ -1262,7 +1262,7 @@
FILE* pFile = fopen(filename.c_str(), "a");
uint32_t appendLength = getRandomInt(1, 256);
for (uint32_t i = 0; i < appendLength; i++) {
- ASSERT_NE(fputc(getRandomInt<uint8_t>(0, 255), pFile), EOF);
+ ASSERT_NE(fputc(getRandomInt<uint16_t>(0, 255), pFile), EOF);
}
fclose(pFile);
*skip = false;
diff --git a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
index 3375602..d7cd6f5 100644
--- a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
@@ -291,26 +291,24 @@
// currently 1Mb, which is shared by all transactions in progress
// for the process."
//
-// Will our representation fit under this limit? There are two complications:
+// Will our representation fit under this limit? There are three complications:
// - Our representation size is just approximate (see sizeForBinder()).
-// - This object may not be the only occupant of the Binder transaction buffer.
+// - This object may not be the only occupant of the Binder transaction buffer
+// (although our VTS test suite should not be putting multiple objects in the
+// buffer at once).
+// - IBinder.MAX_IPC_SIZE recommends limiting a transaction to 64 * 1024 bytes.
// So we'll be very conservative: We want the representation size to be no
-// larger than half the transaction buffer size.
+// larger than half the recommended limit.
//
// If our representation grows large enough that it still fits within
// the transaction buffer but combined with other transactions may
// exceed the buffer size, then we may see intermittent HAL transport
// errors.
static bool exceedsBinderSizeLimit(size_t representationSize) {
- // Instead of using this fixed buffer size, we might instead be able to use
- // ProcessState::self()->getMmapSize(). However, this has a potential
- // problem: The binder/mmap size of the current process does not necessarily
- // indicate the binder/mmap size of the service (i.e., the other process).
- // The only way it would be a good indication is if both the current process
- // and the service use the default size.
- static const size_t kHalfBufferSize = 1024 * 1024 / 2;
+ // There is no C++ API to retrieve the value of the Java variable IBinder.MAX_IPC_SIZE.
+ static const size_t kHalfMaxIPCSize = 64 * 1024 / 2;
- return representationSize > kHalfBufferSize;
+ return representationSize > kHalfMaxIPCSize;
}
///////////////////////// VALIDATE EXECUTION ORDER ////////////////////////////
diff --git a/neuralnetworks/1.3/vts/functional/Android.bp b/neuralnetworks/1.3/vts/functional/Android.bp
index 9fa0f0a..07071cc 100644
--- a/neuralnetworks/1.3/vts/functional/Android.bp
+++ b/neuralnetworks/1.3/vts/functional/Android.bp
@@ -92,7 +92,6 @@
"libneuralnetworks_headers",
],
test_suites: [
- "general-tests",
"vts",
],
}
diff --git a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
index a2013ec..f2cfa3f 100644
--- a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
+++ b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
@@ -1253,7 +1253,7 @@
FILE* pFile = fopen(filename.c_str(), "a");
uint32_t appendLength = getRandomInt(1, 256);
for (uint32_t i = 0; i < appendLength; i++) {
- ASSERT_NE(fputc(getRandomInt<uint8_t>(0, 255), pFile), EOF);
+ ASSERT_NE(fputc(getRandomInt<uint16_t>(0, 255), pFile), EOF);
}
fclose(pFile);
*skip = false;
diff --git a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
index 849ef7b..d8c7cd1 100644
--- a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
@@ -308,26 +308,24 @@
// currently 1Mb, which is shared by all transactions in progress
// for the process."
//
-// Will our representation fit under this limit? There are two complications:
+// Will our representation fit under this limit? There are three complications:
// - Our representation size is just approximate (see sizeForBinder()).
-// - This object may not be the only occupant of the Binder transaction buffer.
+// - This object may not be the only occupant of the Binder transaction buffer
+// (although our VTS test suite should not be putting multiple objects in the
+// buffer at once).
+// - IBinder.MAX_IPC_SIZE recommends limiting a transaction to 64 * 1024 bytes.
// So we'll be very conservative: We want the representation size to be no
-// larger than half the transaction buffer size.
+// larger than half the recommended limit.
//
// If our representation grows large enough that it still fits within
// the transaction buffer but combined with other transactions may
// exceed the buffer size, then we may see intermittent HAL transport
// errors.
static bool exceedsBinderSizeLimit(size_t representationSize) {
- // Instead of using this fixed buffer size, we might instead be able to use
- // ProcessState::self()->getMmapSize(). However, this has a potential
- // problem: The binder/mmap size of the current process does not necessarily
- // indicate the binder/mmap size of the service (i.e., the other process).
- // The only way it would be a good indication is if both the current process
- // and the service use the default size.
- static const size_t kHalfBufferSize = 1024 * 1024 / 2;
+ // There is no C++ API to retrieve the value of the Java variable IBinder.MAX_IPC_SIZE.
+ static const size_t kHalfMaxIPCSize = 64 * 1024 / 2;
- return representationSize > kHalfBufferSize;
+ return representationSize > kHalfMaxIPCSize;
}
///////////////////////// VALIDATE EXECUTION ORDER ////////////////////////////
diff --git a/neuralnetworks/TEST_MAPPING b/neuralnetworks/TEST_MAPPING
index d296828..3218206 100644
--- a/neuralnetworks/TEST_MAPPING
+++ b/neuralnetworks/TEST_MAPPING
@@ -17,54 +17,10 @@
},
{
"name": "neuralnetworks_utils_hal_aidl_test"
- },
- {
- "name": "VtsHalNeuralnetworksV1_0TargetTest",
- "options": [
- {
- // Do not use any sample driver except sample-all in order to reduce
- // testing time. The other sample drivers (fast-float, quant, etc.)
- // are subsets of sample-all.
- "include-filter": "-*sample_float_fast*:*sample_float_slow*:*sample_minimal*:*sample_quant*"
- }
- ]
- },
- {
- "name": "VtsHalNeuralnetworksV1_1TargetTest",
- "options": [
- {
- // Do not use any sample driver except sample-all in order to reduce
- // testing time. The other sample drivers (fast-float, quant, etc.)
- // are subsets of sample-all.
- "include-filter": "-*sample_float_fast*:*sample_float_slow*:*sample_minimal*:*sample_quant*"
- }
- ]
}
],
"presubmit-large": [
{
- "name": "VtsHalNeuralnetworksV1_2TargetTest",
- "options": [
- {
- // Do not use any sample driver except sample-all in order to reduce
- // testing time. The other sample drivers (fast-float, quant, etc.)
- // are subsets of sample-all.
- "include-filter": "-*sample_float_fast*:*sample_float_slow*:*sample_minimal*:*sample_quant*"
- }
- ]
- },
- {
- "name": "VtsHalNeuralnetworksV1_3TargetTest",
- "options": [
- {
- // Do not use any sample driver except sample-all in order to reduce
- // testing time. The other sample drivers (fast-float, quant, etc.)
- // are subsets of sample-all.
- "include-filter": "-*sample_float_fast*:*sample_float_slow*:*sample_minimal*:*sample_quant*"
- }
- ]
- },
- {
"name": "VtsHalNeuralnetworksTargetTest",
"options": [
{
diff --git a/neuralnetworks/aidl/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/aidl/vts/functional/CompilationCachingTests.cpp
index 7451f7e..da0fe64 100644
--- a/neuralnetworks/aidl/vts/functional/CompilationCachingTests.cpp
+++ b/neuralnetworks/aidl/vts/functional/CompilationCachingTests.cpp
@@ -1068,7 +1068,7 @@
FILE* pFile = fopen(filename.c_str(), "a");
uint32_t appendLength = getRandomInt(1, 256);
for (uint32_t i = 0; i < appendLength; i++) {
- ASSERT_NE(fputc(getRandomInt<uint8_t>(0, 255), pFile), EOF);
+ ASSERT_NE(fputc(getRandomInt<uint16_t>(0, 255), pFile), EOF);
}
fclose(pFile);
*skip = false;
diff --git a/neuralnetworks/aidl/vts/functional/ValidateModel.cpp b/neuralnetworks/aidl/vts/functional/ValidateModel.cpp
index 060434e..d7baf19 100644
--- a/neuralnetworks/aidl/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/aidl/vts/functional/ValidateModel.cpp
@@ -344,26 +344,24 @@
// currently 1Mb, which is shared by all transactions in progress
// for the process."
//
-// Will our representation fit under this limit? There are two complications:
+// Will our representation fit under this limit? There are three complications:
// - Our representation size is just approximate (see sizeForBinder()).
-// - This object may not be the only occupant of the Binder transaction buffer.
+// - This object may not be the only occupant of the Binder transaction buffer
+// (although our VTS test suite should not be putting multiple objects in the
+// buffer at once).
+// - IBinder.MAX_IPC_SIZE recommends limiting a transaction to 64 * 1024 bytes.
// So we'll be very conservative: We want the representation size to be no
-// larger than half the transaction buffer size.
+// larger than half the recommended limit.
//
// If our representation grows large enough that it still fits within
// the transaction buffer but combined with other transactions may
// exceed the buffer size, then we may see intermittent HAL transport
// errors.
static bool exceedsBinderSizeLimit(size_t representationSize) {
- // Instead of using this fixed buffer size, we might instead be able to use
- // ProcessState::self()->getMmapSize(). However, this has a potential
- // problem: The binder/mmap size of the current process does not necessarily
- // indicate the binder/mmap size of the service (i.e., the other process).
- // The only way it would be a good indication is if both the current process
- // and the service use the default size.
- static const size_t kHalfBufferSize = 1024 * 1024 / 2;
+ // There is no C++ API to retrieve the value of the Java variable IBinder.MAX_IPC_SIZE.
+ static const size_t kHalfMaxIPCSize = 64 * 1024 / 2;
- return representationSize > kHalfBufferSize;
+ return representationSize > kHalfMaxIPCSize;
}
///////////////////////// VALIDATE EXECUTION ORDER ////////////////////////////
diff --git a/nfc/aidl/Android.bp b/nfc/aidl/Android.bp
index b9578f4..09a45d1 100644
--- a/nfc/aidl/Android.bp
+++ b/nfc/aidl/Android.bp
@@ -34,11 +34,6 @@
sdk_version: "module_current",
enabled: false,
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
versions_with_info: [
{
diff --git a/oemlock/aidl/Android.bp b/oemlock/aidl/Android.bp
index d1930f9..1c19bb1 100644
--- a/oemlock/aidl/Android.bp
+++ b/oemlock/aidl/Android.bp
@@ -16,11 +16,6 @@
java: {
platform_apis: true,
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
versions: ["1"],
}
diff --git a/oemlock/aidl/default/OemLock.cpp b/oemlock/aidl/default/OemLock.cpp
index 646b532..234a8a9 100644
--- a/oemlock/aidl/default/OemLock.cpp
+++ b/oemlock/aidl/default/OemLock.cpp
@@ -24,29 +24,31 @@
// Methods from ::android::hardware::oemlock::IOemLock follow.
::ndk::ScopedAStatus OemLock::getName(std::string *out_name) {
- (void)out_name;
+ *out_name = "SomeCoolName";
return ::ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus OemLock::setOemUnlockAllowedByCarrier(bool in_allowed, const std::vector<uint8_t> &in_signature, OemLockSecureStatus *_aidl_return) {
- (void)in_allowed;
+ // Default impl doesn't care about a valid vendor signature
(void)in_signature;
- (void)_aidl_return;
+
+ mAllowedByCarrier = in_allowed;
+ *_aidl_return = OemLockSecureStatus::OK;
return ::ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus OemLock::isOemUnlockAllowedByCarrier(bool *out_allowed) {
- (void)out_allowed;
+ *out_allowed = mAllowedByCarrier;
return ::ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus OemLock::setOemUnlockAllowedByDevice(bool in_allowed) {
- (void)in_allowed;
+ mAllowedByDevice = in_allowed;
return ::ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus OemLock::isOemUnlockAllowedByDevice(bool *out_allowed) {
- (void)out_allowed;
+ *out_allowed = mAllowedByDevice;
return ::ndk::ScopedAStatus::ok();
}
diff --git a/oemlock/aidl/default/OemLock.h b/oemlock/aidl/default/OemLock.h
index b0df414..9dff21a 100644
--- a/oemlock/aidl/default/OemLock.h
+++ b/oemlock/aidl/default/OemLock.h
@@ -36,6 +36,10 @@
::ndk::ScopedAStatus isOemUnlockAllowedByDevice(bool* out_allowed) override;
::ndk::ScopedAStatus setOemUnlockAllowedByCarrier(bool in_allowed, const std::vector<uint8_t>& in_signature, OemLockSecureStatus* _aidl_return) override;
::ndk::ScopedAStatus setOemUnlockAllowedByDevice(bool in_allowed) override;
+
+ private:
+ bool mAllowedByCarrier = false;
+ bool mAllowedByDevice = false;
};
} // namespace oemlock
diff --git a/power/OWNERS b/power/OWNERS
new file mode 100644
index 0000000..7229b22
--- /dev/null
+++ b/power/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 826709
+
+# ADPF virtual team
+lpy@google.com
+wvw@google.com
diff --git a/power/TEST_MAPPING b/power/TEST_MAPPING
new file mode 100644
index 0000000..c0963f9
--- /dev/null
+++ b/power/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "VtsHalPowerTargetTest"
+ }
+ ]
+}
diff --git a/power/aidl/Android.bp b/power/aidl/Android.bp
index e4708f8..70b1203 100644
--- a/power/aidl/Android.bp
+++ b/power/aidl/Android.bp
@@ -35,11 +35,6 @@
java: {
platform_apis: true,
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
versions_with_info: [
{
diff --git a/power/aidl/default/Android.bp b/power/aidl/default/Android.bp
index 223b9d5..b321394 100644
--- a/power/aidl/default/Android.bp
+++ b/power/aidl/default/Android.bp
@@ -35,6 +35,7 @@
srcs: [
"main.cpp",
"Power.cpp",
+ "PowerHintSession.cpp",
],
}
diff --git a/power/aidl/default/Power.cpp b/power/aidl/default/Power.cpp
index 7f08f44..8fe370c 100644
--- a/power/aidl/default/Power.cpp
+++ b/power/aidl/default/Power.cpp
@@ -15,6 +15,7 @@
*/
#include "Power.h"
+#include "PowerHintSession.h"
#include <android-base/logging.h>
@@ -25,42 +26,53 @@
namespace impl {
namespace example {
+using namespace std::chrono_literals;
+
+using ndk::ScopedAStatus;
+
const std::vector<Boost> BOOST_RANGE{ndk::enum_range<Boost>().begin(),
ndk::enum_range<Boost>().end()};
const std::vector<Mode> MODE_RANGE{ndk::enum_range<Mode>().begin(), ndk::enum_range<Mode>().end()};
-ndk::ScopedAStatus Power::setMode(Mode type, bool enabled) {
+ScopedAStatus Power::setMode(Mode type, bool enabled) {
LOG(VERBOSE) << "Power setMode: " << static_cast<int32_t>(type) << " to: " << enabled;
- return ndk::ScopedAStatus::ok();
+ return ScopedAStatus::ok();
}
-ndk::ScopedAStatus Power::isModeSupported(Mode type, bool* _aidl_return) {
+ScopedAStatus Power::isModeSupported(Mode type, bool* _aidl_return) {
LOG(INFO) << "Power isModeSupported: " << static_cast<int32_t>(type);
*_aidl_return = type >= MODE_RANGE.front() && type <= MODE_RANGE.back();
- return ndk::ScopedAStatus::ok();
+ return ScopedAStatus::ok();
}
-ndk::ScopedAStatus Power::setBoost(Boost type, int32_t durationMs) {
+ScopedAStatus Power::setBoost(Boost type, int32_t durationMs) {
LOG(VERBOSE) << "Power setBoost: " << static_cast<int32_t>(type)
<< ", duration: " << durationMs;
- return ndk::ScopedAStatus::ok();
+ return ScopedAStatus::ok();
}
-ndk::ScopedAStatus Power::isBoostSupported(Boost type, bool* _aidl_return) {
+ScopedAStatus Power::isBoostSupported(Boost type, bool* _aidl_return) {
LOG(INFO) << "Power isBoostSupported: " << static_cast<int32_t>(type);
*_aidl_return = type >= BOOST_RANGE.front() && type <= BOOST_RANGE.back();
- return ndk::ScopedAStatus::ok();
+ return ScopedAStatus::ok();
}
-ndk::ScopedAStatus Power::createHintSession(int32_t, int32_t, const std::vector<int32_t>&, int64_t,
- std::shared_ptr<IPowerHintSession>* _aidl_return) {
- *_aidl_return = nullptr;
- return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ScopedAStatus Power::createHintSession(int32_t, int32_t, const std::vector<int32_t>& tids, int64_t,
+ std::shared_ptr<IPowerHintSession>* _aidl_return) {
+ if (tids.size() == 0) {
+ *_aidl_return = nullptr;
+ return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ std::shared_ptr<IPowerHintSession> powerHintSession =
+ ndk::SharedRefBase::make<PowerHintSession>();
+ mPowerHintSessions.push_back(powerHintSession);
+ *_aidl_return = powerHintSession;
+ return ScopedAStatus::ok();
}
-ndk::ScopedAStatus Power::getHintSessionPreferredRate(int64_t* outNanoseconds) {
- *outNanoseconds = -1;
- return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ScopedAStatus Power::getHintSessionPreferredRate(int64_t* outNanoseconds) {
+ *outNanoseconds = std::chrono::nanoseconds(1ms).count();
+ return ScopedAStatus::ok();
}
} // namespace example
diff --git a/power/aidl/default/Power.h b/power/aidl/default/Power.h
index ef6439d..7f8405e 100644
--- a/power/aidl/default/Power.h
+++ b/power/aidl/default/Power.h
@@ -26,6 +26,7 @@
namespace example {
class Power : public BnPower {
+ public:
ndk::ScopedAStatus setMode(Mode type, bool enabled) override;
ndk::ScopedAStatus isModeSupported(Mode type, bool* _aidl_return) override;
ndk::ScopedAStatus setBoost(Boost type, int32_t durationMs) override;
@@ -35,6 +36,9 @@
int64_t durationNanos,
std::shared_ptr<IPowerHintSession>* _aidl_return) override;
ndk::ScopedAStatus getHintSessionPreferredRate(int64_t* outNanoseconds) override;
+
+ private:
+ std::vector<std::shared_ptr<IPowerHintSession>> mPowerHintSessions;
};
} // namespace example
diff --git a/power/aidl/default/PowerHintSession.cpp b/power/aidl/default/PowerHintSession.cpp
new file mode 100644
index 0000000..17fd26a
--- /dev/null
+++ b/power/aidl/default/PowerHintSession.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "PowerHintSession.h"
+
+#include <android-base/logging.h>
+
+namespace aidl::android::hardware::power::impl::example {
+
+using ndk::ScopedAStatus;
+
+PowerHintSession::PowerHintSession() {}
+
+ScopedAStatus PowerHintSession::updateTargetWorkDuration(int64_t targetDurationNanos) {
+ LOG(VERBOSE) << __func__ << "target duration in nanoseconds: " << targetDurationNanos;
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus PowerHintSession::reportActualWorkDuration(
+ const std::vector<WorkDuration>& /* durations */) {
+ LOG(VERBOSE) << __func__;
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus PowerHintSession::pause() {
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus PowerHintSession::resume() {
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus PowerHintSession::close() {
+ return ScopedAStatus::ok();
+}
+
+} // namespace aidl::android::hardware::power::impl::example
diff --git a/power/aidl/default/PowerHintSession.h b/power/aidl/default/PowerHintSession.h
new file mode 100644
index 0000000..b7bf54c
--- /dev/null
+++ b/power/aidl/default/PowerHintSession.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/power/BnPowerHintSession.h>
+#include <aidl/android/hardware/power/WorkDuration.h>
+
+namespace aidl::android::hardware::power::impl::example {
+
+class PowerHintSession : public BnPowerHintSession {
+ public:
+ explicit PowerHintSession();
+ ndk::ScopedAStatus updateTargetWorkDuration(int64_t targetDurationNanos) override;
+ ndk::ScopedAStatus reportActualWorkDuration(
+ const std::vector<WorkDuration>& durations) override;
+ ndk::ScopedAStatus pause() override;
+ ndk::ScopedAStatus resume() override;
+ ndk::ScopedAStatus close() override;
+};
+
+} // namespace aidl::android::hardware::power::impl::example
diff --git a/power/aidl/vts/Android.bp b/power/aidl/vts/Android.bp
index ea398ac..4e8f517 100644
--- a/power/aidl/vts/Android.bp
+++ b/power/aidl/vts/Android.bp
@@ -35,6 +35,7 @@
"android.hardware.power-V3-ndk",
],
test_suites: [
+ "general-tests",
"vts",
],
}
diff --git a/power/aidl/vts/VtsHalPowerTargetTest.cpp b/power/aidl/vts/VtsHalPowerTargetTest.cpp
index 2cfa04a..b81dd8f 100644
--- a/power/aidl/vts/VtsHalPowerTargetTest.cpp
+++ b/power/aidl/vts/VtsHalPowerTargetTest.cpp
@@ -83,6 +83,14 @@
DurationWrapper(1000000000L, 4L),
};
+// DEVICEs launching with Android 11 MUST meet the requirements for the
+// target-level=5 compatibility_matrix file.
+const uint64_t kCompatibilityMatrix5ApiLevel = 30;
+
+// DEVICEs launching with Android 13 MUST meet the requirements for the
+// target-level=7 compatibility_matrix file.
+const uint64_t kCompatibilityMatrix7ApiLevel = 33;
+
inline bool isUnknownOrUnsupported(const ndk::ScopedAStatus& status) {
return status.getStatus() == STATUS_UNKNOWN_TRANSACTION ||
status.getExceptionCode() == EX_UNSUPPORTED_OPERATION;
@@ -94,9 +102,13 @@
AIBinder* binder = AServiceManager_waitForService(GetParam().c_str());
ASSERT_NE(binder, nullptr);
power = IPower::fromBinder(ndk::SpAIBinder(binder));
+
+ mApiLevel = GetUintProperty<uint64_t>("ro.vendor.api_level", 0);
+ ASSERT_NE(mApiLevel, 0);
}
std::shared_ptr<IPower> power;
+ uint64_t mApiLevel;
};
TEST_P(PowerAidl, setMode) {
@@ -152,11 +164,11 @@
TEST_P(PowerAidl, getHintSessionPreferredRate) {
int64_t rate = -1;
auto status = power->getHintSessionPreferredRate(&rate);
- if (!status.isOk()) {
+ if (mApiLevel < kCompatibilityMatrix7ApiLevel && !status.isOk()) {
EXPECT_TRUE(isUnknownOrUnsupported(status));
- return;
+ GTEST_SKIP() << "DEVICE not launching with Android 13 and beyond.";
}
-
+ ASSERT_TRUE(status.isOk());
// At least 1ms rate limit from HAL
ASSERT_GE(rate, 1000000);
}
@@ -164,10 +176,11 @@
TEST_P(PowerAidl, createAndCloseHintSession) {
std::shared_ptr<IPowerHintSession> session;
auto status = power->createHintSession(getpid(), getuid(), kSelfTids, 16666666L, &session);
- if (!status.isOk()) {
+ if (mApiLevel < kCompatibilityMatrix7ApiLevel && !status.isOk()) {
EXPECT_TRUE(isUnknownOrUnsupported(status));
- return;
+ GTEST_SKIP() << "DEVICE not launching with Android 13 and beyond.";
}
+ ASSERT_TRUE(status.isOk());
ASSERT_NE(nullptr, session);
ASSERT_TRUE(session->pause().isOk());
ASSERT_TRUE(session->resume().isOk());
@@ -175,12 +188,18 @@
ASSERT_TRUE(session->close().isOk());
session.reset();
}
+
TEST_P(PowerAidl, createHintSessionFailed) {
std::shared_ptr<IPowerHintSession> session;
auto status = power->createHintSession(getpid(), getuid(), kEmptyTids, 16666666L, &session);
+
+ // Regardless of whether V2 and beyond is supported, the status is always not STATUS_OK.
ASSERT_FALSE(status.isOk());
- if (isUnknownOrUnsupported(status)) {
- return;
+
+ // If device not launching with Android 13 and beyond, check whether it's supported,
+ // if not, skip the test.
+ if (mApiLevel < kCompatibilityMatrix7ApiLevel && isUnknownOrUnsupported(status)) {
+ GTEST_SKIP() << "DEVICE not launching with Android 13 and beyond.";
}
ASSERT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode());
}
@@ -188,10 +207,11 @@
TEST_P(PowerAidl, updateAndReportDurations) {
std::shared_ptr<IPowerHintSession> session;
auto status = power->createHintSession(getpid(), getuid(), kSelfTids, 16666666L, &session);
- if (!status.isOk()) {
+ if (mApiLevel < kCompatibilityMatrix7ApiLevel && !status.isOk()) {
EXPECT_TRUE(isUnknownOrUnsupported(status));
- return;
+ GTEST_SKIP() << "DEVICE not launching with Android 13 and beyond.";
}
+ ASSERT_TRUE(status.isOk());
ASSERT_NE(nullptr, session);
ASSERT_TRUE(session->updateTargetWorkDuration(16666667LL).isOk());
@@ -201,14 +221,13 @@
// FIXED_PERFORMANCE mode is required for all devices which ship on Android 11
// or later
TEST_P(PowerAidl, hasFixedPerformance) {
- auto apiLevel = GetUintProperty<uint64_t>("ro.vendor.api_level", 0);
- ASSERT_NE(apiLevel, 0);
-
- if (apiLevel >= 30) {
- bool supported;
- ASSERT_TRUE(power->isModeSupported(Mode::FIXED_PERFORMANCE, &supported).isOk());
- ASSERT_TRUE(supported);
+ if (mApiLevel < kCompatibilityMatrix5ApiLevel) {
+ GTEST_SKIP() << "FIXED_PERFORMANCE mode is only required for all devices launching Android "
+ "11 or later.";
}
+ bool supported;
+ ASSERT_TRUE(power->isModeSupported(Mode::FIXED_PERFORMANCE, &supported).isOk());
+ ASSERT_TRUE(supported);
}
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(PowerAidl);
diff --git a/power/stats/aidl/Android.bp b/power/stats/aidl/Android.bp
index 48d3c51..b1b2515 100644
--- a/power/stats/aidl/Android.bp
+++ b/power/stats/aidl/Android.bp
@@ -32,11 +32,6 @@
java: {
platform_apis: true,
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
cpp: {
enabled: true,
},
diff --git a/power/stats/aidl/OWNERS b/power/stats/aidl/OWNERS
index b290b49..e0d66d7 100644
--- a/power/stats/aidl/OWNERS
+++ b/power/stats/aidl/OWNERS
@@ -1,3 +1,4 @@
-bsschwar@google.com
+darrenhsu@google.com
+joaodias@google.com
krossmo@google.com
-tstrudel@google.com
+vincentwang@google.com
diff --git a/radio/1.0/Android.bp b/radio/1.0/Android.bp
index 8d0d782..e49a50d 100644
--- a/radio/1.0/Android.bp
+++ b/radio/1.0/Android.bp
@@ -25,7 +25,7 @@
],
apex_available: [
"//apex_available:platform",
- "com.android.bluetooth",
+ "com.android.btservices",
],
gen_java: true,
}
diff --git a/radio/aidl/Android.bp b/radio/aidl/Android.bp
index 72f160d..98eafc1 100644
--- a/radio/aidl/Android.bp
+++ b/radio/aidl/Android.bp
@@ -20,11 +20,6 @@
java: {
sdk_version: "module_current",
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
versions_with_info: [
{
@@ -49,11 +44,6 @@
java: {
sdk_version: "module_current",
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
versions_with_info: [
{
@@ -78,11 +68,6 @@
java: {
sdk_version: "module_current",
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
versions_with_info: [
{
@@ -107,11 +92,6 @@
java: {
sdk_version: "module_current",
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
versions_with_info: [
{
@@ -136,11 +116,6 @@
java: {
sdk_version: "module_current",
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
versions_with_info: [
{
@@ -165,11 +140,6 @@
java: {
sdk_version: "module_current",
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
versions_with_info: [
{
@@ -197,11 +167,6 @@
java: {
sdk_version: "module_current",
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
versions_with_info: [
{
@@ -229,11 +194,6 @@
java: {
sdk_version: "module_current",
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
versions_with_info: [
{
diff --git a/radio/aidl/OWNERS b/radio/aidl/OWNERS
new file mode 100644
index 0000000..7b01aad
--- /dev/null
+++ b/radio/aidl/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 20868
+include ../1.0/vts/OWNERS
+
diff --git a/radio/aidl/compat/libradiocompat/data/structs.cpp b/radio/aidl/compat/libradiocompat/data/structs.cpp
index 4ff89a1..cc6dcbc 100644
--- a/radio/aidl/compat/libradiocompat/data/structs.cpp
+++ b/radio/aidl/compat/libradiocompat/data/structs.cpp
@@ -28,14 +28,14 @@
V1_5::DataProfileInfo toHidl(const aidl::DataProfileInfo& info) {
return {
- .profileId = V1_0::DataProfileId{info.profileId},
+ .profileId = static_cast<V1_0::DataProfileId>(info.profileId),
.apn = info.apn,
- .protocol = V1_4::PdpProtocolType{info.protocol},
- .roamingProtocol = V1_4::PdpProtocolType{info.roamingProtocol},
- .authType = V1_0::ApnAuthType{info.authType},
+ .protocol = static_cast<V1_4::PdpProtocolType>(info.protocol),
+ .roamingProtocol = static_cast<V1_4::PdpProtocolType>(info.roamingProtocol),
+ .authType = static_cast<V1_0::ApnAuthType>(info.authType),
.user = info.user,
.password = info.password,
- .type = V1_0::DataProfileInfoType{info.type},
+ .type = static_cast<V1_0::DataProfileInfoType>(info.type),
.maxConnsTime = info.maxConnsTime,
.maxConns = info.maxConns,
.waitTime = info.waitTime,
@@ -74,7 +74,7 @@
.sliceDifferentiator = info.sliceDifferentiator,
.mappedHplmnSst = static_cast<V1_6::SliceServiceType>(info.mappedHplmnSst),
.mappedHplmnSD = info.mappedHplmnSd,
- .status = V1_6::SliceStatus{info.status},
+ .status = static_cast<V1_6::SliceStatus>(info.status),
};
}
@@ -106,7 +106,7 @@
V1_1::KeepaliveRequest toHidl(const aidl::KeepaliveRequest& keep) {
return {
- .type = V1_1::KeepaliveType{keep.type},
+ .type = static_cast<V1_1::KeepaliveType>(keep.type),
.sourceAddress = keep.sourceAddress,
.sourcePort = keep.sourcePort,
.destinationAddress = keep.destinationAddress,
diff --git a/radio/aidl/compat/libradiocompat/messaging/structs.cpp b/radio/aidl/compat/libradiocompat/messaging/structs.cpp
index 9019680..f30c5ce 100644
--- a/radio/aidl/compat/libradiocompat/messaging/structs.cpp
+++ b/radio/aidl/compat/libradiocompat/messaging/structs.cpp
@@ -45,11 +45,11 @@
static V1_0::CdmaSmsAddress toHidl(const aidl::CdmaSmsAddress& addr) {
return {
- .digitMode = V1_0::CdmaSmsDigitMode{addr.digitMode},
+ .digitMode = static_cast<V1_0::CdmaSmsDigitMode>(addr.digitMode),
.numberMode = addr.isNumberModeDataNetwork ? V1_0::CdmaSmsNumberMode::DATA_NETWORK
: V1_0::CdmaSmsNumberMode::NOT_DATA_NETWORK,
- .numberType = V1_0::CdmaSmsNumberType{addr.numberType},
- .numberPlan = V1_0::CdmaSmsNumberPlan{addr.numberPlan},
+ .numberType = static_cast<V1_0::CdmaSmsNumberType>(addr.numberType),
+ .numberPlan = static_cast<V1_0::CdmaSmsNumberPlan>(addr.numberPlan),
.digits = addr.digits,
};
}
@@ -64,7 +64,7 @@
static V1_0::CdmaSmsSubaddress toHidl(const aidl::CdmaSmsSubaddress& addr) {
return {
- .subaddressType = V1_0::CdmaSmsSubaddressType{addr.subaddressType},
+ .subaddressType = static_cast<V1_0::CdmaSmsSubaddressType>(addr.subaddressType),
.odd = addr.odd,
.digits = addr.digits,
};
@@ -94,7 +94,7 @@
V1_0::ImsSmsMessage toHidl(const aidl::ImsSmsMessage& msg) {
return {
- .tech = V1_0::RadioTechnologyFamily{msg.tech},
+ .tech = static_cast<V1_0::RadioTechnologyFamily>(msg.tech),
.retry = msg.retry,
.messageRef = msg.messageRef,
.cdmaMessage = toHidl(msg.cdmaMessage),
@@ -147,14 +147,14 @@
V1_0::CdmaSmsWriteArgs toHidl(const aidl::CdmaSmsWriteArgs& args) {
return {
- .status = V1_0::CdmaSmsWriteArgsStatus{args.status},
+ .status = static_cast<V1_0::CdmaSmsWriteArgsStatus>(args.status),
.message = toHidl(args.message),
};
}
V1_0::SmsWriteArgs toHidl(const aidl::SmsWriteArgs& args) {
return {
- .status = V1_0::SmsWriteArgsStatus{args.status},
+ .status = static_cast<V1_0::SmsWriteArgsStatus>(args.status),
.pdu = args.pdu,
.smsc = args.smsc,
};
diff --git a/radio/aidl/compat/libradiocompat/modem/structs.cpp b/radio/aidl/compat/libradiocompat/modem/structs.cpp
index 69e651b..6f32cdf 100644
--- a/radio/aidl/compat/libradiocompat/modem/structs.cpp
+++ b/radio/aidl/compat/libradiocompat/modem/structs.cpp
@@ -30,7 +30,7 @@
V1_0::NvWriteItem toHidl(const aidl::NvWriteItem& item) {
return {
- .itemId = V1_0::NvItem{item.itemId},
+ .itemId = static_cast<V1_0::NvItem>(item.itemId),
.value = item.value,
};
}
@@ -48,10 +48,10 @@
V1_0::RadioCapability toHidl(const aidl::RadioCapability& capa) {
return {
.session = capa.session,
- .phase = V1_0::RadioCapabilityPhase{capa.phase},
+ .phase = static_cast<V1_0::RadioCapabilityPhase>(capa.phase),
.raf = toHidlBitfield<V1_0::RadioAccessFamily>(capa.raf),
.logicalModemUuid = capa.logicalModemUuid,
- .status = V1_0::RadioCapabilityStatus{capa.status},
+ .status = static_cast<V1_0::RadioCapabilityStatus>(capa.status),
};
}
diff --git a/radio/aidl/compat/libradiocompat/network/structs.cpp b/radio/aidl/compat/libradiocompat/network/structs.cpp
index d0b3b90..30d4f6d 100644
--- a/radio/aidl/compat/libradiocompat/network/structs.cpp
+++ b/radio/aidl/compat/libradiocompat/network/structs.cpp
@@ -66,7 +66,7 @@
V1_5::SignalThresholdInfo toHidl(const aidl::SignalThresholdInfo& info) {
return {
- .signalMeasurement = V1_5::SignalMeasurementType{info.signalMeasurement},
+ .signalMeasurement = static_cast<V1_5::SignalMeasurementType>(info.signalMeasurement),
.hysteresisMs = info.hysteresisMs,
.hysteresisDb = info.hysteresisDb,
.thresholds = info.thresholds,
@@ -155,7 +155,7 @@
V1_5::NetworkScanRequest toHidl(const aidl::NetworkScanRequest& req) {
return {
- .type = V1_1::ScanType{req.type},
+ .type = static_cast<V1_1::ScanType>(req.type),
.interval = req.interval,
.specifiers = toHidl(req.specifiers),
.maxSearchTime = req.maxSearchTime,
diff --git a/radio/aidl/compat/libradiocompat/sim/structs.cpp b/radio/aidl/compat/libradiocompat/sim/structs.cpp
index bfbff02..00db2b8 100644
--- a/radio/aidl/compat/libradiocompat/sim/structs.cpp
+++ b/radio/aidl/compat/libradiocompat/sim/structs.cpp
@@ -65,7 +65,7 @@
return {
.mcc = carrier.mcc,
.mnc = carrier.mnc,
- .matchType = V1_0::CarrierMatchType{carrier.matchType},
+ .matchType = static_cast<V1_0::CarrierMatchType>(carrier.matchType),
.matchData = carrier.matchData,
};
}
@@ -107,7 +107,7 @@
V1_6::ImsiEncryptionInfo toHidl_1_6(const aidl::ImsiEncryptionInfo& info) {
return {
.base = toHidl(info),
- .keyType = V1_6::PublicKeyType{info.keyType},
+ .keyType = static_cast<V1_6::PublicKeyType>(info.keyType),
};
}
diff --git a/radio/aidl/compat/libradiocompat/voice/structs.cpp b/radio/aidl/compat/libradiocompat/voice/structs.cpp
index 254ea20..35c8d46 100644
--- a/radio/aidl/compat/libradiocompat/voice/structs.cpp
+++ b/radio/aidl/compat/libradiocompat/voice/structs.cpp
@@ -29,15 +29,15 @@
V1_0::Dial toHidl(const aidl::Dial& info) {
return {
.address = info.address,
- .clir = V1_0::Clir{info.clir},
+ .clir = static_cast<V1_0::Clir>(info.clir),
.uusInfo = toHidl(info.uusInfo),
};
}
V1_0::UusInfo toHidl(const aidl::UusInfo& info) {
return {
- .uusType = V1_0::UusType{info.uusType},
- .uusDcs = V1_0::UusDcs{info.uusDcs},
+ .uusType = static_cast<V1_0::UusType>(info.uusType),
+ .uusDcs = static_cast<V1_0::UusDcs>(info.uusDcs),
.uusData = info.uusData,
};
}
@@ -55,7 +55,7 @@
V1_0::CallForwardInfo toHidl(const aidl::CallForwardInfo& info) {
return {
- .status = V1_0::CallForwardInfoStatus{info.status},
+ .status = static_cast<V1_0::CallForwardInfoStatus>(info.status),
.reason = info.reason,
.serviceClass = info.serviceClass,
.toa = info.toa,
diff --git a/radio/aidl/vts/OWNERS b/radio/aidl/vts/OWNERS
deleted file mode 100644
index e75c6c8..0000000
--- a/radio/aidl/vts/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 20868
-include ../../1.0/vts/OWNERS
-
diff --git a/radio/aidl/vts/radio_aidl_hal_utils.cpp b/radio/aidl/vts/radio_aidl_hal_utils.cpp
index efc4f26..6ed8e7d 100644
--- a/radio/aidl/vts/radio_aidl_hal_utils.cpp
+++ b/radio/aidl/vts/radio_aidl_hal_utils.cpp
@@ -92,6 +92,10 @@
return testing::checkSubstringInCommandOutput("getprop persist.radio.multisim.config", "dsds");
}
+bool isDsDaEnabled() {
+ return testing::checkSubstringInCommandOutput("getprop persist.radio.multisim.config", "dsda");
+}
+
bool isTsTsEnabled() {
return testing::checkSubstringInCommandOutput("getprop persist.radio.multisim.config", "tsts");
}
diff --git a/radio/aidl/vts/radio_aidl_hal_utils.h b/radio/aidl/vts/radio_aidl_hal_utils.h
index 47976b9..8170a01 100644
--- a/radio/aidl/vts/radio_aidl_hal_utils.h
+++ b/radio/aidl/vts/radio_aidl_hal_utils.h
@@ -104,6 +104,11 @@
bool isDsDsEnabled();
/*
+ * Check if device is in DSDA (Dual SIM Dual Active).
+ */
+bool isDsDaEnabled();
+
+/*
* Check if device is in TSTS (Triple SIM Triple Standby).
*/
bool isTsTsEnabled();
diff --git a/radio/aidl/vts/radio_config_test.cpp b/radio/aidl/vts/radio_config_test.cpp
index 258b172..c979d28 100644
--- a/radio/aidl/vts/radio_config_test.cpp
+++ b/radio/aidl/vts/radio_config_test.cpp
@@ -176,7 +176,7 @@
slotPortMapping.physicalSlotId = -1;
slotPortMapping.portId = -1;
std::vector<SlotPortMapping> slotPortMappingList = {slotPortMapping};
- if (isDsDsEnabled()) {
+ if (isDsDsEnabled() || isDsDaEnabled()) {
slotPortMappingList.push_back(slotPortMapping);
} else if (isTsTsEnabled()) {
slotPortMappingList.push_back(slotPortMapping);
@@ -252,7 +252,7 @@
}
if (isSsSsEnabled()) {
EXPECT_EQ(1, simCount);
- } else if (isDsDsEnabled()) {
+ } else if (isDsDsEnabled() || isDsDaEnabled()) {
EXPECT_EQ(2, simCount);
} else if (isTsTsEnabled()) {
EXPECT_EQ(3, simCount);
diff --git a/rebootescrow/aidl/Android.bp b/rebootescrow/aidl/Android.bp
index c764f86..39aaa07 100644
--- a/rebootescrow/aidl/Android.bp
+++ b/rebootescrow/aidl/Android.bp
@@ -18,11 +18,6 @@
java: {
platform_apis: true,
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
versions: ["1"],
}
diff --git a/secure_element/aidl/Android.bp b/secure_element/aidl/Android.bp
new file mode 100644
index 0000000..6450eb4
--- /dev/null
+++ b/secure_element/aidl/Android.bp
@@ -0,0 +1,44 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+aidl_interface {
+ name: "android.hardware.secure_element",
+ vendor_available: true,
+ host_supported: true,
+ srcs: ["android/hardware/secure_element/*.aidl"],
+ stability: "vintf",
+ backend: {
+ cpp: {
+ enabled: false,
+ },
+ java: {
+ sdk_version: "system_current",
+ },
+ },
+}
+
+cc_test {
+ name: "VtsHalSecureElementTargetTest",
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "use_libaidlvintf_gtest_helper_static",
+ ],
+ srcs: ["vts/VtsHalSecureElementTargetTest.cpp"],
+ shared_libs: [
+ "libbinder_ndk",
+ ],
+ static_libs: [
+ "android.hardware.secure_element-V1-ndk",
+ "libgmock",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+}
diff --git a/secure_element/aidl/aidl_api/android.hardware.secure_element/current/android/hardware/secure_element/ISecureElement.aidl b/secure_element/aidl/aidl_api/android.hardware.secure_element/current/android/hardware/secure_element/ISecureElement.aidl
new file mode 100644
index 0000000..fba29ab
--- /dev/null
+++ b/secure_element/aidl/aidl_api/android.hardware.secure_element/current/android/hardware/secure_element/ISecureElement.aidl
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.secure_element;
+@VintfStability
+interface ISecureElement {
+ void closeChannel(in byte channelNumber);
+ byte[] getAtr();
+ void init(in android.hardware.secure_element.ISecureElementCallback clientCallback);
+ boolean isCardPresent();
+ byte[] openBasicChannel(in byte[] aid, in byte p2);
+ android.hardware.secure_element.LogicalChannelResponse openLogicalChannel(in byte[] aid, in byte p2);
+ void reset();
+ byte[] transmit(in byte[] data);
+ const int FAILED = 1;
+ const int CHANNEL_NOT_AVAILABLE = 2;
+ const int NO_SUCH_ELEMENT_ERROR = 3;
+ const int UNSUPPORTED_OPERATION = 4;
+ const int IOERROR = 5;
+}
diff --git a/secure_element/aidl/aidl_api/android.hardware.secure_element/current/android/hardware/secure_element/ISecureElementCallback.aidl b/secure_element/aidl/aidl_api/android.hardware.secure_element/current/android/hardware/secure_element/ISecureElementCallback.aidl
new file mode 100644
index 0000000..6c2be2a
--- /dev/null
+++ b/secure_element/aidl/aidl_api/android.hardware.secure_element/current/android/hardware/secure_element/ISecureElementCallback.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.secure_element;
+@VintfStability
+interface ISecureElementCallback {
+ void onStateChange(in boolean connected, in String debugReason);
+}
diff --git a/secure_element/aidl/aidl_api/android.hardware.secure_element/current/android/hardware/secure_element/LogicalChannelResponse.aidl b/secure_element/aidl/aidl_api/android.hardware.secure_element/current/android/hardware/secure_element/LogicalChannelResponse.aidl
new file mode 100644
index 0000000..f2e7f04
--- /dev/null
+++ b/secure_element/aidl/aidl_api/android.hardware.secure_element/current/android/hardware/secure_element/LogicalChannelResponse.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.secure_element;
+@VintfStability
+parcelable LogicalChannelResponse {
+ byte channelNumber;
+ byte[] selectResponse;
+}
diff --git a/secure_element/aidl/android/hardware/secure_element/ISecureElement.aidl b/secure_element/aidl/android/hardware/secure_element/ISecureElement.aidl
new file mode 100644
index 0000000..7c5a704
--- /dev/null
+++ b/secure_element/aidl/android/hardware/secure_element/ISecureElement.aidl
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.secure_element;
+
+import android.hardware.secure_element.ISecureElementCallback;
+import android.hardware.secure_element.LogicalChannelResponse;
+
+@VintfStability
+interface ISecureElement {
+ const int FAILED = 1;
+ const int CHANNEL_NOT_AVAILABLE = 2;
+ const int NO_SUCH_ELEMENT_ERROR = 3;
+ const int UNSUPPORTED_OPERATION = 4;
+ const int IOERROR = 5;
+
+ /**
+ * Closes the channel indicated by the channelNumber.
+ *
+ * @throws ServiceSpecificException Closing a channel must return
+ * FAILED on an error or if a basic channel (i.e. channel 0)
+ * is used.
+ *
+ * @param channelNumber to be closed
+ */
+ void closeChannel(in byte channelNumber);
+
+ /**
+ * Returns Answer to Reset as per ISO/IEC 7816
+ *
+ * @return containing the response. Empty vector if Secure Element
+ * doesn't support ATR.
+ */
+ byte[] getAtr();
+
+ /**
+ * Initializes the Secure Element. This may include updating the applet
+ * and/or vendor-specific initialization.
+ *
+ * HAL service must send onStateChange() with connected equal to true
+ * after all the initialization has been successfully completed.
+ * Clients must wait for a onStateChange(true) before opening channels.
+ *
+ * @param clientCallback callback used to sent status of the SE back to the
+ * client
+ */
+ void init(in ISecureElementCallback clientCallback);
+
+ /**
+ * Returns the current state of the card.
+ *
+ * This is useful for removable Secure Elements like UICC,
+ * Secure Elements on SD cards etc.
+ *
+ * @return true if present, false otherwise
+ */
+ boolean isCardPresent();
+
+ /**
+ * Opens a basic channel with the Secure Element, selecting the applet
+ * represented by the Application ID (AID). A basic channel has channel
+ * number 0.
+ *
+ * @throws ServiceSpecificException with codes
+ * - CHANNEL_NOT_AVAILABLE if secure element has reached the maximum
+ * limit on the number of channels it can support.
+ * - NO_SUCH_ELEMENT_ERROR if AID provided doesn't match any applet
+ * on the secure element.
+ * - UNSUPPORTED_OPERATION if operation provided by the P2 parameter
+ * is not permitted by the applet.
+ * - IOERROR if there was an error communicating with the Secure Element.
+ *
+ * @param aid AID to uniquely identify the applet on the Secure Element
+ * @param p2 P2 parameter of SELECT APDU as per ISO 7816-4
+ *
+ * @return On success, response to SELECT command.
+ */
+ byte[] openBasicChannel(in byte[] aid, in byte p2);
+
+ /**
+ * Opens a logical channel with the Secure Element, selecting the applet
+ * represented by the Application ID (AID).
+ *
+ * @param aid AID to uniquely identify the applet on the Secure Element
+ * @param p2 P2 parameter of SELECT APDU as per ISO 7816-4
+ * @throws ServiceSpecificException on error with the following code:
+ * - CHANNEL_NOT_AVAILABLE if secure element has reached the maximum
+ * limit on the number of channels it can support.
+ * - NO_SUCH_ELEMENT_ERROR if AID provided doesn't match any applet
+ * on the secure element.
+ * - UNSUPPORTED_OPERATION if operation provided by the P2 parameter
+ * is not permitted by the applet.
+ * - IOERROR if there was an error communicating with the Secure Element.
+ *
+ * @return On success, response to SELECT command
+ */
+ LogicalChannelResponse openLogicalChannel(in byte[] aid, in byte p2);
+
+ /**
+ * Reset the Secure Element.
+ *
+ * HAL should trigger reset to the secure element. It could hardware power cycle or
+ * a soft reset depends on the hardware design.
+ * HAL service must send onStateChange() with connected equal to true
+ * after resetting and all the re-initialization has been successfully completed.
+ */
+ void reset();
+
+ /**
+ * Transmits an APDU command (as per ISO/IEC 7816) to the SE.
+ *
+ * @param data APDU command to be sent
+ * @return response to the command
+ */
+ byte[] transmit(in byte[] data);
+}
diff --git a/secure_element/aidl/android/hardware/secure_element/ISecureElementCallback.aidl b/secure_element/aidl/android/hardware/secure_element/ISecureElementCallback.aidl
new file mode 100644
index 0000000..d15a7fb
--- /dev/null
+++ b/secure_element/aidl/android/hardware/secure_element/ISecureElementCallback.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.secure_element;
+
+@VintfStability
+interface ISecureElementCallback {
+ /**
+ * Used to inform the client about changes in the state of the Secure
+ * Element.
+ *
+ * @param connected indicates the current state of the SE
+ * @param reason provides additional data why there was a change in state
+ * ex. initialization error, SE removed etc
+ * This is used only for debugging purpose to understand
+ * in-field issues.
+ */
+ void onStateChange(in boolean connected, in String debugReason);
+}
diff --git a/secure_element/aidl/android/hardware/secure_element/LogicalChannelResponse.aidl b/secure_element/aidl/android/hardware/secure_element/LogicalChannelResponse.aidl
new file mode 100644
index 0000000..65ea71e
--- /dev/null
+++ b/secure_element/aidl/android/hardware/secure_element/LogicalChannelResponse.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.secure_element;
+
+@VintfStability
+parcelable LogicalChannelResponse {
+ /**
+ * Channel number to uniquely identify the channel
+ */
+ byte channelNumber;
+ /**
+ * Response to SELECT command as per ISO/IEC 7816
+ */
+ byte[] selectResponse;
+}
diff --git a/secure_element/aidl/default/Android.bp b/secure_element/aidl/default/Android.bp
new file mode 100644
index 0000000..d1bb393
--- /dev/null
+++ b/secure_element/aidl/default/Android.bp
@@ -0,0 +1,24 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_binary {
+ name: "android.hardware.secure_element-service.example",
+ relative_install_path: "hw",
+ vendor: true,
+ init_rc: ["secure_element.rc"],
+ vintf_fragments: ["secure_element.xml"],
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "android.hardware.secure_element-V1-ndk",
+ ],
+ srcs: [
+ "main.cpp",
+ ],
+}
diff --git a/secure_element/aidl/default/main.cpp b/secure_element/aidl/default/main.cpp
new file mode 100644
index 0000000..16b8236
--- /dev/null
+++ b/secure_element/aidl/default/main.cpp
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/android/hardware/secure_element/BnSecureElement.h>
+
+#include <android-base/hex.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+using aidl::android::hardware::secure_element::BnSecureElement;
+using aidl::android::hardware::secure_element::ISecureElementCallback;
+using aidl::android::hardware::secure_element::LogicalChannelResponse;
+using android::base::HexString;
+using ndk::ScopedAStatus;
+
+static const std::vector<uint8_t> kAndroidTestAid = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41,
+ 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64,
+ 0x43, 0x54, 0x53, 0x31};
+static const std::vector<uint8_t> kLongAndroidTestAid = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41,
+ 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64,
+ 0x43, 0x54, 0x53, 0x32};
+
+class MySecureElement : public BnSecureElement {
+ public:
+ ScopedAStatus closeChannel(int8_t channelNumber) override {
+ LOG(INFO) << __func__ << " channel number: " << channelNumber;
+ return ScopedAStatus::ok();
+ }
+ ScopedAStatus getAtr(std::vector<uint8_t>* _aidl_return) override {
+ LOG(INFO) << __func__;
+ _aidl_return->clear();
+ return ScopedAStatus::ok();
+ }
+ ScopedAStatus init(const std::shared_ptr<ISecureElementCallback>& clientCallback) override {
+ LOG(INFO) << __func__ << " callback: " << clientCallback.get();
+ if (!clientCallback) {
+ return ScopedAStatus::fromExceptionCode(EX_NULL_POINTER);
+ }
+ mCb = clientCallback;
+ mCb->onStateChange(true, "");
+ return ScopedAStatus::ok();
+ }
+ ScopedAStatus isCardPresent(bool* _aidl_return) override {
+ LOG(INFO) << __func__;
+ *_aidl_return = true;
+ return ScopedAStatus::ok();
+ }
+ ScopedAStatus openBasicChannel(const std::vector<uint8_t>& aid, int8_t p2,
+ std::vector<uint8_t>* _aidl_return) override {
+ LOG(INFO) << __func__ << " aid: " << HexString(aid.data(), aid.size()) << " (" << aid.size()
+ << ") p2 " << p2;
+
+ // TODO(b/123254068) - this is not an implementation of the OMAPI protocol or APDU.
+ // The functionality here is enough to exercise the framework, but actual
+ // calls to the secure element will fail. This implementation does not model
+ // channel isolation or any other aspects important to implementing secure element.
+ *_aidl_return = {0x90, 0x00, 0x00}; // DO NOT COPY
+ return ScopedAStatus::ok();
+ }
+ ScopedAStatus openLogicalChannel(
+ const std::vector<uint8_t>& aid, int8_t p2,
+ ::aidl::android::hardware::secure_element::LogicalChannelResponse* _aidl_return)
+ override {
+ LOG(INFO) << __func__ << " aid: " << HexString(aid.data(), aid.size()) << " (" << aid.size()
+ << ") p2 " << p2;
+
+ if (aid != kAndroidTestAid && aid != kLongAndroidTestAid) {
+ return ScopedAStatus::fromServiceSpecificError(NO_SUCH_ELEMENT_ERROR);
+ }
+
+ *_aidl_return = LogicalChannelResponse{.channelNumber = 1, .selectResponse = {}};
+
+ // TODO(b/123254068) - this is not an implementation of the OMAPI protocol or APDU.
+ // The functionality here is enough to exercise the framework, but actual
+ // calls to the secure element will fail. This implementation does not model
+ // channel isolation or any other aspects important to implementing secure element.
+ if (aid == kAndroidTestAid) { // DO NOT COPY
+ size_t size = 2050; // DO NOT COPY
+ _aidl_return->selectResponse.resize(size); // DO NOT COPY
+ _aidl_return->selectResponse[size - 1] = 0x00; // DO NOT COPY
+ _aidl_return->selectResponse[size - 2] = 0x90; // DO NOT COPY
+ } else { // DO NOT COPY
+ _aidl_return->selectResponse = {0x00, 0x00, 0x90, 0x00}; // DO NOT COPY
+ } // DO NOT COPY
+
+ LOG(INFO) << __func__ << " sending response: "
+ << HexString(_aidl_return->selectResponse.data(),
+ _aidl_return->selectResponse.size());
+
+ return ScopedAStatus::ok();
+ }
+ ScopedAStatus reset() override {
+ LOG(INFO) << __func__;
+ mCb->onStateChange(false, "reset");
+ mCb->onStateChange(true, "reset");
+ return ScopedAStatus::ok();
+ }
+ ScopedAStatus transmit(const std::vector<uint8_t>& data,
+ std::vector<uint8_t>* _aidl_return) override {
+ LOG(INFO) << __func__ << " data: " << HexString(data.data(), data.size()) << " ("
+ << data.size() << ")";
+
+ // TODO(b/123254068) - this is not an implementation of the OMAPI protocol or APDU.
+ // The functionality here is enough to exercise the framework, but actual
+ // calls to the secure element will fail. This implementation does not model
+ // channel isolation or any other aspects important to implementing secure element.
+
+ std::string hex = HexString(data.data(), data.size()); // DO NOT COPY
+ if (hex == "01a4040210a000000476416e64726f696443545331") { // DO NOT COPY
+ *_aidl_return = {0x00, 0x6A, 0x00}; // DO NOT COPY
+ } else if (data == std::vector<uint8_t>{0x00, 0xF4, 0x00, 0x00, 0x00}) { // DO NOT COPY
+ // CHECK_SELECT_P2_APDU w/ channel 1 // DO NOT COPY
+ *_aidl_return = {0x00, 0x90, 0x00}; // DO NOT COPY
+ } else if (data == std::vector<uint8_t>{0x01, 0xF4, 0x00, 0x00, 0x00}) { // DO NOT COPY
+ // CHECK_SELECT_P2_APDU w/ channel 1 // DO NOT COPY
+ *_aidl_return = {0x00, 0x90, 0x00}; // DO NOT COPY
+ } else if (data.size() == 5 || data.size() == 8) { // DO NOT COPY
+ // SEGMENTED_RESP_APDU - happens to use length 5 and 8 // DO NOT COPY
+ size_t size = (data[2] << 8 | data[3]) + 2; // DO NOT COPY
+ _aidl_return->resize(size); // DO NOT COPY
+ (*_aidl_return)[size - 1] = 0x00; // DO NOT COPY
+ (*_aidl_return)[size - 2] = 0x90; // DO NOT COPY
+ if (size >= 3) (*_aidl_return)[size - 3] = 0xFF; // DO NOT COPY
+ } else { // DO NOT COPY
+ *_aidl_return = {0x90, 0x00, 0x00}; // DO NOT COPY
+ } // DO NOT COPY
+
+ return ScopedAStatus::ok();
+ }
+
+ private:
+ std::shared_ptr<ISecureElementCallback> mCb;
+};
+
+int main() {
+ ABinderProcess_setThreadPoolMaxThreadCount(0);
+
+ auto se = ndk::SharedRefBase::make<MySecureElement>();
+ const std::string name = std::string() + BnSecureElement::descriptor + "/eSE1";
+ binder_status_t status = AServiceManager_addService(se->asBinder().get(), name.c_str());
+ CHECK_EQ(status, STATUS_OK);
+
+ ABinderProcess_joinThreadPool();
+ return EXIT_FAILURE; // should not reach
+}
diff --git a/secure_element/aidl/default/secure_element.rc b/secure_element/aidl/default/secure_element.rc
new file mode 100644
index 0000000..7d21666
--- /dev/null
+++ b/secure_element/aidl/default/secure_element.rc
@@ -0,0 +1,4 @@
+service vendor.secure_element /vendor/bin/hw/android.hardware.secure_element-service.example
+ class hal
+ user nobody
+ group nobody
diff --git a/secure_element/aidl/default/secure_element.xml b/secure_element/aidl/default/secure_element.xml
new file mode 100644
index 0000000..96ab2e7
--- /dev/null
+++ b/secure_element/aidl/default/secure_element.xml
@@ -0,0 +1,7 @@
+<manifest version="1.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.secure_element</name>
+ <version>1</version>
+ <fqname>ISecureElement/eSE1</fqname>
+ </hal>
+</manifest>
diff --git a/secure_element/aidl/vts/VtsHalSecureElementTargetTest.cpp b/secure_element/aidl/vts/VtsHalSecureElementTargetTest.cpp
new file mode 100644
index 0000000..a85a8bc
--- /dev/null
+++ b/secure_element/aidl/vts/VtsHalSecureElementTargetTest.cpp
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/secure_element/BnSecureElementCallback.h>
+#include <aidl/android/hardware/secure_element/ISecureElement.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
+
+using namespace std::chrono_literals;
+
+using aidl::android::hardware::secure_element::BnSecureElementCallback;
+using aidl::android::hardware::secure_element::ISecureElement;
+using aidl::android::hardware::secure_element::LogicalChannelResponse;
+using ndk::ScopedAStatus;
+using ndk::SharedRefBase;
+using ndk::SpAIBinder;
+using testing::ElementsAre;
+using testing::ElementsAreArray;
+
+#define EXPECT_OK(status) \
+ do { \
+ auto status_impl = (status); \
+ EXPECT_TRUE(status_impl.isOk()) << status_impl.getDescription(); \
+ } while (false)
+
+static const std::vector<uint8_t> kDataApdu = {0x00, 0x08, 0x00, 0x00, 0x00};
+static const std::vector<uint8_t> kAndroidTestAid = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41,
+ 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64,
+ 0x43, 0x54, 0x53, 0x31};
+
+class MySecureElementCallback : public BnSecureElementCallback {
+ public:
+ ScopedAStatus onStateChange(bool state, const std::string& debugReason) override {
+ {
+ std::unique_lock<std::mutex> l(m);
+ (void)debugReason;
+ history.push_back(state);
+ }
+ cv.notify_one();
+ return ScopedAStatus::ok();
+ };
+
+ void expectCallbackHistory(std::vector<bool>&& want) {
+ std::unique_lock<std::mutex> l(m);
+ cv.wait_for(l, 2s, [&]() { return history.size() >= want.size(); });
+ EXPECT_THAT(history, ElementsAreArray(want));
+ }
+
+ private:
+ std::mutex m; // guards history
+ std::condition_variable cv;
+ std::vector<bool> history;
+};
+
+class SecureElementAidl : public ::testing::TestWithParam<std::string> {
+ public:
+ virtual void SetUp() override {
+ SpAIBinder binder = SpAIBinder(AServiceManager_waitForService(GetParam().c_str()));
+ se = ISecureElement::fromBinder(binder);
+ ASSERT_NE(se, nullptr);
+
+ cb = SharedRefBase::make<MySecureElementCallback>();
+ EXPECT_OK(se->init(cb));
+
+ cb->expectCallbackHistory({true});
+ }
+
+ std::shared_ptr<ISecureElement> se;
+ std::shared_ptr<MySecureElementCallback> cb;
+};
+
+TEST_P(SecureElementAidl, isCardPresent) {
+ bool res = false;
+ EXPECT_OK(se->isCardPresent(&res));
+ EXPECT_TRUE(res);
+}
+
+TEST_P(SecureElementAidl, transmit) {
+ LogicalChannelResponse response;
+ EXPECT_OK(se->openLogicalChannel(kAndroidTestAid, 0x00, &response));
+
+ EXPECT_GE(response.selectResponse.size(), 2u);
+ EXPECT_GE(response.channelNumber, 1);
+
+ std::vector<uint8_t> command = kDataApdu;
+ command[0] |= response.channelNumber;
+
+ std::vector<uint8_t> transmitResponse;
+ EXPECT_OK(se->transmit(command, &transmitResponse));
+
+ EXPECT_LE(transmitResponse.size(), 3);
+ EXPECT_GE(transmitResponse.size(), 2);
+ EXPECT_EQ(transmitResponse[transmitResponse.size() - 1], 0x00);
+ EXPECT_EQ(transmitResponse[transmitResponse.size() - 2], 0x90);
+
+ EXPECT_OK(se->closeChannel(response.channelNumber));
+}
+
+TEST_P(SecureElementAidl, openBasicChannel) {
+ std::vector<uint8_t> response;
+ auto status = se->openBasicChannel(kAndroidTestAid, 0x00, &response);
+
+ if (!status.isOk()) {
+ EXPECT_EQ(status.getServiceSpecificError(), ISecureElement::CHANNEL_NOT_AVAILABLE)
+ << status.getDescription();
+ return;
+ }
+
+ EXPECT_GE(response.size(), 2u);
+ EXPECT_OK(se->closeChannel(0));
+}
+
+TEST_P(SecureElementAidl, getAtr) {
+ std::vector<uint8_t> atr;
+ EXPECT_OK(se->getAtr(&atr));
+ if (atr.size() == 0) {
+ return;
+ }
+ EXPECT_LE(atr.size(), 32u);
+ EXPECT_GE(atr.size(), 1u);
+}
+
+TEST_P(SecureElementAidl, openCloseLogicalChannel) {
+ LogicalChannelResponse response;
+ EXPECT_OK(se->openLogicalChannel(kAndroidTestAid, 0x00, &response));
+ EXPECT_GE(response.selectResponse.size(), 2u);
+ EXPECT_GE(response.channelNumber, 1);
+ EXPECT_OK(se->closeChannel(response.channelNumber));
+}
+
+TEST_P(SecureElementAidl, openInvalidAid) {
+ LogicalChannelResponse response;
+ auto status = se->openLogicalChannel({0x42}, 0x00, &response);
+ EXPECT_EQ(status.getServiceSpecificError(), ISecureElement::NO_SUCH_ELEMENT_ERROR)
+ << status.getDescription();
+}
+
+TEST_P(SecureElementAidl, Reset) {
+ cb->expectCallbackHistory({true});
+ EXPECT_OK(se->reset());
+ cb->expectCallbackHistory({true, false, true});
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SecureElementAidl);
+INSTANTIATE_TEST_SUITE_P(
+ SecureElement, SecureElementAidl,
+ testing::ValuesIn(android::getAidlHalInstanceNames(ISecureElement::descriptor)),
+ android::PrintInstanceNameToString);
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ ABinderProcess_setThreadPoolMaxThreadCount(1);
+ ABinderProcess_startThreadPool();
+ return RUN_ALL_TESTS();
+}
diff --git a/security/OWNERS b/security/OWNERS
index 54d820a..fbaf854 100644
--- a/security/OWNERS
+++ b/security/OWNERS
@@ -1,5 +1,14 @@
+# Bug component: 1084733
+
+# Please assign all bugs related to /hardware/interfaces/security/ to the team alias:
+#
+# android-hardware-security@google.com
+#
+# This will get them auto-assigned to the on-call triage engineer, ensuring quickest response.
+
drysdale@google.com
+eranm@google.com
+hasinitg@google.com
jbires@google.com
-jdanis@google.com
-seleneh@google.com
swillden@google.com
+zeuthen@google.com
diff --git a/security/dice/aidl/Android.bp b/security/dice/aidl/Android.bp
index 97781b3..5625d70 100644
--- a/security/dice/aidl/Android.bp
+++ b/security/dice/aidl/Android.bp
@@ -34,9 +34,6 @@
platform_apis: false,
},
ndk: {
- vndk: {
- enabled: true,
- },
apps_enabled: false,
apex_available: [
"//apex_available:platform",
diff --git a/security/keymint/README.md b/security/keymint/README.md
new file mode 100644
index 0000000..54647af
--- /dev/null
+++ b/security/keymint/README.md
@@ -0,0 +1,10 @@
+# KeyMint HAL
+
+This directory contains the HAL definition for KeyMint. KeyMint provides
+cryptographic services in a hardware-isolated environment.
+
+Note that the `IRemotelyProvisionedComponent` HAL, and it's associated types,
+used to also be defined in this directory. As of Android U, this HAL has been
+moved to a different directory (../rkp). This move is ABI compatible, as the
+interfaces have been maintained. The build is split so that the generated
+code may be built with different options.
diff --git a/security/keymint/RKP_README.md b/security/keymint/RKP_README.md
deleted file mode 100644
index 89a2598..0000000
--- a/security/keymint/RKP_README.md
+++ /dev/null
@@ -1,374 +0,0 @@
-# Remote Provisioning HAL
-
-## Objective
-
-Design a HAL to support over-the-air provisioning of certificates for asymmetric
-keys. The HAL must interact effectively with Keystore (and other daemons) and
-protect device privacy and security.
-
-Note that this API is designed for KeyMint, but with the intention that it
-should be usable for other HALs that require certificate provisioning.
-Throughout this document we'll refer to the Keystore and KeyMint (formerly
-called Keymaster) components, but only for concreteness and convenience; those
-labels could be replaced with the names of any system and secure area
-components, respectively, that need certificates provisioned.
-
-## Key design decisions
-
-### General approach
-
-To more securely and reliably get keys and certificates to Android devices, we
-need to create a system where no party outside of the device's secure components
-is responsible for managing private keys. The strategy we've chosen is to
-deliver certificates over the air, using an asymmetric key pair created
-on-device in the factory as a root of trust to create an authenticated, secure
-channel. In this document we refer to this device-unique asymmetric key pair as
-Device Key (DK), its public half DK\_pub, its private half DK\_priv and a Device
-Key Certificate containing DK\_pub is denoted DKC.
-
-In order for the provisioning service to use DK (or a key authenticated by DK),
-it must know whether a given DK\_pub is known and trusted. To prove trust, we
-ask device OEMs to use one of two mechanisms:
-
-1. (Preferred, recommended) The device OEM extracts DK\_pub from each device it
- manufactures and uploads the public keys to a backend server.
-
-1. The device OEM signs the DK\_pub to produce DKC and stores it on the device.
- This has the advantage that they don't need to upload a DK\_pub for every
- device immediately, but the disadvantage that they have to manage their
- private signing keys, which means they have to have HSMs, configure and
- secure them correctly, etc. Some backend providers may also require that the
- OEM passes a factory security audit, and additionally promises to upload the
- keys eventually as well.
-
-Note that in the full elaboration of this plan, DK\_pub is not the key used to
-establish a secure channel. Instead, DK\_pub is just the first public key in a
-chain of public keys which ends with the KeyMint public key, KM\_pub. All keys
-in the chain are device-unique and are joined in a certificate chain called the
-_Boot Certificate Chain_ (BCC), because in phases 2 and 3 of the remote
-provisioning project it is a chain of certificates corresponding to boot phases.
-We speak of the BCC even for phase 1, though in phase 1 it contains only a
-single self-signed DKC. This is described in more depth in the Phases section
-below.
-
-The BCC is authenticated by DK\_pub. To authenticate DK\_pub, we may have
-additional DKCs, from the SoC vendor, the device OEM, or both. Those are not
-part of the BCC but included as optional fields in the certificate request
-structure.
-
-The format of the the DK and BCC is specified within [Open Profile for DICE]
-(https://pigweed.googlesource.com/open-dice/+/HEAD/docs/specification.md). To
-map phrases within this document to their equivalent terminology in the DICE
-specification, read the terms as follows: the DK corresponds to the UDS-derived
-key pair, DKC corresponds to the UDS certificate, and the BCC entries between
-DK\_pub and KM\_pub correspond to a chain of CDI certificates.
-
-Note: In addition to allowing 32 byte hash values for fields in the BCC payload,
-this spec additionally constrains some of the choices allowed in open-DICE.
-Specifically, these include which entries are required and which are optional in
-the BCC payload, and which algorithms are acceptable for use.
-
-### Phases
-
-RKP will be deployed in three phases, in terms of managing the root of trust
-binding between the device and the backend. To briefly describe them:
-
-* Phase 1: In phase 1 there is only one entry in the BCC; DK_pub and KM_pub are
- the same key and the certificate is self-signed.
-* Phase 2: This is identical to phase 1, except it leverages the hardware root
- of trust process described by DICE. Instead of trust being rooted in the TEE,
- it is now rooted in the ROM by key material blown into fuses which are only
- accessible to the ROM code.
-* Phase 3: This is identical to Phase 2, except the SoC vendor also does the
- public key extraction or certification in their facilities, along with the OEM
- doing it in the factory. This tightens up the "supply chain" and aims to make
- key upload management more secure.
-
-### Privacy considerations
-
-Because DK and the DKCs are unique, immutable, unspoofable hardware-bound
-identifiers for the device, we must limit access to them to the absolute minimum
-possible. We do this in two ways:
-
-1. We require KeyMint (which knows the BCC and either knows or at least has the
-ability to use KM\_priv) to refuse to ever divulge the BCC or additional
-signatures in plaintext. Instead, KeyMint requires the caller to provide an
-_Endpoint Encryption Key_ (EEK), with which it will encrypt the data before
-returning it. When provisioning production keys, the EEK must be signed by an
-approved authority whose public key is embedded in KeyMint. When certifying test
-keys, KeyMint will accept any EEK without checking the signature, but will
-encrypt and return a test BCC, rather than the real one. The result is that
-only an entity in possession of an Trusted EEK (TEEK) private key can discover
-the plaintext of the production BCC.
-1. Having thus limited access to the public keys to the trusted party only, we
-need to prevent the entity from abusing this unique device identifier. The
-approach and mechanisms for doing that are beyond the scope of this document
-(they must be addressed in the server design), but generally involve taking care
-to ensure that we do not create any links between user IDs, IP addresses or
-issued certificates and the device pubkey.
-
-Although the details of the mechanisms for preventing the entity from abusing
-the BCC are, as stated, beyond the scope of this document, there is a subtle
-design decision here made specifically to enable abuse prevention. Specifically
-the `CertificateRequest` message sent to the server is (in
-[CDDL](https://tools.ietf.org/html/rfc8610)):
-
-```
-cddl
-CertificateRequest = [
- DeviceInfo,
- challenge : bstr,
- ProtectedData,
- MacedKeysToSign
-]
-```
-
-The public keys to be attested by the server are in `MacedKeysToSign`, which is
-a COSE\_Mac0 structure, MACed with a key that is found in `ProtectedData`. The
-MAC key is signed by DK\_pub.
-
-This structure allows the backend component that has access to EEK\_priv to
-decrypt `ProtectedData`, validate that the request is from an authorized device,
-check that the request is fresh and verify and extract the MAC key. That backend
-component never sees any data related to the keys to be signed, but can provide
-the MAC key to another backend component that can verify `MacedKeysToSign` and
-proceed to generate the certificates.
-
-In this way, we can partition the provisioning server into one component that
-knows the device identity, as represented by DK\_pub, but never sees the keys to
-be certified or certificates generated, and another component that sees the keys
-to be certified and certificates generated but does not know the device
-identity.
-
-### Key and cryptographic message formatting
-
-For simplicity of generation and parsing, compactness of wire representation,
-and flexibility and standardization, we've settled on using the CBOR Object
-Signing and Encryption (COSE) standard, defined in [RFC
-8152](https://tools.ietf.org/html/rfc8152). COSE provides compact and reasonably
-simple, yet easily-extensible, wire formats for:
-
-* Keys,
-* MACed messages,
-* Signed messages, and
-* Encrypted messages
-
-COSE enables easy layering of these message formats, such as using a COSE\_Sign
-structure to contain a COSE\_Key with a public key in it. We call this a
-"certificate".
-
-Due to the complexity of the standard, we'll spell out the COSE structures
-completely in this document and in the HAL and other documentation, so that
-although implementors will need to understand CBOR and the CBOR Data Definition
-Language ([CDDL, defined in RFC 8610](https://tools.ietf.org/html/rfc8610)),
-they shouldn't need to understand COSE.
-
-Note, however, that the certificate chains returned from the provisioning server
-are standard X.509 certificates.
-
-### Algorithm choices
-
-This document uses:
-
-* ECDSA P-256 for attestation signing keys;
-* Remote provisioning protocol signing keys:
- * Ed25519 / P-256
-* ECDH keys:
- * X25519 / P-256
-* AES-GCM for all encryption;
-* SHA-256 for all message digesting;
-* HMAC-SHA-256 for all MACing; and
-* HKDF-SHA-256 for all key derivation.
-
-We believe that Curve25519 offers the best tradeoff in terms of security,
-efficiency and global trustworthiness, and that it is now sufficiently
-widely-used and widely-implemented to make it a practical choice.
-
-However, since Secure Elements (SE) do not currently offer support for curve
-25519, we are allowing implementations to instead make use of EC P-256 for
-signing and ECDH. To put it simply, the device unique key pair will be a P-256
-key pair for ECDSA instead of Ed25519, and the ProtectedData COSE\_Encrypt
-message will have its payload encrypted with P-256 ECDH key exchange instead of
-X25519.
-
-The CDDL in the rest of the document will use the '/' operator to show areas
-where either curve 25519 or P-256 may be used. Since there is no easy way to
-bind choices across different CDDL groups, it is important that the implementor
-stays consistent in which type is chosen. E.g. taking ES256 as the choice for
-algorithm implies the implementor should also choose the P256 public key group
-further down in the COSE structure.
-
-### Testability
-
-It's critical that the remote provisioning implementation be testable, to
-minimize the probability that broken devices are sold to end users. To support
-testing, the remote provisioning HAL methods take a `testMode` argument. Keys
-created in test mode are tagged to indicate this. The provisioning server will
-check for the test mode tag and issue test certificates that do not chain back
-to a trusted public key. In test mode, any EEK will be accepted, enabling
-testing tools to use EEKs for which they have the private key so they can
-validate the content of certificate requests. The BCC included in the
-`CertificateRequest` must contain freshly-generated keys, not the real BCC keys.
-
-Keystore (or similar) will need to be able to handle both testMode keys and
-production keys and keep them distinct, generating test certificate requests
-when asked with a test EEK and production certificate requests when asked with a
-production EEK. Likewise, the interface used to instruct Keystore to create keys
-will need to be able to specify whether test or production keys are desired.
-
-## Design
-
-### Certificate provisioning flow
-
-TODO(jbires): Replace this with a `.png` containing a sequence diagram. The
-provisioning flow looks something like this:
-
-Provisioner -> Keystore: Prepare N keys
-Keystore -> KeyMint: generateKeyPair
-KeyMint -> KeyMint: Generate key pair
-KeyMint --> Keystore: key\_blob,pubkey
-Keystore -> Keystore: Store key\_blob,pubkey
-Provisioner -> Server: Get TEEK
-Server --> Provisioner: TEEK
-Provisioner -> Keystore: genCertReq(N, TEEK)
-Keystore -> KeyMint: genCertReq(pubkeys, TEEK)
-KeyMint -> KeyMint: Sign pubkeys & encrypt BCC
-KeyMint --> Keystore: signature, encrypted BCC
-Keystore -> Keystore: Construct cert\_request
-Keystore --> Provisioner: cert\_request
-Provisioner --> Server: cert\_request
-Server -> Server: Validate cert\_request
-Server -> Server: Generate certificates
-Server --> Provisioner: certificates
-Provisioner -> Keystore: certificates
-Keystore -> Keystore: Store certificates
-
-The actors in the above diagram are:
-
-* **Server** is the backend certificate provisioning server. It has access to
- the uploaded device public keys and is responsible for providing encryption
- keys, decrypting and validating requests, and generating certificates in
- response to requests.
-* **Provisioner** is an application that is responsible for communicating with
- the server and all of the system components that require key certificates
- from the server. It also implements the policy that defines how many key
- pairs each client should keep in their pool.
-* **Keystore** is the [Android keystore
- daemon](https://developer.android.com/training/articles/keystore) (or, more
- generally, whatever system component manages communications with a
- particular secure aread component).
-* **KeyMint** is the secure area component that manages cryptographic keys and
- performs attestations (or perhaps some other secure area component).
-
-### `BCC`
-
-The _Boot Certificate Chain_ (BCC) is the chain of certificates that contains
-DK\_pub as well as other often device-unique certificates. The BCC is
-represented as a COSE\_Key containing DK\_pub followed by an array of
-COSE\_Sign1 "certificates" containing public keys and optional additional
-information, ordered from root to leaf, with each certificate signing the next.
-The first certificate in the array is signed by DK\_pub, the last certificate
-has the KeyMint (or whatever) signing key's public key, KM\_pub. In phase 1
-there is only one entry; DK\_pub and KM\_pub are the same key and the
-certificate is self-signed.
-
-Each COSE\_Sign1 certificate is a CBOR Web Token (CWT) as described in [RFC
-8392](https://tools.ietf.org/html/rfc8392) with additional fields as described
-in the Open Profile for DICE. Of these additional fields, only the
-_subjectPublicKey_ and _keyUsage_ fields are expected to be present for the
-KM\_pub entry (that is, the last entry) in a BCC, but all fields required by the
-Open Profile for DICE are expected for other entries (each of which corresponds
-to a particular firmware component or boot stage). The CWT fields _iss_ and
-_sub_ identify the issuer and subject of the certificate and are consistent
-along the BCC entries; the issuer of a given entry matches the subject of the
-previous entry.
-
-The BCC is designed to be constructed using the Open Profile for DICE. In this
-case the DK key pair is derived from the UDS as described by that profile and
-all BCC entries before the leaf are CBOR CDI certificates chained from DK\_pub.
-The KM key pair is not part of the derived DICE chain. It is generated (not
-derived) by the KeyMint module, certified by the last key in the DICE chain, and
-added as the leaf BCC entry. The key usage field in this leaf certificate must
-indicate the key is not used to sign certificates. If a UDS certificate is
-available on the device it should appear in the certificate request as the leaf
-of a DKCertChain in AdditionalDKSignatures (see
-[CertificateRequest](#certificaterequest)).
-
-The Open Profile for DICE allows for an arbitrary configuration descriptor. For
-BCC entries, this configuration descriptor is a CBOR map with the following
-optional fields. If no fields are relevant, an empty map should be encoded.
-Additional implementation-specific fields may be added using key values not in
-the range \[-70000, -70999\] (these are reserved for future additions here).
-
-```
-| Name | Key | Value type | Meaning |
-| ----------------- | ------ | ---------- | ----------------------------------|
-| Component name | -70002 | tstr | Name of firmware component / boot |
-: : : : stage :
-| Component version | -70003 | int | Version of firmware component / |
-: : : : boot stage :
-| Resettable | -70004 | null | If present, key changes on factory|
-: : : : reset :
-```
-
-Please see
-[ProtectedData.aidl](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl)
-for a full CDDL definition of the BCC.
-
-### `CertificateRequest`
-
-The full CBOR message that will be sent to the server to request certificates
-is:
-
-```cddl
-CertificateRequest = [
- DeviceInfo,
- challenge : bstr, // Provided by the server
- ProtectedData, // See ProtectedData.aidl
- MacedKeysToSign // See IRemotelyProvisionedComponent.aidl
-]
-
-DeviceInfo = [
- VerifiedDeviceInfo, // See DeviceInfo.aidl
- UnverifiedDeviceInfo
-]
-
-// Unverified info is anything provided by the HLOS. Subject to change out of
-// step with the HAL.
-UnverifiedDeviceInfo = {
- ? "fingerprint" : tstr,
-}
-
-```
-
-It will be the responsibility of Keystore and the Provisioner to construct the
-`CertificateRequest`. The HAL provides a method to generate the elements that
-need to be constructed on the secure side, which are the tag field of
-`MacedKeysToSign`, `VerifiedDeviceInfo`, and the ciphertext field of
-`ProtectedData`.
-
-### HAL
-
-The remote provisioning HAL provides a simple interface that can be implemented
-by multiple secure components that require remote provisioning. It would be
-slightly simpler to extend the KeyMint API, but that approach would only serve
-the needs of KeyMint, this is more general.
-
-NOTE the data structures defined in this HAL may look a little bloated and
-complex. This is because the COSE data structures are fully spelled-out; we
-could make it much more compact by not re-specifying the standardized elements
-and instead just referencing the standard, but it seems better to fully specify
-them. If the apparent complexity seems daunting, consider what the same would
-look like if traditional ASN.1 DER-based structures from X.509 and related
-standards were used and also fully elaborated.
-
-Please see the related HAL documentation directly in the source code at the
-following links:
-
-* [IRemotelyProvisionedComponent
- HAL](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl)
-* [ProtectedData](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl)
-* [MacedPublicKey](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/MacedPublicKey.aidl)
-* [RpcHardwareInfo](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl)
-* [DeviceInfo](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/DeviceInfo.aidl)
-
diff --git a/security/keymint/TEST_MAPPING b/security/keymint/TEST_MAPPING
new file mode 100644
index 0000000..4ab60b6
--- /dev/null
+++ b/security/keymint/TEST_MAPPING
@@ -0,0 +1,10 @@
+{
+ "presubmit": [
+ {
+ "name": "VtsAidlKeyMintTargetTest"
+ },
+ {
+ "name": "VtsHalRemotelyProvisionedComponentTargetTest"
+ }
+ ]
+}
diff --git a/security/keymint/aidl/Android.bp b/security/keymint/aidl/Android.bp
index a233087..4753afb 100644
--- a/security/keymint/aidl/Android.bp
+++ b/security/keymint/aidl/Android.bp
@@ -17,14 +17,12 @@
"android.hardware.security.secureclock-V1",
],
stability: "vintf",
+ frozen: false,
backend: {
java: {
platform_apis: true,
},
ndk: {
- vndk: {
- enabled: true,
- },
apps_enabled: false,
},
rust: {
@@ -55,21 +53,28 @@
cc_defaults {
name: "keymint_use_latest_hal_aidl_ndk_static",
static_libs: [
- "android.hardware.security.keymint-V2-ndk",
+ "android.hardware.security.keymint-V3-ndk",
],
}
cc_defaults {
name: "keymint_use_latest_hal_aidl_ndk_shared",
shared_libs: [
- "android.hardware.security.keymint-V2-ndk",
+ "android.hardware.security.keymint-V3-ndk",
],
}
cc_defaults {
name: "keymint_use_latest_hal_aidl_cpp_static",
static_libs: [
- "android.hardware.security.keymint-V2-cpp",
+ "android.hardware.security.keymint-V3-cpp",
+ ],
+}
+
+cc_defaults {
+ name: "keymint_use_latest_hal_aidl_cpp_shared",
+ shared_libs: [
+ "android.hardware.security.keymint-V3-cpp",
],
}
@@ -79,6 +84,6 @@
rust_defaults {
name: "keymint_use_latest_hal_aidl_rust",
rustlibs: [
- "android.hardware.security.keymint-V2-rust",
+ "android.hardware.security.keymint-V3-rust",
],
}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/.hash b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/.hash
index b712a52..3a6d415 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/.hash
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/.hash
@@ -1 +1,2 @@
976674616001f714f4a4df49ee45f548de828524
+cd862ae2e49b54fc965dc1b99c218eb729c93bb1
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/.hash b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/.hash
index 69ba9a6..b4c2b78 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/.hash
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/.hash
@@ -1 +1,2 @@
207c9f218b9b9e4e74ff5232eb16511eca9d7d2e
+70c734fbd5cac5b36676d66d8d9aa941967e1e7b
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
deleted file mode 100644
index f566462..0000000
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-// the interface (from the latest frozen version), the build system will
-// prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file built
-// with the aidl_interface module type with versions property set. The module
-// type is used to build AIDL files in a way that they can be used across
-// independently updatable components of the system. If a device is shipped
-// with such a backward incompatible change, it has a high risk of breaking
-// later when a module using the interface is updated, e.g., Mainline modules.
-
-package android.hardware.security.keymint;
-/* @hide */
-@VintfStability
-interface IRemotelyProvisionedComponent {
- android.hardware.security.keymint.RpcHardwareInfo getHardwareInfo();
- byte[] generateEcdsaP256KeyPair(in boolean testMode, out android.hardware.security.keymint.MacedPublicKey macedPublicKey);
- byte[] generateCertificateRequest(in boolean testMode, in android.hardware.security.keymint.MacedPublicKey[] keysToSign, in byte[] endpointEncryptionCertChain, in byte[] challenge, out android.hardware.security.keymint.DeviceInfo deviceInfo, out android.hardware.security.keymint.ProtectedData protectedData);
- const int STATUS_FAILED = 1;
- const int STATUS_INVALID_MAC = 2;
- const int STATUS_PRODUCTION_KEY_IN_TEST_REQUEST = 3;
- const int STATUS_TEST_KEY_IN_PRODUCTION_REQUEST = 4;
- const int STATUS_INVALID_EEK = 5;
-}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl
deleted file mode 100644
index 5ff45f8..0000000
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-// the interface (from the latest frozen version), the build system will
-// prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file built
-// with the aidl_interface module type with versions property set. The module
-// type is used to build AIDL files in a way that they can be used across
-// independently updatable components of the system. If a device is shipped
-// with such a backward incompatible change, it has a high risk of breaking
-// later when a module using the interface is updated, e.g., Mainline modules.
-
-package android.hardware.security.keymint;
-/* @hide */
-@RustDerive(Clone=true, Eq=true, Hash=true, Ord=true, PartialEq=true, PartialOrd=true) @VintfStability
-parcelable RpcHardwareInfo {
- int versionNumber;
- @utf8InCpp String rpcAuthorName;
- int supportedEekCurve = 0;
- @nullable @utf8InCpp String uniqueId;
- const int CURVE_NONE = 0;
- const int CURVE_P256 = 1;
- const int CURVE_25519 = 2;
-}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/Tag.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/Tag.aidl
index e310b44..6ae2369 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/Tag.aidl
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/Tag.aidl
@@ -90,6 +90,7 @@
DEVICE_UNIQUE_ATTESTATION = 1879048912,
IDENTITY_CREDENTIAL_KEY = 1879048913,
STORAGE_KEY = 1879048914,
+ ATTESTATION_ID_SECOND_IMEI = -1879047469,
ASSOCIATED_DATA = -1879047192,
NONCE = -1879047191,
MAC_LENGTH = 805307371,
diff --git a/security/keymint/aidl/android/hardware/security/keymint/DeviceInfo.aidl b/security/keymint/aidl/android/hardware/security/keymint/DeviceInfo.aidl
deleted file mode 100644
index abb2a7b..0000000
--- a/security/keymint/aidl/android/hardware/security/keymint/DeviceInfo.aidl
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.security.keymint;
-
-/**
- * DeviceInfo contains information about the device that's fed in as AAD in the signature of the
- * device private key over the MAC key used for the bundle of public keys. These values are intended
- * to be checked by the server to verify that the certificate signing request crafted by
- * an IRemotelyProvisionedComponent HAL instance is coming from the expected device based
- * on values initially uploaded during device manufacture in the factory.
- * @hide
- */
-@VintfStability
-parcelable DeviceInfo {
- /**
- * DeviceInfo is a CBOR Map structure described by the following CDDL. DeviceInfo must be
- * canonicalized according to the specification in RFC 7049. The ordering presented here is
- * non-canonical to group similar entries semantically.
- *
- * DeviceInfo = {
- * "brand" : tstr,
- * "manufacturer" : tstr,
- * "product" : tstr,
- * "model" : tstr,
- * "device" : tstr,
- * "vb_state" : "green" / "yellow" / "orange", // Taken from the AVB values
- * "bootloader_state" : "locked" / "unlocked", // Taken from the AVB values
- * "vbmeta_digest": bstr, // Taken from the AVB values
- * ? "os_version" : tstr, // Same as
- * // android.os.Build.VERSION.release
- * // Not optional for TEE.
- * "system_patch_level" : uint, // YYYYMMDD
- * "boot_patch_level" : uint, // YYYYMMDD
- * "vendor_patch_level" : uint, // YYYYMMDD
- * "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.
- * }
- */
- byte[] deviceInfo;
-}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
index 95a3710..2e4fc15 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
@@ -196,12 +196,12 @@
* derive a key that is used to encrypt the private/secret key material.
*
* The root of trust consists of a bitstring that must be derived from the public key used by
- * Verified Boot to verify the signature on the boot image and from the lock state of the
- * device. If the public key is changed to allow a different system image to be used or if the
- * lock state is changed, then all of the IKeyMintDevice-protected keys created by the previous
- * system state must be unusable, unless the previous state is restored. The goal is to increase
- * the value of the software-enforced key access controls by making it impossible for an attacker-
- * installed operating system to use IKeyMintDevice keys.
+ * Verified Boot to verify the signature on the boot image, from the lock state and from the
+ * Verified Boot state of the device. If the public key is changed to allow a different system
+ * image to be used or if the lock state is changed, then all of the IKeyMintDevice-protected keys
+ * created by the previous system state must be unusable, unless the previous state is restored.
+ * The goal is to increase the value of the software-enforced key access controls by making it
+ * impossible for an attacker-installed operating system to use IKeyMintDevice keys.
*
* == Version Binding ==
*
@@ -336,6 +336,17 @@
* Only Tag::KEY_SIZE is required to generate an 3DES key, and its value must be 168. If
* omitted, generateKey must return ErrorCode::UNSUPPORTED_KEY_SIZE.
*
+ * == HMAC Keys ==
+ *
+ * Tag::KEY_SIZE must be provided to generate an HMAC key, and its value must be >= 64 and a
+ * multiple of 8. All devices must support key sizes up to 512 bits, but StrongBox devices must
+ * not support key sizes larger than 512 bits. If omitted or invalid, generateKey() must return
+ * ErrorCode::UNSUPPORTED_KEY_SIZE.
+ *
+ * Tag::MIN_MAC_LENGTH must be provided, and must be a multiple of 8 in the range 64 to 512
+ * bits (inclusive). If omitted, generateKey must return ErrorCode::MISSING_MIN_MAC_LENGTH; if
+ * invalid, generateKey must return ErrorCode::UNSUPPORTED_MIN_MAC_LENGTH.
+ *
* @param keyParams Key generation parameters are defined as KeyMintDevice tag/value pairs,
* provided in params. See above for detailed specifications of which tags are required
* for which types of keys.
@@ -613,9 +624,15 @@
*
* o The key must have a Tag::USER_AUTH_TYPE that matches the auth type in the token.
*
- * o The timestamp in the auth token plus the value of the Tag::AUTH_TIMEOUT must be less than
- * the current secure timestamp (which is a monotonic timer counting milliseconds since
- * boot.)
+ * o If the device has a source of secure time, then the timestamp in the auth token plus the
+ * value of the Tag::AUTH_TIMEOUT must be greater than the current secure timestamp (which
+ * is a monotonic timer counting milliseconds since boot).
+ *
+ * o If the device does not have a source of secure time, then the timestamp check should be
+ * performed on the first update(), updateAad() or finish() invocation for the operation,
+ * using the timeStampToken parameter provided on the invocation to indicate the current
+ * timestamp. It may optionally also be performed on subsequent update() / updateAad() /
+ * finish() invocations.
*
* If any of these conditions are not met, begin() must return
* ErrorCode::KEY_USER_NOT_AUTHENTICATED.
@@ -661,19 +678,19 @@
* structure, because it cannot add the DigestInfo structure. Instead, the IKeyMintDevice
* must construct 0x00 || 0x01 || PS || 0x00 || M, where M is the provided message and PS is a
* random padding string at least eight bytes in length. The size of the RSA key has to be at
- * least 11 bytes larger than the message, otherwise begin() must return
+ * least 11 bytes larger than the message, otherwise finish() must return
* ErrorCode::INVALID_INPUT_LENGTH.
*
* o PaddingMode::RSA_PKCS1_1_1_5_ENCRYPT padding does not require a digest.
*
- * o PaddingMode::RSA_PSS padding requires a digest, which must match one of the padding values
+ * o PaddingMode::RSA_PSS padding requires a digest, which must match one of the digest values
* in the key authorizations, and which may not be Digest::NONE. begin() must return
* ErrorCode::INCOMPATIBLE_DIGEST if this is not the case. In addition, the size of the RSA
- * key must be at least 2 + D bytes larger than the output size of the digest, where D is the
- * size of the digest, in bytes. Otherwise begin() must return
- * ErrorCode::INCOMPATIBLE_DIGEST. The salt size must be D.
+ * key must be at least (D + S + 9) bits, where D is the size of the digest (in bits) and
+ * S is the size of the salt (in bits). The salt size S must equal D, so the RSA key must
+ * be at least (2*D + 9) bits. Otherwise begin() must return ErrorCode::INCOMPATIBLE_DIGEST.
*
- * o PaddingMode::RSA_OAEP padding requires a digest, which must match one of the padding values
+ * o PaddingMode::RSA_OAEP padding requires a digest, which must match one of the digest values
* in the key authorizations, and which may not be Digest::NONE. begin() must return
* ErrorCode::INCOMPATIBLE_DIGEST if this is not the case. RSA_OAEP padding also requires an
* MGF1 digest, specified with Tag::RSA_OAEP_MGF_DIGEST, which must match one of the MGF1
@@ -683,9 +700,9 @@
*
* -- EC Keys --
*
- * Private key operations (KeyPurpose::SIGN) need authorization of digest and padding, which
- * means that the key authorizations must contain the specified values. If not, begin() must
- * return ErrorCode::INCOMPATIBLE_DIGEST.
+ * Private key operations (KeyPurpose::SIGN) need authorization of digest, which means that the
+ * key authorizations must contain the specified values. If not, begin() must return
+ * ErrorCode::INCOMPATIBLE_DIGEST.
*
* -- AES Keys --
*
@@ -804,7 +821,7 @@
/**
* Called by client to notify the IKeyMintDevice that the device has left the early boot
* state, and that keys with the EARLY_BOOT_ONLY tag may no longer be used. All attempts to use
- * an EARLY_BOOT_ONLY key after this method is called must fail with Error::INVALID_KEY_BLOB.
+ * an EARLY_BOOT_ONLY key after this method is called must fail with Error::EARLY_BOOT_ENDED.
*/
void earlyBootEnded();
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintOperation.aidl b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintOperation.aidl
index c30c183..82c8a0d 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintOperation.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintOperation.aidl
@@ -40,31 +40,7 @@
*
* == Authorization Enforcement ==
*
- * Key authorization enforcement is performed primarily in begin(). The one exception is the
- * case where the key has:
- *
- * o One or more Tag::USER_SECURE_IDs, and
- *
- * o Does not have a Tag::AUTH_TIMEOUT
- *
- * In this case, the key requires an authorization per operation, and the update method must
- * receive a non-null and valid HardwareAuthToken. For the auth token to be valid, all of the
- * following has to be true:
- *
- * o The HMAC field must validate correctly.
- *
- * o At least one of the Tag::USER_SECURE_ID values from the key must match at least one of
- * the secure ID values in the token.
- *
- * o The key must have a Tag::USER_AUTH_TYPE that matches the auth type in the token.
- *
- * o The challenge field in the auth token must contain the value returned from
- * IKeyMintDevice::begin(), given by the challenge field of the BeginResult structure.
- *
- * If any of these conditions are not met, updateAad() must return
- * ErrorCode::KEY_USER_NOT_AUTHENTICATED.
- *
- * The caller must provide the auth token on every call to updateAad(), update() and finish().
+ * See the Authorization Enforcement section for the update() method.
*
*
* For GCM encryption, the AEAD tag must be appended to the ciphertext by finish(). During
@@ -104,16 +80,22 @@
*
* == Authorization Enforcement ==
*
- * Key authorization enforcement is performed primarily in IKeyMintDevice::begin(). The one
- * exception is the case where the key has:
+ * Key authorization enforcement is performed primarily in IKeyMintDevice::begin(). There are
+ * two exceptions to this:
*
- * o One or more Tag::USER_SECURE_IDs, and
+ * 1) Key with USER_SECURE_IDs but no AUTH_TIMEOUT
*
- * o Does not have a Tag::AUTH_TIMEOUT
+ * 2) Key with USER_SECURE_IDs and AUTH_TIMEOUT, but the device does not support secure time.
*
- * In this case, the key requires an authorization per operation, and the update method must
- * receive a non-empty and valid HardwareAuthToken. For the auth token to be valid, all of the
- * following has to be true:
+ * The first exception is the case where the key:
+ *
+ * o Has one or more Tag::USER_SECURE_IDs, and
+ *
+ * o Does not have a Tag::AUTH_TIMEOUT
+ *
+ * In this case, the key requires an authorization per operation, and update() / updateAad() /
+ * finish() methods must receive a non-null and valid HardwareAuthToken. For the auth token to
+ * be valid, all of the following has to be true:
*
* o The HMAC field must validate correctly.
*
@@ -125,10 +107,47 @@
* o The challenge field in the auth token must contain the challenge value contained in the
* BeginResult returned from IKeyMintDevice::begin().
*
- * If any of these conditions are not met, update() must return
+ * If any of these conditions are not met, the method must return
* ErrorCode::KEY_USER_NOT_AUTHENTICATED.
*
- * The caller must provide the auth token on every call to update() and finish().
+ * The caller must provide the auth token on every call to update(), updateAad() and finish().
+ *
+ *
+ * The second exception is the case where the key:
+ *
+ * o Has one or more Tag::USER_SECURE_IDs, and
+ *
+ * o Has a Tag::AUTH_TIMEOUT value, but the device does not have a source of secure time (as
+ * indicated by the KeyMintHardwareInfo.timestampTokenRequired field).
+ *
+ * In this case, the key requires an per-operation authorization on the first call to update(),
+ * updateAad() or finish() for the operation, using the provided timeStampToken as a source of
+ * secure time. For this timeStampToken to be valid, all of the following has to be true:
+ *
+ * o The HMAC field must validate correctly.
+ *
+ * o The challenge field in the auth token must contain the challenge value contained in the
+ * BeginResult returned from IKeyMintDevice::begin().
+ *
+ * The resulting secure time value is then used to authenticate the HardwareAuthToken. For the
+ * auth token to be valid, all of the following has to be true:
+ *
+ * o The HMAC field must validate correctly.
+ *
+ * o At least one of the Tag::USER_SECURE_ID values from the key must match at least one of
+ * the secure ID values in the token.
+ *
+ * o The key must have a Tag::USER_AUTH_TYPE that matches the auth type in the token.
+ *
+ * o The challenge field in the auth token must contain the challenge value contained in the
+ * BeginResult returned from IKeyMintDevice::begin().
+ *
+ * o The timestamp in the auth token plus the value of the Tag::AUTH_TIMEOUT must be greater
+ * than the provided secure timestamp.
+
+ * If any of these conditions are not met, the method must return
+ * ErrorCode::KEY_USER_NOT_AUTHENTICATED.
+ *
*
* -- RSA keys --
*
@@ -187,24 +206,7 @@
* Key authorization enforcement is performed primarily in begin(). The exceptions are
* authorization per operation keys and confirmation-required keys.
*
- * Authorization per operation keys are the case where the key has one or more
- * Tag::USER_SECURE_IDs, and does not have a Tag::AUTH_TIMEOUT. In this case, the key requires
- * an authorization per operation, and the finish method must receive a non-empty and valid
- * authToken. For the auth token to be valid, all of the following has to be true:
- *
- * o The HMAC field must validate correctly.
- *
- * o At least one of the Tag::USER_SECURE_ID values from the key must match at least one of
- * the secure ID values in the token.
- *
- * o The key must have a Tag::USER_AUTH_TYPE that matches the auth type in the token.
- *
- * o The challenge field in the auth token must contain the operation challenge.
- *
- * If any of these conditions are not met, update() must return
- * ErrorCode::KEY_USER_NOT_AUTHENTICATED.
- *
- * The caller must provide the auth token on every call to update() and finish().
+ * Authorization per operation keys must be authorized as described for the update() method.
*
* Confirmation-required keys are keys that were generated with
* Tag::TRUSTED_CONFIRMATION_REQUIRED. For these keys, when doing a signing operation the
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl b/security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
deleted file mode 100644
index a29fb08..0000000
--- a/security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.security.keymint;
-
-import android.hardware.security.keymint.DeviceInfo;
-import android.hardware.security.keymint.MacedPublicKey;
-import android.hardware.security.keymint.ProtectedData;
-import android.hardware.security.keymint.RpcHardwareInfo;
-
-/**
- * An IRemotelyProvisionedComponent is a secure-side component for which certificates can be
- * remotely provisioned. It provides an interface for generating asymmetric key pairs and then
- * creating a CertificateRequest that contains the generated public keys, plus other information to
- * authenticate the request origin. The CertificateRequest can be sent to a server, which can
- * validate the request and create certificates.
- *
- * This interface does not provide any way to use the generated and certified key pairs. It's
- * intended to be implemented by a HAL service that does other things with keys (e.g. Keymint).
- *
- * The root of trust for secure provisioning is something called the "Boot Certificate Chain", or
- * BCC. The BCC is a chain of public key certificates, represented as COSE_Sign1 objects containing
- * COSE_Key representations of the public keys. The "root" of the BCC is
- * a device-unique public key, denoted DK_pub. All public keys in the BCC are device-unique. The
- * public key from each certificate in the chain is used to sign the next certificate in the
- * chain. The final, "leaf" certificate contains a public key, denoted KM_pub, whose corresponding
- * private key, denoted KM_priv, is available for use by the IRemotelyProvisionedComponent.
- *
- * BCC Design
- * ==========
- *
- * The BCC is designed to mirror the boot stages of a device, and to prove the content and integrity
- * of each firmware image. In a proper BCC, each boot stage hashes its own private key with the code
- * and any relevant configuration parameters of the next stage to produce a key pair for the next
- * stage. Each stage also uses its own private key to sign the public key of the next stage,
- * including in the certificate the hash of the next firmware stage, then loads the next stage,
- * passing the private key and certificate to it in a manner that does not leak the private key to
- * later boot stages. The BCC root key pair is generated by immutable code (e.g. ROM), from a
- * device-unique secret. After the device-unique secret is used, it must be made unavailable to any
- * later boot stage.
- *
- * In this way, booting the device incrementally builds a certificate chain that (a) identifies and
- * validates the integrity of every stage and (b) contains a set of public keys that correspond to
- * private keys, one known to each stage. Any stage can compute the secrets of all later stages
- * (given the necessary input), but no stage can compute the secret of any preceding stage. Updating
- * the firmware or configuration of any stage changes the key pair of that stage, and of all
- * subsequent stages, and no attacker who compromised the previous version of the updated firmware
- * can know or predict the post-update key pairs. It is recommended and expected that the BCC is
- * constructed using the Open Profile for DICE.
- *
- * When the provisioning server receives a message signed by KM_priv and containing a BCC that
- * chains from DK_pub to KM_pub, it can be certain that (barring vulnerabilities in some boot
- * stage), the CertificateRequest came from the device associated with DK_pub, running the specific
- * software identified by the certificates in the BCC. If the server has some mechanism for knowing
- * which the DK_pub values of "valid" devices, it can determine whether signing certificates is
- * appropriate.
- *
- * Degenerate BCCs
- * ===============
- *
- * While a proper BCC, as described above, reflects the complete boot sequence from boot ROM to the
- * secure area image of the IRemotelyProvisionedComponent, it's also possible to use a "degenerate"
- * BCC which consists only of a single, self-signed certificate containing the public key of a
- * hardware-bound key pair. This is an appopriate solution for devices which haven't implemented
- * everything necessary to produce a proper BCC, but can derive a unique key pair in the secure
- * area. In this degenerate case, DK_pub is the same as KM_pub.
- *
- * BCC Privacy
- * ===========
- *
- * Because the BCC constitutes an unspoofable, device-unique identifier, special care is taken to
- * prevent its availability to entities who may wish to track devices. Two precautions are taken:
- *
- * 1. The BCC is never exported from the IRemotelyProvisionedComponent except in encrypted
- * form. The portion of the CertificateRequest that contains the BCC is encrypted using an
- * Endpoint Encryption Key (EEK). The EEK is provided in the form of a certificate chain whose
- * root must be pre-provisioned into the secure area (hardcoding the roots into the secure area
- * firmware image is a recommended approach). Multiple roots may be provisioned. If the provided
- * EEK does not chain back to this already-known root, the IRemotelyProvisionedComponent must
- * reject it.
- *
- * 2. Precaution 1 above ensures that only an entity with a valid EEK private key can decrypt the
- * BCC. To make it feasible to build a provisioning server which cannot use the BCC to track
- * devices, the CertificateRequest is structured so that the server can be partitioned into two
- * components. The "decrypter" decrypts the BCC, verifies DK_pub and the device's right to
- * receive provisioned certificates, but does not see the public keys to be signed or the
- * resulting certificates. The "certifier" gets informed of the results of the decrypter's
- * validation and sees the public keys to be signed and resulting certificates, but does not see
- * the BCC.
- *
- * Test Mode
- * =========
- *
- * The IRemotelyProvisionedComponent supports a test mode, allowing the generation of test key pairs
- * and test CertificateRequests. Test keys/requests are annotated as such, and the BCC used for test
- * CertificateRequests must contain freshly-generated keys, not the real BCC key pairs.
- * @hide
- */
-@VintfStability
-interface IRemotelyProvisionedComponent {
- const int STATUS_FAILED = 1;
- const int STATUS_INVALID_MAC = 2;
- const int STATUS_PRODUCTION_KEY_IN_TEST_REQUEST = 3;
- const int STATUS_TEST_KEY_IN_PRODUCTION_REQUEST = 4;
- const int STATUS_INVALID_EEK = 5;
-
- /**
- * @return info which contains information about the underlying IRemotelyProvisionedComponent
- * hardware, such as version number, component name, author name, and supported curve.
- */
- RpcHardwareInfo getHardwareInfo();
-
- /**
- * generateKeyPair generates a new ECDSA P-256 key pair that can be certified. Note that this
- * method only generates ECDSA P-256 key pairs, but the interface can be extended to add methods
- * for generating keys for other algorithms, if necessary.
- *
- * @param in boolean testMode indicates whether the generated key is for testing only. Test keys
- * are marked (see the definition of PublicKey in the MacedPublicKey structure) to
- * prevent them from being confused with production keys.
- *
- * @param out MacedPublicKey macedPublicKey contains the public key of the generated key pair,
- * MACed so that generateCertificateRequest can easily verify, without the
- * privateKeyHandle, that the contained public key is for remote certification.
- *
- * @return data representing a handle to the private key. The format is implementation-defined,
- * but note that specific services may define a required format. KeyMint does.
- */
- byte[] generateEcdsaP256KeyPair(in boolean testMode, out MacedPublicKey macedPublicKey);
-
- /**
- * generateCertificateRequest creates a certificate request to be sent to the provisioning
- * server.
- *
- * @param in boolean testMode indicates whether the generated certificate request is for testing
- * only.
- *
- * @param in MacedPublicKey[] keysToSign contains the set of keys to certify. The
- * IRemotelyProvisionedComponent must validate the MACs on each key. If any entry in the
- * array lacks a valid MAC, the method must return STATUS_INVALID_MAC.
- *
- * If testMode is true, the keysToCertify array must contain only keys flagged as test
- * keys. Otherwise, the method must return STATUS_PRODUCTION_KEY_IN_TEST_REQUEST.
- *
- * If testMode is false, the keysToCertify array must not contain any keys flagged as
- * test keys. Otherwise, the method must return STATUS_TEST_KEY_IN_PRODUCTION_REQUEST.
- *
- * @param in endpointEncryptionKey contains an X22519 public key which will be used to encrypt
- * the BCC. For flexibility, this is represented as a certificate chain, represented as a
- * CBOR array of COSE_Sign1 objects, ordered from root to leaf. The leaf contains the
- * X25519 encryption key, each other element is an Ed25519 key signing the next in the
- * chain. The root is self-signed. An implementor may also choose to use P256 as an
- * alternative curve for signing and encryption instead of Curve 25519.
- *
- * EekChain = [ + SignedSignatureKey, SignedEek ]
- *
- * SignedSignatureKey = [ // COSE_Sign1
- * protected: bstr .cbor {
- * 1 : AlgorithmEdDSA / AlgorithmES256, // Algorithm
- * },
- * unprotected: {},
- * payload: bstr .cbor SignatureKeyEd25519 /
- * bstr .cbor SignatureKeyP256,
- * signature: bstr PureEd25519(.cbor SignatureKeySignatureInput) /
- * bstr ECDSA(.cbor SignatureKeySignatureInput)
- * ]
- *
- * SignatureKeyEd25519 = { // COSE_Key
- * 1 : 1, // Key type : Octet Key Pair
- * 3 : AlgorithmEdDSA, // Algorithm
- * -1 : 6, // Curve : Ed25519
- * -2 : bstr // Ed25519 public key
- * }
- *
- * SignatureKeyP256 = {
- * 1 : 2, // Key type : EC2
- * 3 : AlgorithmES256, // Algorithm
- * -1 : 1, // Curve: P256
- * -2 : bstr, // X coordinate
- * -3 : bstr // Y coordinate
- * }
- *
- * SignatureKeySignatureInput = [
- * context: "Signature1",
- * body_protected: bstr .cbor {
- * 1 : AlgorithmEdDSA / AlgorithmES256, // Algorithm
- * },
- * external_aad: bstr .size 0,
- * payload: bstr .cbor SignatureKeyEd25519 /
- * bstr .cbor SignatureKeyP256
- * ]
- *
- * SignedEek = [ // COSE_Sign1
- * protected: bstr .cbor {
- * 1 : AlgorithmEdDSA / AlgorithmES256, // Algorithm
- * },
- * unprotected: {},
- * payload: bstr .cbor EekX25519 / .cbor EekP256,
- * signature: bstr PureEd25519(.cbor EekSignatureInput) /
- * bstr ECDSA(.cbor EekSignatureInput)
- * ]
- *
- * EekX25519 = { // COSE_Key
- * 1 : 1, // Key type : Octet Key Pair
- * 2 : bstr // KID : EEK ID
- * 3 : -25, // Algorithm : ECDH-ES + HKDF-256
- * -1 : 4, // Curve : X25519
- * -2 : bstr // Ed25519 public key
- * }
- *
- * EekP256 = { // COSE_Key
- * 1 : 2, // Key type : EC2
- * 2 : bstr // KID : EEK ID
- * 3 : -25, // Algorithm : ECDH-ES + HKDF-256
- * -1 : 1, // Curve : P256
- * -2 : bstr // Sender X coordinate
- * -3 : bstr // Sender Y coordinate
- * }
- *
- * EekSignatureInput = [
- * context: "Signature1",
- * body_protected: bstr .cbor {
- * 1 : AlgorithmEdDSA / AlgorithmES256, // Algorithm
- * },
- * external_aad: bstr .size 0,
- * payload: bstr .cbor EekX25519 / .cbor EekP256
- * ]
- *
- * AlgorithmES256 = -7
- * AlgorithmEdDSA = -8
- *
- * If the contents of endpointEncryptionKey do not match the SignedEek structure above,
- * the method must return STATUS_INVALID_EEK.
- *
- * If testMode is true, the method must ignore the length and content of the signatures
- * in the chain, which implies that it must not attempt to validate the signature.
- *
- * If testMode is false, the method must validate the chain signatures, and must verify
- * that the public key in the root certifictate is in its pre-configured set of
- * authorized EEK root keys. If the public key is not in the database, or if signature
- * verification fails, the method must return STATUS_INVALID_EEK.
- *
- * @param in challenge contains a byte string from the provisioning server that must be signed
- * by the secure area. See the description of the 'signature' output parameter for
- * details.
- *
- * @param out DeviceInfo contains the VerifiedDeviceInfo portion of the DeviceInfo array in
- * CertificateRequest. The structure is described within the DeviceInfo.aidl file.
- *
- * @param out ProtectedData contains the encrypted BCC and the ephemeral MAC key used to
- * authenticate the keysToSign (see keysToSignMac output argument).
- *
- * @return The of KeysToSign in the CertificateRequest structure. Specifically, it contains:
- *
- * HMAC-256(EK_mac, .cbor KeysToMacStructure)
- *
- * Where EK_mac is an ephemeral MAC key, found in ProtectedData (see below). The MACed
- * data is the "tag" field of a COSE_Mac0 structure like:
- *
- * MacedKeys = [ // COSE_Mac0
- * protected : bstr .cbor {
- * 1 : 5, // Algorithm : HMAC-256
- * },
- * unprotected : {},
- * // Payload is PublicKeys from keysToSign argument, in provided order.
- * payload: bstr .cbor [ * PublicKey ],
- * tag: bstr
- * ]
- *
- * KeysToMacStructure = [
- * context : "MAC0",
- * protected : bstr .cbor { 1 : 5 }, // Algorithm : HMAC-256
- * external_aad : bstr .size 0,
- * // Payload is PublicKeys from keysToSign argument, in provided order.
- * payload : bstr .cbor [ * PublicKey ]
- * ]
- */
- byte[] generateCertificateRequest(in boolean testMode, in MacedPublicKey[] keysToSign,
- in byte[] endpointEncryptionCertChain, in byte[] challenge, out DeviceInfo deviceInfo,
- out ProtectedData protectedData);
-}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/KeyCreationResult.aidl b/security/keymint/aidl/android/hardware/security/keymint/KeyCreationResult.aidl
index 57285a3..294c205 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/KeyCreationResult.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/KeyCreationResult.aidl
@@ -99,8 +99,7 @@
* X.509 certificates ordered such that each certificate is signed by the subsequent one, up to
* the root which must be self-signed (or contain a fake signature in the case of case 4 above).
* The first certificate in the chain signs the public key info of the newly-generated or
- * newly-imported key pair. In the attestation cases (1 and 2 above), the first certificate
- * must also satisfy some other requirements:
+ * newly-imported key pair. The first certificate must also satisfy some other requirements:
*
* o It must have the serial number provided in Tag::CERTIFICATE_SERIAL, or default to 1 if the
* tag is not provided.
@@ -119,15 +118,16 @@
* - the keyAgreement bit set iff the attested key has KeyPurpose::AGREE_KEY, and
* - the keyCertSignBit set iff the attested key has KeyPurpose::ATTEST_KEY.
*
- * o it must contain a KeyDescription attestation extension with OID 1.3.6.1.4.1.11129.2.1.17.
+ * In the attestation cases (1 and 2 above), the first certificate must contain a
+ * KeyDescription attestation extension with OID 1.3.6.1.4.1.11129.2.1.17.
*
* The KeyDescription content is defined by the following ASN.1 schema, which is mostly a
* straightforward translation of the KeyMint tag/value parameter lists to ASN.1.
*
* KeyDescription ::= SEQUENCE {
- * attestationVersion INTEGER, # Value 200
+ * attestationVersion INTEGER, # Value 300
* attestationSecurityLevel SecurityLevel, # See below
- * keyMintVersion INTEGER, # Value 200
+ * keyMintVersion INTEGER, # Value 300
* keymintSecurityLevel SecurityLevel, # See below
* attestationChallenge OCTET_STRING, # Tag::ATTESTATION_CHALLENGE from attestParams
* uniqueId OCTET_STRING, # Empty unless key has Tag::INCLUDE_UNIQUE_ID
@@ -158,12 +158,23 @@
* Failed (3),
* }
*
+ * -- Note that the AuthorizationList SEQUENCE is also used in IKeyMintDevice::importWrappedKey
+ * -- as a way of describing the authorizations associated with a key that is being securely
+ * -- imported. As such, it includes the ability to describe tags that are only relevant for
+ * -- symmetric keys, and which will never appear in the attestation extension of an X.509
+ * -- certificate that holds the public key part of an asymmetric keypair. Importing a wrapped
+ * -- key also allows the use of Tag::USER_SECURE_ID, which is never included in an attestation
+ * -- extension because it has no meaning off-device.
+ *
* AuthorizationList ::= SEQUENCE {
* purpose [1] EXPLICIT SET OF INTEGER OPTIONAL,
* algorithm [2] EXPLICIT INTEGER OPTIONAL,
* keySize [3] EXPLICIT INTEGER OPTIONAL,
+ * blockMode [4] EXPLICIT SET OF INTEGER OPTIONAL, -- symmetric only
* digest [5] EXPLICIT SET OF INTEGER OPTIONAL,
* padding [6] EXPLICIT SET OF INTEGER OPTIONAL,
+ * callerNonce [7] EXPLICIT NULL OPTIONAL, -- symmetric only
+ * minMacLength [8] EXPLICIT INTEGER OPTIONAL, -- symmetric only
* ecCurve [10] EXPLICIT INTEGER OPTIONAL,
* rsaPublicExponent [200] EXPLICIT INTEGER OPTIONAL,
* mgfDigest [203] EXPLICIT SET OF INTEGER OPTIONAL,
@@ -173,6 +184,7 @@
* originationExpireDateTime [401] EXPLICIT INTEGER OPTIONAL,
* usageExpireDateTime [402] EXPLICIT INTEGER OPTIONAL,
* usageCountLimit [405] EXPLICIT INTEGER OPTIONAL,
+ * userSecureId [502] EXPLICIT INTEGER OPTIONAL, -- only used on import
* noAuthRequired [503] EXPLICIT NULL OPTIONAL,
* userAuthType [504] EXPLICIT INTEGER OPTIONAL,
* authTimeout [505] EXPLICIT INTEGER OPTIONAL,
@@ -197,6 +209,7 @@
* vendorPatchLevel [718] EXPLICIT INTEGER OPTIONAL,
* bootPatchLevel [719] EXPLICIT INTEGER OPTIONAL,
* deviceUniqueAttestation [720] EXPLICIT NULL OPTIONAL,
+ * attestationIdSecondImei [723] EXPLICIT OCTET_STRING OPTIONAL,
* }
*/
Certificate[] certificateChain;
diff --git a/security/keymint/aidl/android/hardware/security/keymint/KeyPurpose.aidl b/security/keymint/aidl/android/hardware/security/keymint/KeyPurpose.aidl
index fd103ef..32e71a7 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/KeyPurpose.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/KeyPurpose.aidl
@@ -23,7 +23,7 @@
@VintfStability
@Backing(type="int")
enum KeyPurpose {
- /* Usable with RSA, 3DES and AES keys. */
+ /* Usable with 3DES and AES keys. */
ENCRYPT = 0,
/* Usable with RSA, 3DES and AES keys. */
@@ -32,7 +32,7 @@
/* Usable with RSA, EC and HMAC keys. */
SIGN = 2,
- /* Usable with RSA, EC and HMAC keys. */
+ /* Usable with HMAC keys. */
VERIFY = 3,
/* 4 is reserved */
diff --git a/security/keymint/aidl/android/hardware/security/keymint/MacedPublicKey.aidl b/security/keymint/aidl/android/hardware/security/keymint/MacedPublicKey.aidl
deleted file mode 100644
index ad97443..0000000
--- a/security/keymint/aidl/android/hardware/security/keymint/MacedPublicKey.aidl
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.security.keymint;
-
-/**
- * MacedPublicKey contains a CBOR-encoded public key, MACed by an IRemotelyProvisionedComponent, to
- * prove that the key pair was generated by that component.
- * @hide
- */
-@VintfStability
-parcelable MacedPublicKey {
- /**
- * key is a COSE_Mac0 structure containing the new public key. It's MACed by a key available
- * 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)
- * ]
- *
- * PublicKey = { // COSE_Key
- * 1 : 2, // Key type : EC2
- * 3 : -7, // Algorithm : ES256
- * -1 : 1, // Curve : P256
- * -2 : bstr, // X coordinate, little-endian
- * -3 : bstr, // Y coordinate, little-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
- * ]
- *
- * if a non-P256 public key were contained, the contents of the PublicKey map would change a
- * little; see RFC 8152 for details.
- */
- byte[] macedKey;
-}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/PaddingMode.aidl b/security/keymint/aidl/android/hardware/security/keymint/PaddingMode.aidl
index e71a9c9..6ff4b29 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/PaddingMode.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/PaddingMode.aidl
@@ -26,7 +26,7 @@
@VintfStability
@Backing(type="int")
enum PaddingMode {
- NONE = 1, /* deprecated */
+ NONE = 1,
RSA_OAEP = 2,
RSA_PSS = 3,
RSA_PKCS1_1_5_ENCRYPT = 4,
diff --git a/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl b/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl
deleted file mode 100644
index 8b3875b..0000000
--- a/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.security.keymint;
-
-/**
- * ProtectedData contains the encrypted BCC and the ephemeral MAC key used to
- * authenticate the keysToSign (see keysToSignMac output argument of
- * IRemotelyProvisionedComponent.generateCertificateRequest).
- * @hide
- */
-@VintfStability
-parcelable ProtectedData {
- /**
- * ProtectedData is a COSE_Encrypt structure, encrypted with an AES key that is agreed upon
- * using Elliptic-curve Diffie-Hellman. The contents of the structure are specified by the
- * following CDDL [RFC8610].
- *
- * Notes:
- * - None of the CBOR in ProtectedData uses CBOR tags. If an implementation includes
- * tags, parsers may reject the data.
- *
- * ProtectedData = [ // COSE_Encrypt
- * protected: bstr .cbor {
- * 1 : 3 // Algorithm : AES-GCM 256
- * },
- * unprotected: {
- * 5 : bstr .size 12 // IV
- * },
- * ciphertext: bstr, // AES-GCM-256(K, .cbor ProtectedDataPayload)
- * // Where the encryption key 'K' is derived as follows:
- * // ikm = ECDH(EEK_pub, Ephemeral_priv)
- * // salt = null
- * // info = .cbor Context (see below)
- * // K = HKDF-SHA-256(ikm, salt, info)
- * recipients : [
- * [ // COSE_Recipient
- * protected : bstr .cbor {
- * 1 : -25 // Algorithm : ECDH-ES + HKDF-256
- * },
- * unprotected : {
- * -1 : PubKeyX25519 / PubKeyEcdhP256 // Ephemeral_pub
- * 4 : bstr, // KID : EEK ID
- * },
- * ciphertext : nil
- * ]
- * ]
- * ]
- *
- * // The COSE_KDF_Context that is used to derive the ProtectedData encryption key with
- * // HKDF. See details on use in ProtectedData comments above.
- * Context = [
- * AlgorithmID : 3 // AES-GCM 256
- * PartyUInfo : [
- * identity : bstr "client"
- * nonce : bstr .size 0,
- * other : bstr // Ephemeral_pub
- * ],
- * PartyVInfo : [
- * identity : bstr "server",
- * nonce : bstr .size 0,
- * other : bstr // EEK pubkey
- * ],
- * SuppPubInfo : [
- * 256, // Output key length
- * protected : bstr .size 0
- * ]
- * ]
- *
- * // The data that is encrypted and included in ProtectedData ciphertext (see above).
- * ProtectedDataPayload [
- * SignedMac,
- * Bcc,
- * ? AdditionalDKSignatures,
- * ]
- *
- * // AdditionalDKSignatures allows the platform to provide additional certifications
- * // for the DK_pub. For example, this could be provided by the hardware vendor, who
- * // certifies all of their devices. The SignerName is a free-form string describing
- * // who generated the signature.
- * AdditionalDKSignatures = {
- * + SignerName => DKCertChain
- * }
- *
- * // SignerName is a string identifier that indicates both the signing authority as
- * // well as the format of the DKCertChain
- * SignerName = tstr
- *
- * DKCertChain = [
- * 2* X509Certificate // Root -> ... -> Leaf. "Root" is the vendor self-signed
- * // cert, "Leaf" contains DK_pub. 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 SignedMac, which authenticates the MAC key that is used to authenticate the
- * // keysToSign.
- * SignedMac = [ // COSE_Sign1
- * bstr .cbor { // Protected params
- * 1 : AlgorithmEdDSA / AlgorithmES256, // Algorithm
- * },
- * {}, // Unprotected params
- * bstr .size 32, // Payload: MAC key
- * bstr // PureEd25519(KM_priv, bstr .cbor SignedMac_structure) /
- * // ECDSA(KM_priv, bstr .cbor SignedMac_structure)
- * ]
- *
- * SignedMac_structure = [ // COSE Sig_structure
- * "Signature1",
- * bstr .cbor { // Protected params
- * 1 : AlgorithmEdDSA / AlgorithmES256, // Algorithm
- * },
- * bstr .cbor SignedMacAad,
- * bstr .size 32 // MAC key
- * ]
- *
- * SignedMacAad = [
- * challenge : bstr .size (32..64), // Size between 32 - 64
- * // bytes inclusive
- * VerifiedDeviceInfo,
- * tag: bstr // This is the tag from COSE_Mac0 of
- * // KeysToCertify, to tie the key set to
- * // the signature.
- * ]
- *
- * VerifiedDeviceInfo = DeviceInfo // See DeviceInfo.aidl
- *
- * // The BCC is the boot certificate chain, containing measurements about the device
- * // boot chain. The BCC generally follows the Open Profile for DICE specification at
- * // https://pigweed.googlesource.com/open-dice/+/HEAD/docs/specification.md.
- * //
- * // The first entry in the Bcc is the DK_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 BccEntry for DK_pub, only a "bare" COSE_key.
- * Bcc = [
- * PubKeyEd25519 / PubKeyECDSA256, // DK_pub
- * + BccEntry, // Root -> leaf (KM_pub)
- * ]
- *
- * // This is the signed payload for each entry in the Bcc. Note that the "Configuration
- * // Input Values" described by the Open Profile are not used here. Instead, the Bcc
- * // defines its own configuration values for the Configuration Descriptor field. See
- * // the Open Profile for DICE for more details on the fields. All hashes are SHA256.
- * BccPayload = { // CWT [RFC8392]
- * 1 : tstr, // Issuer
- * 2 : tstr, // Subject
- * -4670552 : bstr .cbor PubKeyEd25519 /
- * bstr .cbor PubKeyECDSA256, // Subject Public Key
- * -4670553 : bstr // Key Usage
- *
- * // NOTE: All of the following fields may be omitted for a "Degenerate BCC", as
- * // described by IRemotelyProvisionedComponent.aidl.
- * -4670545 : bstr, // Code Hash
- * ? -4670546 : bstr, // Code Descriptor
- * ? -4670547 : bstr, // Configuration Hash
- * -4670548 : bstr .cbor { // Configuration Descriptor
- * ? -70002 : tstr, // Component name
- * ? -70003 : int, // Firmware version
- * ? -70004 : null, // Resettable
- * },
- * -4670549 : bstr, // Authority Hash
- * ? -4670550 : bstr, // Authority Descriptor
- * -4670551 : bstr, // Mode
- * }
- *
- * // Each entry in the Bcc is a BccPayload signed by the key from the previous entry
- * // in the Bcc array.
- * BccEntry = [ // COSE_Sign1 (untagged)
- * protected : bstr .cbor {
- * 1 : AlgorithmEdDSA / AlgorithmES256, // Algorithm
- * },
- * unprotected: {},
- * payload: bstr .cbor BccPayload,
- * signature: bstr // PureEd25519(SigningKey, bstr .cbor BccEntryInput) /
- * // ECDSA(SigningKey, bstr .cbor BccEntryInput)
- * // See RFC 8032 for details of how to encode the signature value for Ed25519.
- * ]
- *
- * BccEntryInput = [
- * context: "Signature1",
- * protected: bstr .cbor {
- * 1 : AlgorithmEdDSA / AlgorithmES256, // Algorithm
- * },
- * external_aad: bstr .size 0,
- * payload: bstr .cbor BccPayload
- * ]
- *
- * // The following section defines some types that are reused throughout the above
- * // data structures.
- * PubKeyX25519 = { // COSE_Key
- * 1 : 1, // Key type : Octet Key Pair
- * -1 : 4, // Curve : X25519
- * -2 : bstr // Sender X25519 public key
- * }
- *
- * PubKeyEd25519 = { // COSE_Key
- * 1 : 1, // Key type : octet key pair
- * 3 : AlgorithmEdDSA, // Algorithm : EdDSA
- * -1 : 6, // Curve : Ed25519
- * -2 : bstr // X coordinate, little-endian
- * }
- *
- * PubKeyEcdhP256 = { // COSE_Key
- * 1 : 2, // Key type : EC2
- * -1 : 1, // Curve : P256
- * -2 : bstr // Sender X coordinate
- * -3 : bstr // Sender Y coordinate
- * }
- *
- * PubKeyECDSA256 = { // COSE_Key
- * 1 : 2, // Key type : EC2
- * 3 : AlgorithmES256, // Algorithm : ECDSA w/ SHA-256
- * -1 : 1, // Curve: P256
- * -2 : bstr, // X coordinate
- * -3 : bstr // Y coordinate
- * }
- *
- * AlgorithmES256 = -7
- * AlgorithmEdDSA = -8
- */
- byte[] protectedData;
-}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl b/security/keymint/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl
deleted file mode 100644
index 0cb33ce..0000000
--- a/security/keymint/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.security.keymint;
-
-/**
- * RpcHardwareInfo is the hardware information returned by calling RemotelyProvisionedComponent
- * getHardwareInfo()
- * @hide
- */
-@VintfStability
-@RustDerive(Clone=true, Eq=true, PartialEq=true, Ord=true, PartialOrd=true, Hash=true)
-parcelable RpcHardwareInfo {
- const int CURVE_NONE = 0;
- const int CURVE_P256 = 1;
- const int CURVE_25519 = 2;
-
- /**
- * Implementation version of the remotely provisioned component hardware. The version number is
- * implementation defined, and not necessarily globally meaningful. The version is used to
- * distinguish between different versions of a given implementation.
- */
- int versionNumber;
-
- /**
- * rpcAuthorName is the name of the author of the IRemotelyProvisionedComponent implementation
- * (organization name, not individual). This name is implementation defined, so it can be used
- * to distinguish between different implementations from the same author.
- */
- @utf8InCpp String rpcAuthorName;
-
- /**
- * supportedEekCurve returns an int representing which curve is supported for validating
- * signatures over the Endpoint Encryption Key certificate chain and for using the corresponding
- * signed encryption key in ECDH. Only one curve should be supported, with preference for 25519
- * if it's available. These values are defined as constants above.
- *
- * CURVE_NONE is made the default to help ensure that an implementor doesn't accidentally forget
- * to provide the correct information here, as the VTS tests will check to make certain that
- * a passing implementation does not provide CURVE_NONE.
- */
- int supportedEekCurve = CURVE_NONE;
-
- /**
- * uniqueId is an opaque identifier for this IRemotelyProvisionedComponent implementation. The
- * client should NOT interpret the content of the identifier in any way. The client can only
- * compare identifiers to determine if two IRemotelyProvisionedComponents share the same
- * implementation. Each IRemotelyProvisionedComponent implementation must have a distinct
- * identifier from all other implementations, and it must be consistent across all devices.
- * It's critical that this identifier not be usable to uniquely identify a specific device.
- *
- * This identifier must be consistent across reboots, as it is used to store and track
- * provisioned keys in a persistent, on-device database.
- *
- * uniqueId may not be empty, and must not be any longer than 32 characters.
- *
- * A recommended construction for this value is "[Vendor] [Component Name] [Major Version]",
- * e.g. "Google Trusty KeyMint 1".
- *
- * This field was added in API version 2.
- *
- */
- @nullable @utf8InCpp String uniqueId;
-}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl b/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
index b28ebcb..837fc81 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
@@ -186,10 +186,16 @@
* Tag::RSA_OAEP_MGF_DIGEST specifies the MGF1 digest algorithms that may be used with RSA
* encryption/decryption with OAEP padding. Possible values are defined by the Digest enum.
*
- * This tag is repeatable for key generation/import. RSA cipher operations with OAEP padding
- * must specify an MGF1 digest in the params argument of begin(). If this tag is missing or the
- * specified digest is not in the MGF1 digests associated with the key then begin operation must
- * fail with ErrorCode::INCOMPATIBLE_MGF_DIGEST.
+ * This tag is repeatable for key generation/import.
+ *
+ * If the caller specifies an MGF1 digest in the params argument of begin(), that digest must be
+ * present as an RSA_OAEP_MGF_DIGEST value in the key characteristics (or the begin() operation
+ * must fail with ErrorCode::INCOMPATIBLE_MGF_DIGEST).
+ *
+ * If the caller does not specify an MGF1 digest in the params argument of begin(), a default
+ * MGF1 digest of SHA1 is used. If the key characteristics have any explicitly specified values
+ * for RSA_OAEP_MGF_DIGEST, then SHA1 must be included (or the begin() operation must fail with
+ * ErrorCode::INCOMPATIBLE_MGF_DIGEST).
*
* Must be hardware-enforced.
*/
@@ -268,25 +274,10 @@
USAGE_EXPIRE_DATETIME = TagType.DATE | 402,
/**
- * Tag::MIN_SECONDS_BETWEEN_OPS specifies the minimum amount of time that elapses between
- * allowed operations using a key. This can be used to rate-limit uses of keys in contexts
- * where unlimited use may enable brute force attacks.
+ * OBSOLETE: Do not use.
*
- * The value is a 32-bit integer representing seconds between allowed operations.
- *
- * When a key with this tag is used in an operation, the IKeyMintDevice must start a timer
- * during the finish() or abort() call. Any call to begin() that is received before the timer
- * indicates that the interval specified by Tag::MIN_SECONDS_BETWEEN_OPS has elapsed must fail
- * with ErrorCode::KEY_RATE_LIMIT_EXCEEDED. This implies that the IKeyMintDevice must keep a
- * table of use counters for keys with this tag. Because memory is often limited, this table
- * may have a fixed maximum size and KeyMint may fail operations that attempt to use keys with
- * this tag when the table is full. The table must accommodate at least 8 in-use keys and
- * aggressively reuse table slots when key minimum-usage intervals expire. If an operation
- * fails because the table is full, KeyMint returns ErrorCode::TOO_MANY_OPERATIONS.
- *
- * Must be hardware-enforced.
- *
- * TODO(b/191738660): Remove in KeyMint V2. Currently only used for FDE.
+ * This tag value is included for historical reason, as it was present in Keymaster.
+ * KeyMint implementations do not need to support this tag.
*/
MIN_SECONDS_BETWEEN_OPS = TagType.UINT | 403,
@@ -504,7 +495,9 @@
* that is necessary during all uses of the key. In particular, calls to exportKey() and
* getKeyCharacteristics() must provide the same value to the clientId parameter, and calls to
* begin() must provide this tag and the same associated data as part of the inParams set. If
- * the correct data is not provided, the method must return ErrorCode::INVALID_KEY_BLOB.
+ * the correct data is not provided, the method must return ErrorCode::INVALID_KEY_BLOB. Note
+ * that a key with a zero-length APPLICATION_ID cannot have its key characteristics retrieved
+ * using getKeyCharacteristics() due to a historical limitation of the API.
*
* The content of this tag must be bound to the key cryptographically, meaning it must not be
* possible for an adversary who has access to all of the secure world secrets but does not have
@@ -525,7 +518,9 @@
* that is necessary during all uses of the key. In particular, calls to begin() and
* exportKey() must provide the same value to the appData parameter, and calls to begin must
* provide this tag and the same associated data as part of the inParams set. If the correct
- * data is not provided, the method must return ErrorCode::INVALID_KEY_BLOB.
+ * data is not provided, the method must return ErrorCode::INVALID_KEY_BLOB. Note that a key
+ * with a zero-length APPLICATION_DATA cannot have its key characteristics retrieved using
+ * getKeyCharacteristics() due to a historical limitation of the API.
*
* The content of this tag must be bound to the key cryptographically, meaning it must not be
* possible for an adversary who has access to all of the secure world secrets but does not have
@@ -731,9 +726,10 @@
ATTESTATION_ID_SERIAL = TagType.BYTES | 713,
/**
- * Tag::ATTESTATION_ID_IMEI provides the IMEIs for all radios on the device to attested key
+ * Tag::ATTESTATION_ID_IMEI provides the IMEI one of the radios on the device to attested key
* generation/import operations. This field must be set only when requesting attestation of the
- * device's identifiers.
+ * device's identifiers. If the device has more than one IMEI, a second IMEI may be included
+ * by using the Tag::ATTESTATION_ID_SECOND_IMEI tag.
*
* If the device does not support ID attestation (or destroyAttestationIds() was previously
* called and the device can no longer attest its IDs), any key attestation request that
@@ -888,8 +884,26 @@
STORAGE_KEY = TagType.BOOL | 722,
/**
- * OBSOLETE: Do not use. See IKeyMintOperation.updateAad instead.
- * TODO(b/191738660): Remove in KeyMint v2.
+ * Tag::ATTESTATION_ID_SECOND_IMEI provides an additional IMEI of one of the radios on the
+ * device to attested key generation/import operations. This field MUST be accompanied by
+ * the Tag::ATTESTATION_ID_IMEI tag. It would only be used to convery a second IMEI the device
+ * has, after Tag::ATTESTATION_ID_SECOND_IMEI has been used to convery the first IMEI.
+ *
+ * If the device does not support ID attestation (or destroyAttestationIds() was previously
+ * called and the device can no longer attest its IDs), any key attestation request that
+ * includes this tag must fail with ErrorCode::CANNOT_ATTEST_IDS.
+ *
+ * Must never appear in KeyCharacteristics.
+ */
+ ATTESTATION_ID_SECOND_IMEI = TagType.BYTES | 723,
+
+ /**
+ * OBSOLETE: Do not use.
+ *
+ * This tag value is included for historical reasons -- in Keymaster it was used to hold
+ * associated data for AEAD encryption, as an additional parameter to
+ * IKeymasterDevice::finish(). In KeyMint the IKeyMintOperation::updateAad() method is used for
+ * this.
*/
ASSOCIATED_DATA = TagType.BYTES | 1000,
@@ -928,10 +942,12 @@
RESET_SINCE_ID_ROTATION = TagType.BOOL | 1004,
/**
- * OBSOLETE: Do not use. See the authToken parameter for IKeyMintDevice::begin and for
- * IKeyMintOperation methods instead.
+ * OBSOLETE: Do not use.
*
- * TODO(b/191738660): Delete when keystore1 is deleted.
+ * This tag value is included for historical reasons -- in Keymaster it was used to hold
+ * a confirmation token as an additional parameter to
+ * IKeymasterDevice::finish(). In KeyMint the IKeyMintOperation::finish() method includes
+ * a confirmationToken argument for this.
*/
CONFIRMATION_TOKEN = TagType.BYTES | 1005,
diff --git a/security/keymint/aidl/default/Android.bp b/security/keymint/aidl/default/Android.bp
index 1a17fd4..17520b7 100644
--- a/security/keymint/aidl/default/Android.bp
+++ b/security/keymint/aidl/default/Android.bp
@@ -25,6 +25,7 @@
"keymint_use_latest_hal_aidl_ndk_shared",
],
shared_libs: [
+ "android.hardware.security.rkp-V3-ndk",
"android.hardware.security.sharedsecret-V1-ndk",
"android.hardware.security.secureclock-V1-ndk",
"libbase",
diff --git a/security/keymint/aidl/vts/functional/Android.bp b/security/keymint/aidl/vts/functional/Android.bp
index ef5b0bd..13143bf 100644
--- a/security/keymint/aidl/vts/functional/Android.bp
+++ b/security/keymint/aidl/vts/functional/Android.bp
@@ -35,6 +35,7 @@
"libcrypto",
],
static_libs: [
+ "android.hardware.security.rkp-V3-ndk",
"android.hardware.security.secureclock-V1-ndk",
"libcppbor_external",
"libcppcose_rkp",
diff --git a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
index ca517ac..ea4ba18 100644
--- a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
+++ b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
@@ -798,7 +798,7 @@
add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_BRAND, "ro.product.brand");
add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_DEVICE, "ro.product.device");
add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_PRODUCT, "ro.product.name");
- add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_SERIAL, "ro.serial");
+ add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_SERIAL, "ro.serialno");
add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_MANUFACTURER,
"ro.product.manufacturer");
add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_MODEL, "ro.product.model");
@@ -892,6 +892,7 @@
ASSERT_TRUE(result == ErrorCode::CANNOT_ATTEST_IDS || result == ErrorCode::INVALID_TAG)
<< "result = " << result;
+ device_id_attestation_vsr_check(result);
}
CheckedDeleteKey(&attest_key.keyBlob);
}
diff --git a/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp b/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp
index 1dc5df3..26dc3f5 100644
--- a/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp
+++ b/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp
@@ -252,7 +252,7 @@
add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_BRAND, "ro.product.brand");
add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_DEVICE, "ro.product.device");
add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_PRODUCT, "ro.product.name");
- add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_SERIAL, "ro.serial");
+ add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_SERIAL, "ro.serialno");
add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_MANUFACTURER,
"ro.product.manufacturer");
add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_MODEL, "ro.product.model");
@@ -348,8 +348,8 @@
// Add the tag that doesn't match the local device's real ID.
builder.push_back(invalid_tag);
auto result = GenerateKey(builder, &key_blob, &key_characteristics);
-
ASSERT_TRUE(result == ErrorCode::CANNOT_ATTEST_IDS || result == ErrorCode::INVALID_TAG);
+ device_id_attestation_vsr_check(result);
}
}
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
index 46db4f0..43ad30a 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
@@ -772,6 +772,100 @@
}
}
+void KeyMintAidlTestBase::AesCheckEncryptOneByteAtATime(const string& key, BlockMode block_mode,
+ PaddingMode padding_mode, const string& iv,
+ const string& plaintext,
+ const string& exp_cipher_text) {
+ bool is_authenticated_cipher = (block_mode == BlockMode::GCM);
+ auto auth_set = AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(key.size() * 8)
+ .BlockMode(block_mode)
+ .Padding(padding_mode);
+ if (iv.size() > 0) auth_set.Authorization(TAG_CALLER_NONCE);
+ if (is_authenticated_cipher) auth_set.Authorization(TAG_MIN_MAC_LENGTH, 128);
+ ASSERT_EQ(ErrorCode::OK, ImportKey(auth_set, KeyFormat::RAW, key));
+
+ CheckEncryptOneByteAtATime(block_mode, 16 /*block_size*/, padding_mode, iv, plaintext,
+ exp_cipher_text);
+}
+
+void KeyMintAidlTestBase::CheckEncryptOneByteAtATime(BlockMode block_mode, const int block_size,
+ PaddingMode padding_mode, const string& iv,
+ const string& plaintext,
+ const string& exp_cipher_text) {
+ bool is_stream_cipher = (block_mode == BlockMode::CTR || block_mode == BlockMode::GCM);
+ bool is_authenticated_cipher = (block_mode == BlockMode::GCM);
+ auto params = AuthorizationSetBuilder().BlockMode(block_mode).Padding(padding_mode);
+ if (iv.size() > 0) params.Authorization(TAG_NONCE, iv.data(), iv.size());
+ if (is_authenticated_cipher) params.Authorization(TAG_MAC_LENGTH, 128);
+
+ AuthorizationSet output_params;
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &output_params));
+
+ string actual_ciphertext;
+ if (is_stream_cipher) {
+ // Assert that a 1 byte of output is produced for 1 byte of input.
+ // Every input byte produces an output byte.
+ for (int plaintext_index = 0; plaintext_index < plaintext.size(); plaintext_index++) {
+ string ciphertext;
+ EXPECT_EQ(ErrorCode::OK, Update(plaintext.substr(plaintext_index, 1), &ciphertext));
+ // Some StrongBox implementations cannot support 1:1 input:output lengths, so
+ // we relax this API restriction for them.
+ if (SecLevel() != SecurityLevel::STRONGBOX) {
+ EXPECT_EQ(1, ciphertext.size()) << "plaintext index: " << plaintext_index;
+ }
+ actual_ciphertext.append(ciphertext);
+ }
+ string ciphertext;
+ EXPECT_EQ(ErrorCode::OK, Finish(&ciphertext));
+ if (SecLevel() != SecurityLevel::STRONGBOX) {
+ string expected_final_output;
+ if (is_authenticated_cipher) {
+ expected_final_output = exp_cipher_text.substr(plaintext.size());
+ }
+ EXPECT_EQ(expected_final_output, ciphertext);
+ }
+ actual_ciphertext.append(ciphertext);
+ } else {
+ // Assert that a block of output is produced once a full block of input is provided.
+ // Every input block produces an output block.
+ bool compare_output = true;
+ string additional_information;
+ 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 < 33) {
+ compare_output = false;
+ } else {
+ additional_information = " (b/194134359) ";
+ }
+ }
+ for (int plaintext_index = 0; plaintext_index < plaintext.size(); plaintext_index++) {
+ string ciphertext;
+ EXPECT_EQ(ErrorCode::OK, Update(plaintext.substr(plaintext_index, 1), &ciphertext));
+ if (compare_output) {
+ if ((plaintext_index % block_size) == block_size - 1) {
+ // Update is expected to have output a new block
+ EXPECT_EQ(block_size, ciphertext.size())
+ << "plaintext index: " << plaintext_index << additional_information;
+ } else {
+ // Update is expected to have produced no output
+ EXPECT_EQ(0, ciphertext.size())
+ << "plaintext index: " << plaintext_index << additional_information;
+ }
+ }
+ actual_ciphertext.append(ciphertext);
+ }
+ string ciphertext;
+ EXPECT_EQ(ErrorCode::OK, Finish(&ciphertext));
+ actual_ciphertext.append(ciphertext);
+ }
+ // Regardless of how the completed ciphertext got accumulated, it should match the expected
+ // ciphertext.
+ EXPECT_EQ(exp_cipher_text, actual_ciphertext);
+}
+
void KeyMintAidlTestBase::CheckHmacTestVector(const string& key, const string& message,
Digest digest, const string& expected_mac) {
SCOPED_TRACE("CheckHmacTestVector");
@@ -976,12 +1070,24 @@
return "Failure";
}
X509_Ptr key_cert(parse_cert_blob(cert_chain_[0].encodedCertificate));
+ if (key_cert.get() == nullptr) {
+ ADD_FAILURE() << "Failed to parse cert";
+ return "Failure";
+ }
EVP_PKEY_Ptr pub_key(X509_get_pubkey(key_cert.get()));
+ if (pub_key.get() == nullptr) {
+ ADD_FAILURE() << "Failed to retrieve public key";
+ return "Failure";
+ }
RSA_Ptr rsa(EVP_PKEY_get1_RSA(const_cast<EVP_PKEY*>(pub_key.get())));
+ if (rsa.get() == nullptr) {
+ ADD_FAILURE() << "Failed to retrieve RSA public key";
+ return "Failure";
+ }
// Retrieve relevant tags.
Digest digest = Digest::NONE;
- Digest mgf_digest = Digest::NONE;
+ Digest mgf_digest = Digest::SHA1;
PaddingMode padding = PaddingMode::NONE;
auto digest_tag = params.GetTagValue(TAG_DIGEST);
@@ -1813,30 +1919,32 @@
// The following check assumes that canonical CBOR encoding is used for the COSE_Key.
if (testMode) {
- EXPECT_THAT(cppbor::prettyPrint(parsedPayload.get()),
- MatchesRegex("{\n"
- " 1 : 2,\n" // kty: EC2
- " 3 : -7,\n" // alg: ES256
- " -1 : 1,\n" // EC id: P256
- // The regex {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}} matches a
- // sequence of 32 hexadecimal bytes, enclosed in braces and
- // separated by commas. In this case, some Ed25519 public key.
- " -2 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n" // pub_x: data
- " -3 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n" // pub_y: data
- " -70000 : null,\n" // test marker
- "}"));
+ EXPECT_THAT(
+ cppbor::prettyPrint(parsedPayload.get()),
+ MatchesRegex("\\{\n"
+ " 1 : 2,\n" // kty: EC2
+ " 3 : -7,\n" // alg: ES256
+ " -1 : 1,\n" // EC id: P256
+ // The regex {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}} matches a
+ // sequence of 32 hexadecimal bytes, enclosed in braces and
+ // separated by commas. In this case, some Ed25519 public key.
+ " -2 : \\{(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}\\},\n" // pub_x: data
+ " -3 : \\{(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}\\},\n" // pub_y: data
+ " -70000 : null,\n" // test marker
+ "\\}"));
} else {
- EXPECT_THAT(cppbor::prettyPrint(parsedPayload.get()),
- MatchesRegex("{\n"
- " 1 : 2,\n" // kty: EC2
- " 3 : -7,\n" // alg: ES256
- " -1 : 1,\n" // EC id: P256
- // The regex {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}} matches a
- // sequence of 32 hexadecimal bytes, enclosed in braces and
- // separated by commas. In this case, some Ed25519 public key.
- " -2 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n" // pub_x: data
- " -3 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n" // pub_y: data
- "}"));
+ EXPECT_THAT(
+ cppbor::prettyPrint(parsedPayload.get()),
+ MatchesRegex("\\{\n"
+ " 1 : 2,\n" // kty: EC2
+ " 3 : -7,\n" // alg: ES256
+ " -1 : 1,\n" // EC id: P256
+ // The regex {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}} matches a
+ // sequence of 32 hexadecimal bytes, enclosed in braces and
+ // separated by commas. In this case, some Ed25519 public key.
+ " -2 : \\{(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}\\},\n" // pub_x: data
+ " -3 : \\{(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}\\},\n" // pub_y: data
+ "\\}"));
}
}
@@ -1923,6 +2031,16 @@
*signingKey = std::move(pubKey);
}
+void device_id_attestation_vsr_check(const ErrorCode& result) {
+ if (get_vsr_api_level() >= 34) {
+ ASSERT_FALSE(result == ErrorCode::INVALID_TAG)
+ << "It is a specification violation for INVALID_TAG to be returned due to ID "
+ << "mismatch in a Device ID Attestation call. INVALID_TAG is only intended to "
+ << "be used for a case where updateAad() is called after update(). As of "
+ << "VSR-14, this is now enforced as an error.";
+ }
+}
+
} // namespace test
} // namespace aidl::android::hardware::security::keymint
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
index 8f9df24..5b09ca5 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
@@ -188,6 +188,10 @@
void CheckAesIncrementalEncryptOperation(BlockMode block_mode, int message_size);
+ void AesCheckEncryptOneByteAtATime(const string& key, BlockMode block_mode,
+ PaddingMode padding_mode, const string& iv,
+ const string& plaintext, const string& exp_cipher_text);
+
void CheckHmacTestVector(const string& key, const string& message, Digest digest,
const string& expected_mac);
@@ -343,6 +347,11 @@
string name_;
string author_;
long challenge_;
+
+ private:
+ void CheckEncryptOneByteAtATime(BlockMode block_mode, const int block_size,
+ PaddingMode padding_mode, const string& iv,
+ const string& plaintext, const string& exp_cipher_text);
};
// If the given property is available, add it to the tag set under the given tag ID.
@@ -386,6 +395,7 @@
void check_maced_pubkey(const MacedPublicKey& macedPubKey, bool testMode,
vector<uint8_t>* payload_value);
void p256_pub_key(const vector<uint8_t>& coseKeyData, EVP_PKEY_Ptr* signingKey);
+void device_id_attestation_vsr_check(const ErrorCode& result);
AuthorizationSet HwEnforcedAuthorizations(const vector<KeyCharacteristics>& key_characteristics);
AuthorizationSet SwEnforcedAuthorizations(const vector<KeyCharacteristics>& key_characteristics);
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index 4e746b2..b8d0c20 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -613,7 +613,7 @@
class NewKeyGenerationTest : public KeyMintAidlTestBase {
protected:
void CheckBaseParams(const vector<KeyCharacteristics>& keyCharacteristics) {
- AuthorizationSet auths = CheckCommonParams(keyCharacteristics);
+ AuthorizationSet auths = CheckCommonParams(keyCharacteristics, KeyOrigin::GENERATED);
EXPECT_TRUE(auths.Contains(TAG_PURPOSE, KeyPurpose::SIGN));
// Check that some unexpected tags/values are NOT present.
@@ -622,20 +622,21 @@
}
void CheckSymmetricParams(const vector<KeyCharacteristics>& keyCharacteristics) {
- AuthorizationSet auths = CheckCommonParams(keyCharacteristics);
+ AuthorizationSet auths = CheckCommonParams(keyCharacteristics, KeyOrigin::GENERATED);
EXPECT_TRUE(auths.Contains(TAG_PURPOSE, KeyPurpose::ENCRYPT));
EXPECT_TRUE(auths.Contains(TAG_PURPOSE, KeyPurpose::DECRYPT));
EXPECT_FALSE(auths.Contains(TAG_PURPOSE, KeyPurpose::SIGN));
}
- AuthorizationSet CheckCommonParams(const vector<KeyCharacteristics>& keyCharacteristics) {
+ AuthorizationSet CheckCommonParams(const vector<KeyCharacteristics>& keyCharacteristics,
+ const KeyOrigin expectedKeyOrigin) {
// TODO(swillden): Distinguish which params should be in which auth list.
AuthorizationSet auths;
for (auto& entry : keyCharacteristics) {
auths.push_back(AuthorizationSet(entry.authorizations));
}
- EXPECT_TRUE(auths.Contains(TAG_ORIGIN, KeyOrigin::GENERATED));
+ EXPECT_TRUE(auths.Contains(TAG_ORIGIN, expectedKeyOrigin));
// Verify that App data, ROT and auth timeout are NOT included.
EXPECT_FALSE(auths.Contains(TAG_ROOT_OF_TRUST));
@@ -740,6 +741,7 @@
for (auto block_mode : ValidBlockModes(Algorithm::AES)) {
for (auto padding_mode : ValidPaddingModes(Algorithm::AES, block_mode)) {
+ SCOPED_TRACE(testing::Message() << "AES-unknown-" << block_mode << "-" << padding_mode);
vector<uint8_t> key_blob;
vector<KeyCharacteristics> key_characteristics;
// No key size specified
@@ -993,6 +995,7 @@
*/
TEST_P(NewKeyGenerationTest, Rsa) {
for (auto key_size : ValidKeySizes(Algorithm::RSA)) {
+ SCOPED_TRACE(testing::Message() << "RSA-" << key_size);
vector<uint8_t> key_blob;
vector<KeyCharacteristics> key_characteristics;
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
@@ -1024,6 +1027,15 @@
* without providing NOT_BEFORE and NOT_AFTER parameters.
*/
TEST_P(NewKeyGenerationTest, RsaWithMissingValidity) {
+ if (AidlVersion() < 2) {
+ /*
+ * The KeyMint V1 spec required that CERTIFICATE_NOT_{BEFORE,AFTER} be
+ * specified for asymmetric key generation. However, this was not
+ * checked at the time so we can only be strict about checking this for
+ * implementations of KeyMint version 2 and above.
+ */
+ GTEST_SKIP() << "Validity strict since KeyMint v2";
+ }
// Per RFC 5280 4.1.2.5, an undefined expiration (not-after) field should be set to
// GeneralizedTime 999912312359559, which is 253402300799000 ms from Jan 1, 1970.
constexpr uint64_t kUndefinedExpirationDateTime = 253402300799000;
@@ -1065,6 +1077,7 @@
vector<uint8_t> serial_blob(build_serial_blob(serial_int));
for (auto key_size : ValidKeySizes(Algorithm::RSA)) {
+ SCOPED_TRACE(testing::Message() << "RSA-" << key_size);
vector<uint8_t> key_blob;
vector<KeyCharacteristics> key_characteristics;
auto builder = AuthorizationSetBuilder()
@@ -1102,9 +1115,9 @@
<< "Key size " << key_size << "missing";
EXPECT_TRUE(crypto_params.Contains(TAG_RSA_PUBLIC_EXPONENT, 65537U));
+ ASSERT_GT(cert_chain_.size(), 0);
verify_subject_and_serial(cert_chain_[0], serial_int, subject, false);
EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
- ASSERT_GT(cert_chain_.size(), 0);
AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics);
AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics);
@@ -1147,6 +1160,7 @@
attestation_key.issuerSubjectName = make_name_from_str("Android Keystore Key");
for (auto key_size : ValidKeySizes(Algorithm::RSA)) {
+ SCOPED_TRACE(testing::Message() << "RSA-" << key_size);
auto challenge = "hello";
auto app_id = "foo";
@@ -1178,6 +1192,7 @@
EXPECT_FALSE(ChainSignaturesAreValid(cert_chain_));
// The signature over the attested key should correspond to the P256 public key.
+ ASSERT_GT(cert_chain_.size(), 0);
X509_Ptr key_cert(parse_cert_blob(cert_chain_[0].encodedCertificate));
ASSERT_TRUE(key_cert.get());
EVP_PKEY_Ptr signing_pubkey;
@@ -1265,9 +1280,9 @@
<< "Key size " << key_size << "missing";
EXPECT_TRUE(crypto_params.Contains(TAG_RSA_PUBLIC_EXPONENT, 65537U));
+ ASSERT_GT(cert_chain_.size(), 0);
verify_subject_and_serial(cert_chain_[0], serial_int, subject, false);
EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
- ASSERT_GT(cert_chain_.size(), 0);
AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics);
AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics);
@@ -1293,6 +1308,7 @@
vector<uint8_t> serial_blob(build_serial_blob(serial_int));
for (auto key_size : ValidKeySizes(Algorithm::RSA)) {
+ SCOPED_TRACE(testing::Message() << "RSA-" << key_size);
vector<uint8_t> key_blob;
vector<KeyCharacteristics> key_characteristics;
ASSERT_EQ(ErrorCode::OK,
@@ -1317,9 +1333,9 @@
<< "Key size " << key_size << "missing";
EXPECT_TRUE(crypto_params.Contains(TAG_RSA_PUBLIC_EXPONENT, 65537U));
+ ASSERT_EQ(cert_chain_.size(), 1);
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);
}
@@ -1398,6 +1414,7 @@
<< "Key size " << key_size << "missing";
EXPECT_TRUE(crypto_params.Contains(TAG_RSA_PUBLIC_EXPONENT, 65537U));
+ ASSERT_GT(cert_chain_.size(), 0);
verify_subject_and_serial(cert_chain_[0], serial_int, subject, false);
EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
ASSERT_EQ(cert_chain_.size(), 1);
@@ -1413,6 +1430,7 @@
*/
TEST_P(NewKeyGenerationTest, LimitedUsageRsa) {
for (auto key_size : ValidKeySizes(Algorithm::RSA)) {
+ SCOPED_TRACE(testing::Message() << "RSA-" << key_size);
vector<uint8_t> key_blob;
vector<KeyCharacteristics> key_characteristics;
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
@@ -1463,6 +1481,7 @@
vector<uint8_t> serial_blob(build_serial_blob(serial_int));
for (auto key_size : ValidKeySizes(Algorithm::RSA)) {
+ SCOPED_TRACE(testing::Message() << "RSA-" << key_size);
vector<uint8_t> key_blob;
vector<KeyCharacteristics> key_characteristics;
auto builder = AuthorizationSetBuilder()
@@ -1532,6 +1551,7 @@
*/
TEST_P(NewKeyGenerationTest, NoInvalidRsaSizes) {
for (auto key_size : InvalidKeySizes(Algorithm::RSA)) {
+ SCOPED_TRACE(testing::Message() << "RSA-" << key_size);
vector<uint8_t> key_blob;
vector<KeyCharacteristics> key_characteristics;
ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE,
@@ -1566,6 +1586,7 @@
*/
TEST_P(NewKeyGenerationTest, RsaMissingParams) {
for (auto key_size : ValidKeySizes(Algorithm::RSA)) {
+ SCOPED_TRACE(testing::Message() << "RSA-" << key_size);
ASSERT_EQ(ErrorCode::OK,
GenerateKey(
AuthorizationSetBuilder().RsaKey(key_size, 65537).SetDefaultValidity()));
@@ -1581,6 +1602,7 @@
*/
TEST_P(NewKeyGenerationTest, Ecdsa) {
for (auto curve : ValidCurves()) {
+ SCOPED_TRACE(testing::Message() << "Curve::" << curve);
vector<uint8_t> key_blob;
vector<KeyCharacteristics> key_characteristics;
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
@@ -1667,6 +1689,15 @@
* without providing NOT_BEFORE and NOT_AFTER parameters.
*/
TEST_P(NewKeyGenerationTest, EcdsaWithMissingValidity) {
+ if (AidlVersion() < 2) {
+ /*
+ * The KeyMint V1 spec required that CERTIFICATE_NOT_{BEFORE,AFTER} be
+ * specified for asymmetric key generation. However, this was not
+ * checked at the time so we can only be strict about checking this for
+ * implementations of KeyMint version 2 and above.
+ */
+ GTEST_SKIP() << "Validity strict since KeyMint v2";
+ }
// Per RFC 5280 4.1.2.5, an undefined expiration (not-after) field should be set to
// GeneralizedTime 999912312359559, which is 253402300799000 ms from Jan 1, 1970.
constexpr uint64_t kUndefinedExpirationDateTime = 253402300799000;
@@ -1706,6 +1737,7 @@
vector<uint8_t> serial_blob(build_serial_blob(serial_int));
for (auto curve : ValidCurves()) {
+ SCOPED_TRACE(testing::Message() << "Curve::" << curve);
vector<uint8_t> key_blob;
vector<KeyCharacteristics> key_characteristics;
auto builder = AuthorizationSetBuilder()
@@ -1976,7 +2008,7 @@
add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_BRAND, "ro.product.brand");
add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_DEVICE, "ro.product.device");
add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_PRODUCT, "ro.product.name");
- add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_SERIAL, "ro.serial");
+ add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_SERIAL, "ro.serialno");
add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_MANUFACTURER, "ro.product.manufacturer");
add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_MODEL, "ro.product.model");
@@ -2208,6 +2240,7 @@
vector<uint8_t> serial_blob(build_serial_blob(serial_int));
for (auto curve : ValidCurves()) {
+ SCOPED_TRACE(testing::Message() << "Curve::" << curve);
vector<uint8_t> key_blob;
vector<KeyCharacteristics> key_characteristics;
ASSERT_EQ(ErrorCode::OK,
@@ -2228,8 +2261,8 @@
EXPECT_TRUE(crypto_params.Contains(TAG_EC_CURVE, curve)) << "Curve " << curve << "missing";
EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
- verify_subject_and_serial(cert_chain_[0], serial_int, subject, false);
ASSERT_EQ(cert_chain_.size(), 1);
+ verify_subject_and_serial(cert_chain_[0], serial_int, subject, false);
AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics);
AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics);
@@ -2279,6 +2312,7 @@
auto app_id = "foo";
for (auto curve : ValidCurves()) {
+ SCOPED_TRACE(testing::Message() << "Curve::" << curve);
vector<uint8_t> key_blob;
vector<KeyCharacteristics> key_characteristics;
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
@@ -2320,6 +2354,7 @@
std::vector<uint32_t> app_id_lengths{143, 258};
for (uint32_t length : app_id_lengths) {
+ SCOPED_TRACE(testing::Message() << "app_id_len=" << length);
const string app_id(length, 'a');
vector<uint8_t> key_blob;
vector<KeyCharacteristics> key_characteristics;
@@ -2374,6 +2409,7 @@
*/
TEST_P(NewKeyGenerationTest, LimitedUsageEcdsa) {
for (auto curve : ValidCurves()) {
+ SCOPED_TRACE(testing::Message() << "Curve::" << curve);
vector<uint8_t> key_blob;
vector<KeyCharacteristics> key_characteristics;
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
@@ -2427,6 +2463,7 @@
*/
TEST_P(NewKeyGenerationTest, EcdsaInvalidCurve) {
for (auto curve : InvalidCurves()) {
+ SCOPED_TRACE(testing::Message() << "Curve::" << curve);
vector<uint8_t> key_blob;
vector<KeyCharacteristics> key_characteristics;
auto result = GenerateKey(AuthorizationSetBuilder()
@@ -2448,6 +2485,29 @@
}
/*
+ * NewKeyGenerationTest.EcdsaMissingCurve
+ *
+ * Verifies that EC key generation fails if EC_CURVE not specified after KeyMint V2.
+ */
+TEST_P(NewKeyGenerationTest, EcdsaMissingCurve) {
+ if (AidlVersion() < 2) {
+ /*
+ * The KeyMint V1 spec required that EC_CURVE be specified for EC keys.
+ * However, this was not checked at the time so we can only be strict about checking this
+ * for implementations of KeyMint version 2 and above.
+ */
+ GTEST_SKIP() << "Requiring EC_CURVE only strict since KeyMint v2";
+ }
+ /* If EC_CURVE not provided, generateKey
+ * must return ErrorCode::UNSUPPORTED_KEY_SIZE or ErrorCode::UNSUPPORTED_EC_CURVE.
+ */
+ auto result = GenerateKey(
+ AuthorizationSetBuilder().EcdsaKey(256).Digest(Digest::NONE).SetDefaultValidity());
+ ASSERT_TRUE(result == ErrorCode::UNSUPPORTED_KEY_SIZE ||
+ result == ErrorCode::UNSUPPORTED_EC_CURVE);
+}
+
+/*
* NewKeyGenerationTest.EcdsaMismatchKeySize
*
* Verifies that specifying mismatched key size and curve for EC key generation returns
@@ -2481,6 +2541,7 @@
digest = Digest::SHA_2_512;
}
for (auto curve : ValidCurves()) {
+ SCOPED_TRACE(testing::Message() << "Curve::" << curve);
EXPECT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.EcdsaSigningKey(curve)
.Digest(digest)
@@ -2498,6 +2559,7 @@
*/
TEST_P(NewKeyGenerationTest, Hmac) {
for (auto digest : ValidDigests(false /* withNone */, true /* withMD5 */)) {
+ SCOPED_TRACE(testing::Message() << "Digest::" << digest);
vector<uint8_t> key_blob;
vector<KeyCharacteristics> key_characteristics;
constexpr size_t key_size = 128;
@@ -2531,6 +2593,7 @@
auto app_id = "foo";
for (auto digest : ValidDigests(false /* withNone */, true /* withMD5 */)) {
+ SCOPED_TRACE(testing::Message() << "Digest::" << digest);
vector<uint8_t> key_blob;
vector<KeyCharacteristics> key_characteristics;
constexpr size_t key_size = 128;
@@ -2564,6 +2627,7 @@
*/
TEST_P(NewKeyGenerationTest, LimitedUsageHmac) {
for (auto digest : ValidDigests(false /* withNone */, true /* withMD5 */)) {
+ SCOPED_TRACE(testing::Message() << "Digest::" << digest);
vector<uint8_t> key_blob;
vector<KeyCharacteristics> key_characteristics;
constexpr size_t key_size = 128;
@@ -2602,6 +2666,7 @@
*/
TEST_P(NewKeyGenerationTest, HmacCheckKeySizes) {
for (size_t key_size = 0; key_size <= 512; ++key_size) {
+ SCOPED_TRACE(testing::Message() << "HMAC-" << key_size);
if (key_size < 64 || key_size % 8 != 0) {
// To keep this test from being very slow, we only test a random fraction of
// non-byte key sizes. We test only ~10% of such cases. Since there are 392 of
@@ -2644,6 +2709,7 @@
*/
TEST_P(NewKeyGenerationTest, HmacCheckMinMacLengths) {
for (size_t min_mac_length = 0; min_mac_length <= 256; ++min_mac_length) {
+ SCOPED_TRACE(testing::Message() << "MIN_MAC_LENGTH=" << min_mac_length);
if (min_mac_length < 64 || min_mac_length % 8 != 0) {
// To keep this test from being very long, we only test a random fraction of
// non-byte lengths. We test only ~10% of such cases. Since there are 172 of them,
@@ -2800,6 +2866,7 @@
for (auto padding :
{PaddingMode::NONE, PaddingMode::RSA_PSS, PaddingMode::RSA_PKCS1_1_5_SIGN}) {
for (auto digest : ValidDigests(true /* withNone */, true /* withMD5 */)) {
+ SCOPED_TRACE(testing::Message() << "RSA padding=" << padding << " digest=" << digest);
if (padding == PaddingMode::NONE && digest != Digest::NONE) {
// Digesting only makes sense with padding.
continue;
@@ -3515,6 +3582,7 @@
*/
TEST_P(SigningOperationsTest, HmacAllDigests) {
for (auto digest : ValidDigests(false /* withNone */, false /* withMD5 */)) {
+ SCOPED_TRACE(testing::Message() << "Digest::" << digest);
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.HmacKey(128)
@@ -3776,7 +3844,7 @@
// TODO(seleneh) add ExportKey to GenerateKey
// check result
-class ImportKeyTest : public KeyMintAidlTestBase {
+class ImportKeyTest : public NewKeyGenerationTest {
public:
template <TagType tag_type, Tag tag, typename ValueT>
void CheckCryptoParam(TypedTag<tag_type, tag> ttag, ValueT expected) {
@@ -4365,6 +4433,7 @@
string key = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
uint32_t bitlen = key.size() * 8;
for (uint32_t key_size : {bitlen - 1, bitlen + 1, bitlen - 8, bitlen + 8}) {
+ SCOPED_TRACE(testing::Message() << "import-key-size=" << key_size);
// Explicit key size doesn't match that of the provided key.
auto result = ImportKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
@@ -4432,6 +4501,7 @@
string key = hex2str("a49d7564199e97cb529d2c9d97bf2f98d35edf57ba1f7358");
uint32_t bitlen = key.size() * 7;
for (uint32_t key_size : {bitlen - 1, bitlen + 1, bitlen - 8, bitlen + 8}) {
+ SCOPED_TRACE(testing::Message() << "import-key-size=" << key_size);
// Explicit key size doesn't match that of the provided key.
auto result = ImportKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
@@ -4486,6 +4556,65 @@
VerifyMessage(message, signature, AuthorizationSetBuilder().Digest(Digest::SHA_2_256));
}
+/*
+ * ImportKeyTest.GetKeyCharacteristics
+ *
+ * Verifies that imported keys have the correct characteristics.
+ */
+TEST_P(ImportKeyTest, GetKeyCharacteristics) {
+ vector<uint8_t> key_blob;
+ vector<KeyCharacteristics> key_characteristics;
+ auto base_builder = AuthorizationSetBuilder()
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .SetDefaultValidity();
+ vector<Algorithm> algorithms = {Algorithm::RSA, Algorithm::EC, Algorithm::HMAC, Algorithm::AES,
+ Algorithm::TRIPLE_DES};
+ ErrorCode result;
+ string symKey = hex2str("a49d7564199e97cb529d2c9d97bf2f98"); // 128 bits
+ string tdesKey = hex2str("a49d7564199e97cb529d2c9d97bf2f98d35edf57ba1f7358"); // 192 bits
+ for (auto alg : algorithms) {
+ SCOPED_TRACE(testing::Message() << "Algorithm-" << alg);
+ AuthorizationSetBuilder builder(base_builder);
+ switch (alg) {
+ case Algorithm::RSA:
+ builder.RsaSigningKey(2048, 65537).Digest(Digest::NONE);
+
+ result = ImportKey(builder, KeyFormat::PKCS8, rsa_2048_key, &key_blob,
+ &key_characteristics);
+ break;
+ case Algorithm::EC:
+ builder.EcdsaSigningKey(EcCurve::P_256).Digest(Digest::NONE);
+ result = ImportKey(builder, KeyFormat::PKCS8, ec_256_key, &key_blob,
+ &key_characteristics);
+ break;
+ case Algorithm::HMAC:
+ builder.HmacKey(128)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128);
+ result =
+ ImportKey(builder, KeyFormat::RAW, symKey, &key_blob, &key_characteristics);
+ break;
+ case Algorithm::AES:
+ builder.AesEncryptionKey(128).BlockMode(BlockMode::ECB);
+ result =
+ ImportKey(builder, KeyFormat::RAW, symKey, &key_blob, &key_characteristics);
+ break;
+ case Algorithm::TRIPLE_DES:
+ builder.TripleDesEncryptionKey(168).BlockMode(BlockMode::ECB);
+ result = ImportKey(builder, KeyFormat::RAW, tdesKey, &key_blob,
+ &key_characteristics);
+ break;
+ default:
+ ADD_FAILURE() << "Invalid Algorithm " << uint32_t(alg);
+ continue;
+ }
+ ASSERT_EQ(ErrorCode::OK, result);
+ CheckCharacteristics(key_blob, key_characteristics);
+ CheckCommonParams(key_characteristics, KeyOrigin::IMPORTED);
+ }
+}
+
INSTANTIATE_KEYMINT_AIDL_TEST(ImportKeyTest);
auto wrapped_key = hex2str(
@@ -4835,15 +4964,15 @@
TEST_P(ImportWrappedKeyTest, WrongDigest) {
auto wrapping_key_desc = AuthorizationSetBuilder()
.RsaEncryptionKey(2048, 65537)
- .Digest(Digest::SHA_2_512)
.Padding(PaddingMode::RSA_OAEP)
+ .Digest(Digest::SHA_2_256)
.Authorization(TAG_PURPOSE, KeyPurpose::WRAP_KEY)
.SetDefaultValidity();
ASSERT_EQ(ErrorCode::INCOMPATIBLE_DIGEST,
ImportWrappedKey(wrapped_key, wrapping_key, wrapping_key_desc, zero_masking_key,
AuthorizationSetBuilder()
- .Digest(Digest::SHA_2_256)
+ .Digest(Digest::SHA_2_512)
.Padding(PaddingMode::RSA_OAEP)));
}
@@ -4858,6 +4987,7 @@
*/
TEST_P(EncryptionOperationsTest, RsaNoPaddingSuccess) {
for (uint64_t exponent : ValidExponents()) {
+ SCOPED_TRACE(testing::Message() << "RSA exponent=" << exponent);
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.RsaEncryptionKey(2048, exponent)
@@ -5048,6 +5178,7 @@
string message = "Hello";
for (auto digest : digests) {
+ SCOPED_TRACE(testing::Message() << "digest-" << digest);
auto params = AuthorizationSetBuilder()
.Authorization(TAG_RSA_OAEP_MGF_DIGEST, digest)
.Digest(Digest::SHA_2_256)
@@ -5084,6 +5215,79 @@
}
/*
+ * EncryptionOperationsTest.RsaOaepMGFDigestDefaultSuccess
+ *
+ * Verifies that RSA-OAEP decryption operations work when no MGF digest is
+ * specified, defaulting to SHA-1.
+ */
+TEST_P(EncryptionOperationsTest, RsaOaepMGFDigestDefaultSuccess) {
+ size_t key_size = 2048;
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaEncryptionKey(key_size, 65537)
+ .Padding(PaddingMode::RSA_OAEP)
+ .Digest(Digest::SHA_2_256)
+ .SetDefaultValidity()));
+
+ // Do local RSA encryption using the default MGF digest of SHA-1.
+ string message = "Hello";
+ auto params =
+ AuthorizationSetBuilder().Digest(Digest::SHA_2_256).Padding(PaddingMode::RSA_OAEP);
+ string ciphertext = LocalRsaEncryptMessage(message, params);
+ EXPECT_EQ(key_size / 8, ciphertext.size());
+
+ // Do KeyMint RSA decryption also using the default MGF digest of SHA-1.
+ string plaintext = DecryptMessage(ciphertext, params);
+ EXPECT_EQ(message, plaintext) << "RSA-OAEP failed with default digest";
+
+ // Decrypting corrupted ciphertext should fail.
+ size_t offset_to_corrupt = random() % ciphertext.size();
+ char corrupt_byte;
+ do {
+ corrupt_byte = static_cast<char>(random() % 256);
+ } while (corrupt_byte == ciphertext[offset_to_corrupt]);
+ ciphertext[offset_to_corrupt] = corrupt_byte;
+
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
+ string result;
+ EXPECT_EQ(ErrorCode::UNKNOWN_ERROR, Finish(ciphertext, &result));
+ EXPECT_EQ(0U, result.size());
+}
+
+/*
+ * EncryptionOperationsTest.RsaOaepMGFDigestDefaultFail
+ *
+ * Verifies that RSA-OAEP decryption operations fail when no MGF digest is
+ * specified on begin (thus defaulting to SHA-1), but the key characteristics
+ * has an explicit set of values for MGF_DIGEST that do not contain SHA-1.
+ */
+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()));
+
+ // Do local RSA encryption using the default MGF digest of SHA-1.
+ string message = "Hello";
+ auto params =
+ AuthorizationSetBuilder().Digest(Digest::SHA_2_256).Padding(PaddingMode::RSA_OAEP);
+ string ciphertext = LocalRsaEncryptMessage(message, params);
+ EXPECT_EQ(key_size / 8, ciphertext.size());
+
+ // begin() params do not include MGF_DIGEST, so a default of SHA1 is assumed.
+ // Key characteristics *do* include values for MGF_DIGEST, so the SHA1 value
+ // is checked against those values, and found absent.
+ auto result = Begin(KeyPurpose::DECRYPT, params);
+ EXPECT_TRUE(result == ErrorCode::UNSUPPORTED_MGF_DIGEST ||
+ result == ErrorCode::INCOMPATIBLE_MGF_DIGEST);
+}
+
+/*
* EncryptionOperationsTest.RsaOaepWithMGFIncompatibleDigest
*
* Verifies that RSA-OAEP decryption operations fail in the correct way when asked to operate
@@ -5395,6 +5599,7 @@
*/
TEST_P(EncryptionOperationsTest, AesEcbCbcNoPaddingWrongInputSize) {
for (BlockMode blockMode : {BlockMode::ECB, BlockMode::CBC}) {
+ SCOPED_TRACE(testing::Message() << "AES-" << blockMode);
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.AesEncryptionKey(128)
@@ -5614,6 +5819,328 @@
CheckAesIncrementalEncryptOperation(BlockMode::GCM, 240);
}
+/*
+ * EncryptionOperationsTest.Aes128CBCNoPaddingOneByteAtATime
+ * Verifies input and output sizes of AES/CBC/NoPadding Algorithm.
+ */
+TEST_P(EncryptionOperationsTest, Aes128CBCNoPaddingOneByteAtATime) {
+ string kat_key = hex2str("7E3D723C09A9852B24F584F9D916F6A8");
+ string kat_iv = hex2str("944AE274D983892EADE422274858A96A");
+ string kat_plaintext =
+ hex2str("044E15899A080AADEB6778F64323B64D2CBCBADB338DF93B9AC459D4F41029"
+ "809FFF37081C22EF278F896AB213A2A631");
+ string kat_ciphertext =
+ hex2str("B419293FCBD686F2913D1CF947E510D42FAFEDE5593C98AFD6AEE272596A"
+ "56FE42C22F2A5E3B6A02BA9D8D0DE1E9A810");
+ AesCheckEncryptOneByteAtATime(kat_key, BlockMode::CBC, PaddingMode::NONE, kat_iv, kat_plaintext,
+ kat_ciphertext);
+}
+
+/*
+ * EncryptionOperationsTest.Aes128CBCPKCS7PaddingOneByteAtATime
+ * Verifies input and output sizes of AES/CBC/PKCS7Padding Algorithm.
+ */
+TEST_P(EncryptionOperationsTest, Aes128CBCPKCS7PaddingOneByteAtATime) {
+ string kat_key = hex2str("F16E698472578E919D92806262C5169F");
+ string kat_iv = hex2str("EF743540F8421ACA128A3247521F3E7D");
+ string kat_plaintext =
+ hex2str("5BEBF33569D90BF5E853814E12E7C7AA5758013F755773E29F4A25EC26EEB7"
+ "65F7F2DC251F7DC62AEFCA1E8A5A11A1DCD44F0BD8FB593A5AE3");
+ string kat_ciphertext =
+ hex2str("3197CF6DB9466188B5FED375329324EE7D6092A8C0E41DFAF49E3724271427"
+ "896D56A6243C0D59D6639722AF93CD53449BDDABF9C5F153EBDBFED9ED98C8CC37");
+ AesCheckEncryptOneByteAtATime(kat_key, BlockMode::CBC, PaddingMode::PKCS7, kat_iv,
+ kat_plaintext, kat_ciphertext);
+}
+
+/*
+ * EncryptionOperationsTest.Aes128CTRNoPaddingOneByteAtATime
+ * Verifies input and output sizes of AES/CTR/NoPadding Algorithm.
+ */
+TEST_P(EncryptionOperationsTest, Aes128CTRNoPaddingOneByteAtATime) {
+ string kat_key = hex2str("4713a7b2f93efe809b42ecc45213ef9f");
+ string kat_iv = hex2str("ebfa19b0ebf3d57feabd4c4bd04bea01");
+ string kat_plaintext =
+ hex2str("6d2c07e1fc86f99c6e2a8f6567828b4262a9c23d0f3ed8ab32482283c79796"
+ "f0adba1bcd3736084996452a917fae98005aebe61f9e91c3");
+ string kat_ciphertext =
+ hex2str("345deb1d67b95e600e05cad4c32ec381aadb3e2c1ec7e0fb956dc38e6860cf"
+ "0553535566e1b12fa9f87d29266ca26df427233df035df28");
+ AesCheckEncryptOneByteAtATime(kat_key, BlockMode::CTR, PaddingMode::NONE, kat_iv, kat_plaintext,
+ kat_ciphertext);
+}
+
+/*
+ * EncryptionOperationsTest.Aes128ECBNoPaddingOneByteAtATime
+ * Verifies input and output sizes of AES/ECB/NoPadding Algorithm.
+ */
+TEST_P(EncryptionOperationsTest, Aes128ECBNoPaddingOneByteAtATime) {
+ string kat_key = hex2str("7DA2467F068854B3CB36E5C333A16619");
+ string kat_plaintext =
+ hex2str("9A07C9575AD9CE209DF9F3953965CEBE8208587C7AE575A1904BF25048946D"
+ "7B6168A9A27BCE554BEA94EF26E6C742A0");
+ string kat_ciphertext =
+ hex2str("8C47E49420FC92AC4CA2C601BC3F8AC31D01B260B7B849F2B8EEDFFFED8F36"
+ "C31CBDA0D22F95C9C2A48C347E8C77AC82");
+ AesCheckEncryptOneByteAtATime(kat_key, BlockMode::ECB, PaddingMode::NONE, "", kat_plaintext,
+ kat_ciphertext);
+}
+
+/*
+ * EncryptionOperationsTest.Aes128ECBPKCS7PaddingOneByteAtATime
+ * Verifies input and output sizes of AES/ECB/PKCS7Padding Algorithm.
+ */
+TEST_P(EncryptionOperationsTest, Aes128ECBPKCS7PaddingOneByteAtATime) {
+ string kat_key = hex2str("C3BE04BCCB3D99B85290F113FE7AF194");
+ string kat_plaintext =
+ hex2str("348C213FD8DF3F990C20C5ACBF07B34B6264AE245784A5A6176DBFB1C2E7DD"
+ "27E52CC92B8EEE40614F05B507B355F6354A2705BD86");
+ string kat_ciphertext =
+ hex2str("07CD05C41FEDEDDC5DB4B3E35E676153184A119AA4DFDDC290616F1FA60093"
+ "1DE6BEA9BDB90D1D733899946F8C8E5C0C4383F99F5D88E27F3EBC0C6E52759ED3");
+ AesCheckEncryptOneByteAtATime(kat_key, BlockMode::ECB, PaddingMode::PKCS7, "", kat_plaintext,
+ kat_ciphertext);
+}
+
+/*
+ * EncryptionOperationsTest.Aes128GCMNoPaddingOneByteAtATime
+ * Verifies input and output sizes of AES/GCM/NoPadding Algorithm.
+ */
+TEST_P(EncryptionOperationsTest, Aes128GCMNoPaddingOneByteAtATime) {
+ string kat_key = hex2str("ba76354f0aed6e8d91f45c4ff5a062db");
+ string kat_iv = hex2str("b79437ae08ff355d7d8a4d0f");
+ string kat_plaintext =
+ hex2str("6d7596a8fd56ceaec61de7940984b7736fec44f572afc3c8952e4dc6541e2b"
+ "c6a702c440a37610989543f63fedb047ca2173bc18581944");
+ string kat_ciphertext =
+ hex2str("b3f6799e8f9326f2df1e80fcd2cb16d78c9dc7cc14bb677862dc6c639b3a63"
+ "38d24b312d3989e5920b5dbfc976765efbfe57bb385940a7a43bdf05bddae3c9d6a2fb"
+ "bdfcc0cba0");
+
+ AesCheckEncryptOneByteAtATime(kat_key, BlockMode::GCM, PaddingMode::NONE, kat_iv, kat_plaintext,
+ kat_ciphertext);
+}
+
+/*
+ * EncryptionOperationsTest.Aes192CBCNoPaddingOneByteAtATime
+ * Verifies input and output sizes of AES/CBC/NoPadding Algorithm.
+ */
+TEST_P(EncryptionOperationsTest, Aes192CBCNoPaddingOneByteAtATime) {
+ if (SecLevel() == SecurityLevel::STRONGBOX) {
+ GTEST_SKIP() << "Key size 192 is not supported by Strongbox.";
+ }
+ string kat_key = hex2str("be8cc4e25cce46e5d55725e2391f7d3cf59ed60062f5a43b");
+ string kat_iv = hex2str("80a199aab0eee77e7762ddf3b3a32f40");
+ string kat_plaintext =
+ hex2str("064f9200e0df37d4711af4a69d11addf9e1c345d9d8195f9f1f715019ce96a"
+ "167f2497c994bd496eb80bfb2ba2c9d5af");
+ string kat_ciphertext =
+ hex2str("859b90becaa85e95a71e104efbd7a3b723bcbf4eb39865544a05d9e90b6fe5"
+ "72c134552f3a138e726fbe493b3a839598");
+ AesCheckEncryptOneByteAtATime(kat_key, BlockMode::CBC, PaddingMode::NONE, kat_iv, kat_plaintext,
+ kat_ciphertext);
+}
+
+/*
+ * EncryptionOperationsTest.Aes192CBCPKCS7PaddingOneByteAtATime
+ * Verifies input and output sizes of AES/CBC/PKCS7Padding Algorithm.
+ */
+TEST_P(EncryptionOperationsTest, Aes192CBCPKCS7PaddingOneByteAtATime) {
+ if (SecLevel() == SecurityLevel::STRONGBOX) {
+ GTEST_SKIP() << "Key size 192 is not supported by Strongbox.";
+ }
+ string kat_key = hex2str("68969215ec41e4df7d23de0e806f458f52aff492bd7c5263");
+ string kat_iv = hex2str("e61d13dfbf0533289f0e7950209da418");
+ string kat_plaintext =
+ hex2str("8d4c1cac27511ee2d82409a7f378e7e402b0eb189c1eaa5c506eb72a9074"
+ "b170");
+ string kat_ciphertext =
+ hex2str("e70bcd62c595dc1b2b8c197bb91a7447e1be2cbcf3fdc69e7e991faf0f57cf"
+ "4e3884138ff403a41fd99818708ada301c");
+ AesCheckEncryptOneByteAtATime(kat_key, BlockMode::CBC, PaddingMode::PKCS7, kat_iv,
+ kat_plaintext, kat_ciphertext);
+}
+
+/*
+ * EncryptionOperationsTest.Aes192CTRNoPaddingOneByteAtATime
+ * Verifies input and output sizes of AES/CTR/NoPadding Algorithm.
+ */
+TEST_P(EncryptionOperationsTest, Aes192CTRNoPaddingOneByteAtATime) {
+ if (SecLevel() == SecurityLevel::STRONGBOX) {
+ GTEST_SKIP() << "Key size 192 is not supported by Strongbox.";
+ }
+ string kat_key = hex2str("5e2036e790d38815c90beb67a1c9e5aa0e167ef082927317");
+ string kat_iv = hex2str("df0694959b89054156962d68a226965c");
+ string kat_plaintext =
+ hex2str("6ed2781c99e03e45314d6019932220c2c98130c53f9f67ad10ac519adf50e9"
+ "28091e09cdbbd3b42b");
+ string kat_ciphertext =
+ hex2str("e427b6666502e05b82d0b20ae50e862b1936d71266fc49178ac984e71571f2"
+ "2ae0f90f0c19f42b4a");
+ AesCheckEncryptOneByteAtATime(kat_key, BlockMode::CTR, PaddingMode::NONE, kat_iv, kat_plaintext,
+ kat_ciphertext);
+}
+
+/*
+ * EncryptionOperationsTest.Aes192ECBNoPaddingOneByteAtATime
+ * Verifies input and output sizes of AES/ECB/NoPadding Algorithm.
+ */
+TEST_P(EncryptionOperationsTest, Aes192ECBNoPaddingOneByteAtATime) {
+ if (SecLevel() == SecurityLevel::STRONGBOX) {
+ GTEST_SKIP() << "Key size 192 is not supported by Strongbox.";
+ }
+ string kat_key = hex2str("3cab83fb338ba985fbfe74c5e9d2e900adb570b1d67faf92");
+ string kat_plaintext =
+ hex2str("2cc64c335a13fb838f3c6aad0a6b47297ca90bb886ddb059200f0b41740c"
+ "44ab");
+ string kat_ciphertext =
+ hex2str("9c5c825328f5ee0aa24947e374d3f9165f484b39dd808c790d7a12964810"
+ "2453");
+ AesCheckEncryptOneByteAtATime(kat_key, BlockMode::ECB, PaddingMode::NONE, "", kat_plaintext,
+ kat_ciphertext);
+}
+
+/*
+ * EncryptionOperationsTest.Aes192ECBPKCS7PaddingOneByteAtATime
+ * Verifies input and output sizes of AES/ECB/PKCS7Padding Algorithm.
+ */
+TEST_P(EncryptionOperationsTest, Aes192ECBPKCS7PaddingOneByteAtATime) {
+ if (SecLevel() == SecurityLevel::STRONGBOX) {
+ GTEST_SKIP() << "Key size 192 is not supported by Strongbox.";
+ }
+ string kat_key = hex2str("d57f4e5446f736c16476ec4db5decc7b1bf3936e4f7e4618");
+ string kat_plaintext =
+ hex2str("b115777f1ee7a43a07daa6401e59c46b7a98213a8747eabfbe3ca4ec93524d"
+ "e2c7");
+ string kat_ciphertext =
+ hex2str("1e92cd20da08bb5fa174a7a69879d4fc25a155e6af06d75b26c5b450d273c8"
+ "bb7e3a889dd4a9589098b44acf1056e7aa");
+ AesCheckEncryptOneByteAtATime(kat_key, BlockMode::ECB, PaddingMode::PKCS7, "", kat_plaintext,
+ kat_ciphertext);
+}
+
+/*
+ * EncryptionOperationsTest.Aes192GCMNoPaddingOneByteAtATime
+ * Verifies input and output sizes of AES/GCM/NoPadding Algorithm.
+ */
+TEST_P(EncryptionOperationsTest, Aes192GCMNoPaddingOneByteAtATime) {
+ if (SecLevel() == SecurityLevel::STRONGBOX) {
+ GTEST_SKIP() << "Key size 192 is not supported by Strongbox.";
+ }
+ string kat_key = hex2str("21339fc1d011abca65d50ce2365230603fd47d07e8830f6e");
+ string kat_iv = hex2str("d5fb1469a8d81dd75286a418");
+ string kat_plaintext =
+ hex2str("cf776dedf53a828d51a0073db3ef0dd1ee19e2e9e243ce97e95841bb9ad4e3"
+ "ff52");
+ string kat_ciphertext =
+ hex2str("3a0d48278111d3296bc663df8a5dbeb2474ea47fd85b608f8d9375d9dcf7de"
+ "1413ad70fb0e1970669095ad77ebb5974ae8");
+
+ AesCheckEncryptOneByteAtATime(kat_key, BlockMode::GCM, PaddingMode::NONE, kat_iv, kat_plaintext,
+ kat_ciphertext);
+}
+
+/*
+ * EncryptionOperationsTest.Aes256CBCNoPaddingOneByteAtATime
+ * Verifies input and output sizes of AES/CBC/NoPadding Algorithm.
+ */
+TEST_P(EncryptionOperationsTest, Aes256CBCNoPaddingOneByteAtATime) {
+ string kat_key = hex2str("dd2f20dc6b98c100bac919120ff95eb5d96003f8229987b283a1e777b0cd5c30");
+ string kat_iv = hex2str("23b4d85239fb90db93b07a981e90a170");
+ string kat_plaintext =
+ hex2str("2fbe5d46dca5cea433e550d8b291740ab9551c2a2d37680d7fb7b993225f58"
+ "494cb53caca353e4b637ba05687be20f8d");
+ string kat_ciphertext =
+ hex2str("5aba24fc316936c8369061ee8fe463e4faed04288e204456626b988c0e376b"
+ "6047da1e4fd7c4e1cf2656097f75ae8685");
+ AesCheckEncryptOneByteAtATime(kat_key, BlockMode::CBC, PaddingMode::NONE, kat_iv, kat_plaintext,
+ kat_ciphertext);
+}
+
+/*
+ * EncryptionOperationsTest.Aes256CBCPKCS7PaddingOneByteAtATime
+ * Verifies input and output sizes of AES/CBC/PKCS7Padding Algorithm.
+ */
+TEST_P(EncryptionOperationsTest, Aes256CBCPKCS7PaddingOneByteAtATime) {
+ string kat_key = hex2str("03ab2510520f5cfebfab0a17a7f8324c9634911f6fc59e586f85346bb38ac88a");
+ string kat_iv = hex2str("9af96967195bb0184f129beffa8241ae");
+ string kat_plaintext =
+ hex2str("2d6944653ac14988a772a2730b7c5bfa99a21732ae26f40cdc5b3a2874c794"
+ "2545a82b73c48078b9dae62261c65909");
+ string kat_ciphertext =
+ hex2str("26b308f7e1668b55705a79c8b3ad10e244655f705f027f390a5c34e4536f51"
+ "9403a71987b95124073d69f2a3cb95b0ab");
+ AesCheckEncryptOneByteAtATime(kat_key, BlockMode::CBC, PaddingMode::PKCS7, kat_iv,
+ kat_plaintext, kat_ciphertext);
+}
+
+/*
+ * EncryptionOperationsTest.Aes256CTRNoPaddingOneByteAtATime
+ * Verifies input and output sizes of AES/CTR/NoPadding Algorithm.
+ */
+TEST_P(EncryptionOperationsTest, Aes256CTRNoPaddingOneByteAtATime) {
+ string kat_key = hex2str("928b380a8fed4b4b4cfeb56e0c66a4cb0f9ff58d61ac68bcfd0e3fbd910a684f");
+ string kat_iv = hex2str("0b678a5249e6eeda461dfb4776b6c58e");
+ string kat_plaintext =
+ hex2str("f358de57543b297e997cba46fb9100553d6abd65377e55b9aac3006400ead1"
+ "1f6db3c884");
+ string kat_ciphertext =
+ hex2str("a07a35fbd1776ad81462e1935f542337add60962bf289249476817b6ddd532"
+ "a7be30d4c3");
+ AesCheckEncryptOneByteAtATime(kat_key, BlockMode::CTR, PaddingMode::NONE, kat_iv, kat_plaintext,
+ kat_ciphertext);
+}
+
+/*
+ * EncryptionOperationsTest.Aes256ECBNoPaddingOneByteAtATime
+ * Verifies input and output sizes of AES/ECB/NoPadding Algorithm.
+ */
+TEST_P(EncryptionOperationsTest, Aes256ECBNoPaddingOneByteAtATime) {
+ string kat_key = hex2str("fa4622d9cf6485075daedd33d2c4fffdf859e2edb7f7df4f04603f7e647fae90");
+ string kat_plaintext =
+ hex2str("96ccabbe0c68970d8cdee2b30ab43c2d61cc50ee68271e77571e72478d713a"
+ "31a476d6806b8116089c6ec50bb543200f");
+ string kat_ciphertext =
+ hex2str("0e81839e9dfbfe3b503d619e676abe5ac80fac3f245d8f09b9134b1b32a67d"
+ "c83e377faf246288931136bef2a07c0be4");
+ AesCheckEncryptOneByteAtATime(kat_key, BlockMode::ECB, PaddingMode::NONE, "", kat_plaintext,
+ kat_ciphertext);
+}
+
+/*
+ * EncryptionOperationsTest.Aes256ECBPKCS7PaddingOneByteAtATime
+ * Verifies input and output sizes of AES/ECB/PKCS7Padding Algorithm.
+ */
+TEST_P(EncryptionOperationsTest, Aes256ECBPKCS7PaddingOneByteAtATime) {
+ string kat_key = hex2str("bf3f07c68467fead0ca8e2754500ab514258abf02eb7e615a493bcaaa45d5ee1");
+ string kat_plaintext =
+ hex2str("af0757e49018dad628f16998628a407db5f28291bef3bc2e4d8a5a31fb238e"
+ "6f");
+ string kat_ciphertext =
+ hex2str("21ec3011074bf1ef140643d47130326c5e183f61237c69bc77551ca207d71f"
+ "c2b90cfac6c8d2d125e5cd9ff353dee0df");
+ AesCheckEncryptOneByteAtATime(kat_key, BlockMode::ECB, PaddingMode::PKCS7, "", kat_plaintext,
+ kat_ciphertext);
+}
+
+/*
+ * EncryptionOperationsTest.Aes256GCMNoPaddingOneByteAtATime
+ * Verifies input and output sizes of AES/GCM/NoPadding Algorithm.
+ */
+TEST_P(EncryptionOperationsTest, Aes256GCMNoPaddingOneByteAtATime) {
+ string kat_key = hex2str("7972140d831eedac75d5ea515c9a4c3bb124499a90b5f317ac1a685e88fae395");
+ string kat_iv = hex2str("a66c5252808d823dd4151fed");
+ string kat_plaintext =
+ hex2str("c2b9dabf3a55adaa94e8c0d1e77a84a3435aee23b2c3c4abb587b09a9c2afb"
+ "f0");
+ string kat_ciphertext =
+ hex2str("a960619314657b2afb96b93bebb372bffd09e19d53e351f17d1ba2611f9dc3"
+ "3c9c92d563e8fd381254ac262aa2a4ea0d");
+
+ AesCheckEncryptOneByteAtATime(kat_key, BlockMode::GCM, PaddingMode::NONE, kat_iv, kat_plaintext,
+ kat_ciphertext);
+}
+
struct AesCtrSp80038aTestVector {
const char* key;
const char* nonce;
@@ -5769,6 +6296,7 @@
// Zero input message
string message = "";
for (auto padding : {PaddingMode::NONE, PaddingMode::PKCS7}) {
+ SCOPED_TRACE(testing::Message() << "AES padding=" << padding);
auto params = AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(padding);
AuthorizationSet out_params;
string ciphertext1 = EncryptMessage(message, params, &out_params);
@@ -6163,7 +6691,7 @@
// Encrypt
AuthorizationSet begin_out_params;
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &begin_out_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &begin_out_params));
string ciphertext;
AuthorizationSet finish_out_params;
ASSERT_EQ(ErrorCode::OK, UpdateAad(aad));
@@ -6206,7 +6734,7 @@
.Authorization(TAG_MAC_LENGTH, tag_bits);
AuthorizationSet begin_out_params;
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
// No data, AAD only.
EXPECT_EQ(ErrorCode::OK, UpdateAad("foo"));
@@ -6222,7 +6750,7 @@
begin_params.push_back(begin_out_params);
// Decrypt
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
EXPECT_EQ(ErrorCode::OK, UpdateAad("foofoo"));
string plaintext;
EXPECT_EQ(ErrorCode::OK, Finish(ciphertext, &plaintext));
@@ -6249,7 +6777,7 @@
.Authorization(TAG_MAC_LENGTH, 128);
AuthorizationSet begin_out_params;
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
EXPECT_EQ(ErrorCode::OK, UpdateAad("foo"));
string ciphertext;
@@ -6283,7 +6811,7 @@
// Encrypt
AuthorizationSet begin_out_params;
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
EXPECT_EQ(ErrorCode::OK, UpdateAad("foobar"));
string ciphertext;
EXPECT_EQ(ErrorCode::OK, Finish(message, &ciphertext));
@@ -6292,7 +6820,7 @@
begin_params.push_back(begin_out_params);
// Decrypt.
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params, &begin_out_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params, &begin_out_params));
EXPECT_EQ(ErrorCode::OK, UpdateAad("barfoo"));
string plaintext;
EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(ciphertext, &plaintext));
@@ -6319,7 +6847,7 @@
// Encrypt
AuthorizationSet begin_out_params;
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
EXPECT_EQ(ErrorCode::OK, UpdateAad("foobar"));
string ciphertext;
AuthorizationSet finish_out_params;
@@ -6329,7 +6857,7 @@
begin_params.push_back(TAG_NONCE, AidlBuf("123456789012"));
// Decrypt.
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params, &begin_out_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params, &begin_out_params));
EXPECT_EQ(ErrorCode::OK, UpdateAad("foobar"));
string plaintext;
EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(ciphertext, &plaintext));
@@ -6361,7 +6889,7 @@
// Encrypt
AuthorizationSet begin_out_params;
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &begin_out_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &begin_out_params));
EXPECT_EQ(ErrorCode::OK, UpdateAad(aad));
string ciphertext;
EXPECT_EQ(ErrorCode::OK, Finish(message, &ciphertext));
@@ -6373,7 +6901,7 @@
params.push_back(begin_out_params);
// Decrypt.
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
EXPECT_EQ(ErrorCode::OK, UpdateAad(aad));
string plaintext;
EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(ciphertext, &plaintext));
@@ -6437,6 +6965,7 @@
.Padding(PaddingMode::PKCS7)));
for (size_t i = 0; i < 32; ++i) {
+ SCOPED_TRACE(testing::Message() << "msg size=" << i);
string message(i, 'a');
auto inParams =
AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
@@ -6486,7 +7015,7 @@
for (size_t i = 0; i < kMaxPaddingCorruptionRetries; ++i) {
++ciphertext[ciphertext.size() / 2];
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
string plaintext;
EXPECT_EQ(ErrorCode::OK, Update(ciphertext, &plaintext));
ErrorCode error = Finish(&plaintext);
@@ -6747,6 +7276,7 @@
*/
TEST_P(EncryptionOperationsTest, TripleDesEcbCbcNoPaddingWrongInputSize) {
for (BlockMode blockMode : {BlockMode::ECB, BlockMode::CBC}) {
+ SCOPED_TRACE(testing::Message() << "BlockMode::" << blockMode);
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.TripleDesEncryptionKey(168)
.BlockMode(blockMode)
@@ -6758,7 +7288,7 @@
auto begin_params =
AuthorizationSetBuilder().BlockMode(blockMode).Padding(PaddingMode::NONE);
AuthorizationSet output_params;
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &output_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &output_params));
string ciphertext;
EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, Finish(message, "", &ciphertext));
@@ -6805,6 +7335,7 @@
// Try various message lengths; all should fail.
for (size_t i = 0; i <= 32; i++) {
+ SCOPED_TRACE(testing::Message() << "i = " << i);
auto begin_params =
AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::PKCS7);
EXPECT_EQ(ErrorCode::INCOMPATIBLE_PADDING_MODE, Begin(KeyPurpose::ENCRYPT, begin_params));
@@ -6837,7 +7368,7 @@
for (size_t i = 0; i < kMaxPaddingCorruptionRetries; ++i) {
SCOPED_TRACE(testing::Message() << "i = " << i);
++ciphertext[ciphertext.size() / 2];
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
string plaintext;
EXPECT_EQ(ErrorCode::OK, Update(ciphertext, &plaintext));
ErrorCode error = Finish(&plaintext);
@@ -6869,7 +7400,7 @@
AuthorizationSet input_params =
AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::NONE);
AuthorizationSet output_params;
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, input_params, &output_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, input_params, &output_params));
string ciphertext;
for (size_t i = 0; i < message.size(); i += increment)
@@ -6883,7 +7414,7 @@
input_params.push_back(TAG_PADDING, PaddingMode::NONE);
output_params.Clear();
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, input_params, &output_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, input_params, &output_params));
string plaintext;
for (size_t i = 0; i < ciphertext.size(); i += increment)
EXPECT_EQ(ErrorCode::OK, Update(ciphertext.substr(i, increment), &plaintext));
@@ -7000,7 +7531,7 @@
} else {
// Usage count limit tag is enforced by keystore, keymint does nothing.
EXPECT_TRUE(keystore_auths.Contains(TAG_USAGE_COUNT_LIMIT, 1U));
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params));
}
}
@@ -7047,7 +7578,7 @@
} else {
// Usage count limit tag is enforced by keystore, keymint does nothing.
EXPECT_TRUE(keystore_auths.Contains(TAG_USAGE_COUNT_LIMIT, 3U));
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params));
}
}
@@ -7093,7 +7624,7 @@
} else {
// Usage count limit tag is enforced by keystore, keymint does nothing.
EXPECT_TRUE(keystore_auths.Contains(TAG_USAGE_COUNT_LIMIT, 1U));
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::SIGN, params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::SIGN, params));
}
}
@@ -7140,7 +7671,7 @@
} else {
// Usage count limit tag is enforced by keystore, keymint does nothing.
EXPECT_TRUE(keystore_auths.Contains(TAG_USAGE_COUNT_LIMIT, 3U));
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::SIGN, params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::SIGN, params));
}
}
@@ -7453,7 +7984,7 @@
EXPECT_EQ(ErrorCode::OK, Abort(op_handles[j]))
<< "Aboort failed for i = " << j << std::endl;
}
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, key_blob_, params, &out_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, key_blob_, params, &out_params));
AbortIfNeeded();
}
@@ -7474,11 +8005,12 @@
.Padding(PaddingMode::NONE)));
for (int msg_size = 8 /* 256 bytes */; msg_size <= 11 /* 2 KiB */; msg_size++) {
+ SCOPED_TRACE(testing::Message() << "msg_size = " << msg_size);
auto cipher_params =
AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE);
AuthorizationSet out_params;
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, cipher_params, &out_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, cipher_params, &out_params));
string plain_message = std::string(1 << msg_size, 'x');
string encrypted_message;
@@ -7489,7 +8021,7 @@
<< "Encrypt finish returned OK, but did not consume all of the given input";
cipher_params.push_back(out_params);
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, cipher_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, cipher_params));
string decrypted_message;
rc = Finish(encrypted_message, &decrypted_message);
@@ -7655,7 +8187,7 @@
if (curve != localCurve) {
// If the keys are using different curves KeyMint should fail with
// ErrorCode:INVALID_ARGUMENT. Check that.
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::AGREE_KEY, AuthorizationSetBuilder()));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::AGREE_KEY, AuthorizationSetBuilder()));
string ZabFromKeyMintStr;
EXPECT_EQ(ErrorCode::INVALID_ARGUMENT,
Finish(string(localPublicKey.begin(), localPublicKey.end()),
@@ -7787,6 +8319,7 @@
GenerateKeyMintEcKey(curve, &kmPubKey);
for (auto localCurve : ValidCurves()) {
+ SCOPED_TRACE(testing::Message() << "local-curve-" << localCurve);
if (localCurve == curve) {
continue;
}
@@ -7795,7 +8328,7 @@
vector<uint8_t> encodedPublicKey;
GenerateLocalEcKey(localCurve, &privKey, &encodedPublicKey);
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::AGREE_KEY, AuthorizationSetBuilder()));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::AGREE_KEY, AuthorizationSetBuilder()));
string ZabFromKeyMintStr;
EXPECT_EQ(ErrorCode::INVALID_ARGUMENT,
Finish(string(encodedPublicKey.begin(), encodedPublicKey.end()),
diff --git a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
index 7184613..6d9c8c9 100644
--- a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
+++ b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <memory>
+#include <string>
#define LOG_TAG "VtsRemotelyProvisionableComponentTests"
#include <AndroidRemotelyProvisionedComponentDevice.h>
@@ -30,6 +32,7 @@
#include <openssl/ec_key.h>
#include <openssl/x509.h>
#include <remote_prov/remote_prov_utils.h>
+#include <optional>
#include <set>
#include <vector>
@@ -43,6 +46,7 @@
namespace {
constexpr int32_t VERSION_WITH_UNIQUE_ID_SUPPORT = 2;
+constexpr int32_t VERSION_WITHOUT_TEST_MODE = 3;
#define INSTANTIATE_REM_PROV_AIDL_TEST(name) \
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(name); \
@@ -57,22 +61,6 @@
using namespace remote_prov;
using namespace keymaster;
-std::set<std::string> getAllowedVbStates() {
- return {"green", "yellow", "orange"};
-}
-
-std::set<std::string> getAllowedBootloaderStates() {
- return {"locked", "unlocked"};
-}
-
-std::set<std::string> getAllowedSecurityLevels() {
- return {"tee", "strongbox"};
-}
-
-std::set<std::string> getAllowedAttIdStates() {
- return {"locked", "open"};
-}
-
bytevec string_to_bytevec(const char* s) {
const uint8_t* p = reinterpret_cast<const uint8_t*>(s);
return bytevec(p, p + strlen(s));
@@ -213,9 +201,7 @@
RpcHardwareInfo hwInfo;
ASSERT_TRUE(rpc->getHardwareInfo(&hwInfo).isOk());
- int32_t version;
- ASSERT_TRUE(rpc->getInterfaceVersion(&version).isOk());
- if (version >= VERSION_WITH_UNIQUE_ID_SUPPORT) {
+ if (hwInfo.versionNumber >= VERSION_WITH_UNIQUE_ID_SUPPORT) {
ASSERT_TRUE(hwInfo.uniqueId);
auto [_, wasInserted] = uniqueIds.insert(*hwInfo.uniqueId);
EXPECT_TRUE(wasInserted);
@@ -245,10 +231,7 @@
* Verify that the unique id is within the length limits as described in RpcHardwareInfo.aidl.
*/
TEST_P(GetHardwareInfoTests, uniqueId) {
- int32_t version;
- ASSERT_TRUE(provisionable_->getInterfaceVersion(&version).isOk());
-
- if (version < VERSION_WITH_UNIQUE_ID_SUPPORT) {
+ if (rpcHardwareInfo.versionNumber < VERSION_WITH_UNIQUE_ID_SUPPORT) {
return;
}
@@ -259,6 +242,19 @@
EXPECT_LE(hwInfo.uniqueId->size(), 32);
}
+/**
+ * Verify implementation supports at least MIN_SUPPORTED_NUM_KEYS_IN_CSR keys in a CSR.
+ */
+TEST_P(GetHardwareInfoTests, supportedNumKeysInCsr) {
+ if (rpcHardwareInfo.versionNumber < VERSION_WITHOUT_TEST_MODE) {
+ return;
+ }
+
+ RpcHardwareInfo hwInfo;
+ ASSERT_TRUE(provisionable_->getHardwareInfo(&hwInfo).isOk());
+ ASSERT_GE(hwInfo.supportedNumKeysInCsr, RpcHardwareInfo::MIN_SUPPORTED_NUM_KEYS_IN_CSR);
+}
+
using GenerateKeyTests = VtsRemotelyProvisionedComponentTests;
INSTANTIATE_REM_PROV_AIDL_TEST(GenerateKeyTests);
@@ -352,13 +348,13 @@
bool testMode = true;
auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &macedPubKey, &privateKeyBlob);
ASSERT_TRUE(status.isOk());
-
check_maced_pubkey(macedPubKey, testMode, nullptr);
}
-class CertificateRequestTest : public VtsRemotelyProvisionedComponentTests {
+class CertificateRequestTestBase : public VtsRemotelyProvisionedComponentTests {
protected:
- CertificateRequestTest() : eekId_(string_to_bytevec("eekid")), challenge_(randomBytes(64)) {}
+ CertificateRequestTestBase()
+ : eekId_(string_to_bytevec("eekid")), challenge_(randomBytes(64)) {}
void generateTestEekChain(size_t eekLength) {
auto chain = generateEekChain(rpcHardwareInfo.supportedEekCurve, eekLength, eekId_);
@@ -382,157 +378,6 @@
}
}
- ErrMsgOr<bytevec> getSessionKey(ErrMsgOr<std::pair<bytevec, bytevec>>& senderPubkey) {
- if (rpcHardwareInfo.supportedEekCurve == RpcHardwareInfo::CURVE_25519 ||
- rpcHardwareInfo.supportedEekCurve == RpcHardwareInfo::CURVE_NONE) {
- return x25519_HKDF_DeriveKey(testEekChain_.last_pubkey, testEekChain_.last_privkey,
- senderPubkey->first, false /* senderIsA */);
- } else {
- return ECDH_HKDF_DeriveKey(testEekChain_.last_pubkey, testEekChain_.last_privkey,
- senderPubkey->first, false /* senderIsA */);
- }
- }
-
- void checkProtectedData(const DeviceInfo& deviceInfo, const cppbor::Array& keysToSign,
- const bytevec& keysToSignMac, const ProtectedData& protectedData,
- std::vector<BccEntryData>* bccOutput = nullptr) {
- auto [parsedProtectedData, _, protDataErrMsg] = cppbor::parse(protectedData.protectedData);
- ASSERT_TRUE(parsedProtectedData) << protDataErrMsg;
- ASSERT_TRUE(parsedProtectedData->asArray());
- ASSERT_EQ(parsedProtectedData->asArray()->size(), kCoseEncryptEntryCount);
-
- auto senderPubkey = getSenderPubKeyFromCoseEncrypt(parsedProtectedData);
- ASSERT_TRUE(senderPubkey) << senderPubkey.message();
- EXPECT_EQ(senderPubkey->second, eekId_);
-
- auto sessionKey = getSessionKey(senderPubkey);
- ASSERT_TRUE(sessionKey) << sessionKey.message();
-
- auto protectedDataPayload =
- decryptCoseEncrypt(*sessionKey, parsedProtectedData.get(), bytevec{} /* aad */);
- ASSERT_TRUE(protectedDataPayload) << protectedDataPayload.message();
-
- auto [parsedPayload, __, payloadErrMsg] = cppbor::parse(*protectedDataPayload);
- ASSERT_TRUE(parsedPayload) << "Failed to parse payload: " << payloadErrMsg;
- ASSERT_TRUE(parsedPayload->asArray());
- // Strongbox may contain additional certificate chain.
- EXPECT_LE(parsedPayload->asArray()->size(), 3U);
-
- auto& signedMac = parsedPayload->asArray()->get(0);
- auto& bcc = parsedPayload->asArray()->get(1);
- ASSERT_TRUE(signedMac && signedMac->asArray());
- ASSERT_TRUE(bcc && bcc->asArray());
-
- // BCC is [ pubkey, + BccEntry]
- auto bccContents = validateBcc(bcc->asArray());
- ASSERT_TRUE(bccContents) << "\n" << bccContents.message() << "\n" << prettyPrint(bcc.get());
- ASSERT_GT(bccContents->size(), 0U);
-
- auto [deviceInfoMap, __2, deviceInfoErrMsg] = cppbor::parse(deviceInfo.deviceInfo);
- ASSERT_TRUE(deviceInfoMap) << "Failed to parse deviceInfo: " << deviceInfoErrMsg;
- ASSERT_TRUE(deviceInfoMap->asMap());
- checkDeviceInfo(deviceInfoMap->asMap(), deviceInfo.deviceInfo);
- auto& signingKey = bccContents->back().pubKey;
- deviceInfoMap->asMap()->canonicalize();
- auto macKey = verifyAndParseCoseSign1(signedMac->asArray(), signingKey,
- cppbor::Array() // SignedMacAad
- .add(challenge_)
- .add(std::move(deviceInfoMap))
- .add(keysToSignMac)
- .encode());
- ASSERT_TRUE(macKey) << macKey.message();
-
- auto coseMac0 = cppbor::Array()
- .add(cppbor::Map() // protected
- .add(ALGORITHM, HMAC_256)
- .canonicalize()
- .encode())
- .add(cppbor::Map()) // unprotected
- .add(keysToSign.encode()) // payload (keysToSign)
- .add(keysToSignMac); // tag
-
- auto macPayload = verifyAndParseCoseMac0(&coseMac0, *macKey);
- ASSERT_TRUE(macPayload) << macPayload.message();
-
- if (bccOutput) {
- *bccOutput = std::move(*bccContents);
- }
- }
-
- void checkType(const cppbor::Map* devInfo, uint8_t majorType, std::string entryName) {
- const auto& val = devInfo->get(entryName);
- ASSERT_TRUE(val) << entryName << " does not exist";
- ASSERT_EQ(val->type(), majorType) << entryName << " has the wrong type.";
- switch (majorType) {
- case cppbor::TSTR:
- EXPECT_GT(val->asTstr()->value().size(), 0);
- break;
- case cppbor::BSTR:
- EXPECT_GT(val->asBstr()->value().size(), 0);
- break;
- default:
- break;
- }
- }
-
- void checkDeviceInfo(const cppbor::Map* deviceInfo, bytevec deviceInfoBytes) {
- EXPECT_EQ(deviceInfo->clone()->asMap()->canonicalize().encode(), deviceInfoBytes)
- << "DeviceInfo ordering is non-canonical.";
- const auto& version = deviceInfo->get("version");
- ASSERT_TRUE(version);
- ASSERT_TRUE(version->asUint());
- RpcHardwareInfo info;
- provisionable_->getHardwareInfo(&info);
- ASSERT_EQ(version->asUint()->value(), info.versionNumber);
- std::set<std::string> allowList;
- switch (version->asUint()->value()) {
- // These fields became mandated in version 2.
- case 2:
- checkType(deviceInfo, cppbor::TSTR, "brand");
- checkType(deviceInfo, cppbor::TSTR, "manufacturer");
- checkType(deviceInfo, cppbor::TSTR, "product");
- checkType(deviceInfo, cppbor::TSTR, "model");
- checkType(deviceInfo, cppbor::TSTR, "device");
- // TODO: Refactor the KeyMint code that validates these fields and include it here.
- checkType(deviceInfo, cppbor::TSTR, "vb_state");
- allowList = getAllowedVbStates();
- EXPECT_NE(allowList.find(deviceInfo->get("vb_state")->asTstr()->value()),
- allowList.end());
- checkType(deviceInfo, cppbor::TSTR, "bootloader_state");
- allowList = getAllowedBootloaderStates();
- EXPECT_NE(allowList.find(deviceInfo->get("bootloader_state")->asTstr()->value()),
- allowList.end());
- checkType(deviceInfo, cppbor::BSTR, "vbmeta_digest");
- checkType(deviceInfo, cppbor::UINT, "system_patch_level");
- checkType(deviceInfo, cppbor::UINT, "boot_patch_level");
- checkType(deviceInfo, cppbor::UINT, "vendor_patch_level");
- checkType(deviceInfo, cppbor::UINT, "fused");
- EXPECT_LT(deviceInfo->get("fused")->asUint()->value(), 2); // Must be 0 or 1.
- checkType(deviceInfo, cppbor::TSTR, "security_level");
- allowList = getAllowedSecurityLevels();
- EXPECT_NE(allowList.find(deviceInfo->get("security_level")->asTstr()->value()),
- allowList.end());
- if (deviceInfo->get("security_level")->asTstr()->value() == "tee") {
- checkType(deviceInfo, cppbor::TSTR, "os_version");
- }
- break;
- case 1:
- checkType(deviceInfo, cppbor::TSTR, "security_level");
- allowList = getAllowedSecurityLevels();
- EXPECT_NE(allowList.find(deviceInfo->get("security_level")->asTstr()->value()),
- allowList.end());
- if (version->asUint()->value() == 1) {
- checkType(deviceInfo, cppbor::TSTR, "att_id_state");
- allowList = getAllowedAttIdStates();
- EXPECT_NE(allowList.find(deviceInfo->get("att_id_state")->asTstr()->value()),
- allowList.end());
- }
- break;
- default:
- FAIL() << "Unrecognized version: " << version->asUint()->value();
- }
- }
-
bytevec eekId_;
size_t testEekLength_;
EekChain testEekChain_;
@@ -541,6 +386,26 @@
cppbor::Array cborKeysToSign_;
};
+class CertificateRequestTest : public CertificateRequestTestBase {
+ protected:
+ void SetUp() override {
+ CertificateRequestTestBase::SetUp();
+
+ if (rpcHardwareInfo.versionNumber >= VERSION_WITHOUT_TEST_MODE) {
+ bytevec keysToSignMac;
+ DeviceInfo deviceInfo;
+ ProtectedData protectedData;
+ auto status = provisionable_->generateCertificateRequest(
+ false, {}, {}, {}, &deviceInfo, &protectedData, &keysToSignMac);
+ if (!status.isOk() && (status.getServiceSpecificError() ==
+ BnRemotelyProvisionedComponent::STATUS_REMOVED)) {
+ GTEST_SKIP() << "This test case applies to RKP v3+ only if "
+ << "generateCertificateRequest() is implemented.";
+ }
+ }
+ }
+};
+
/**
* Generate an empty certificate request in test mode, and decrypt and verify the structure and
* content.
@@ -559,7 +424,10 @@
&protectedData, &keysToSignMac);
ASSERT_TRUE(status.isOk()) << status.getMessage();
- checkProtectedData(deviceInfo, cppbor::Array(), keysToSignMac, protectedData);
+ auto result = verifyProductionProtectedData(
+ deviceInfo, cppbor::Array(), keysToSignMac, protectedData, testEekChain_, eekId_,
+ rpcHardwareInfo.supportedEekCurve, provisionable_.get(), challenge_);
+ ASSERT_TRUE(result) << result.message();
}
}
@@ -581,22 +449,24 @@
&protectedData, &keysToSignMac);
ASSERT_TRUE(status.isOk()) << status.getMessage();
- std::vector<BccEntryData> firstBcc;
- checkProtectedData(deviceInfo, /*keysToSign=*/cppbor::Array(), keysToSignMac, protectedData,
- &firstBcc);
+ auto firstBcc = verifyProductionProtectedData(
+ deviceInfo, /*keysToSign=*/cppbor::Array(), keysToSignMac, protectedData, testEekChain_,
+ eekId_, rpcHardwareInfo.supportedEekCurve, provisionable_.get(), challenge_);
+ ASSERT_TRUE(firstBcc) << firstBcc.message();
status = provisionable_->generateCertificateRequest(
testMode, {} /* keysToSign */, testEekChain_.chain, challenge_, &deviceInfo,
&protectedData, &keysToSignMac);
ASSERT_TRUE(status.isOk()) << status.getMessage();
- std::vector<BccEntryData> secondBcc;
- checkProtectedData(deviceInfo, /*keysToSign=*/cppbor::Array(), keysToSignMac, protectedData,
- &secondBcc);
+ auto secondBcc = verifyProductionProtectedData(
+ deviceInfo, /*keysToSign=*/cppbor::Array(), keysToSignMac, protectedData, testEekChain_,
+ eekId_, rpcHardwareInfo.supportedEekCurve, provisionable_.get(), challenge_);
+ ASSERT_TRUE(secondBcc) << secondBcc.message();
// Verify that none of the keys in the first BCC are repeated in the second one.
- for (const auto& i : firstBcc) {
- for (auto& j : secondBcc) {
+ for (const auto& i : *firstBcc) {
+ for (auto& j : *secondBcc) {
ASSERT_THAT(i.pubKey, testing::Not(testing::ElementsAreArray(j.pubKey)))
<< "Found a repeated pubkey in two generateCertificateRequest test mode calls";
}
@@ -639,7 +509,10 @@
&keysToSignMac);
ASSERT_TRUE(status.isOk()) << status.getMessage();
- checkProtectedData(deviceInfo, cborKeysToSign_, keysToSignMac, protectedData);
+ auto result = verifyProductionProtectedData(
+ deviceInfo, cborKeysToSign_, keysToSignMac, protectedData, testEekChain_, eekId_,
+ rpcHardwareInfo.supportedEekCurve, provisionable_.get(), challenge_);
+ ASSERT_TRUE(result) << result.message();
}
}
@@ -799,4 +672,115 @@
INSTANTIATE_REM_PROV_AIDL_TEST(CertificateRequestTest);
+class CertificateRequestV2Test : public CertificateRequestTestBase {
+ void SetUp() override {
+ CertificateRequestTestBase::SetUp();
+
+ if (rpcHardwareInfo.versionNumber < VERSION_WITHOUT_TEST_MODE) {
+ GTEST_SKIP() << "This test case only applies to RKP v3 and above. "
+ << "RKP version discovered: " << rpcHardwareInfo.versionNumber;
+ }
+ }
+};
+
+/**
+ * Generate an empty certificate request, and decrypt and verify the structure and content.
+ */
+TEST_P(CertificateRequestV2Test, EmptyRequest) {
+ bytevec csr;
+
+ auto status =
+ provisionable_->generateCertificateRequestV2({} /* keysToSign */, challenge_, &csr);
+ ASSERT_TRUE(status.isOk()) << status.getMessage();
+
+ auto result = verifyProductionCsr(cppbor::Array(), csr, provisionable_.get(), challenge_);
+ ASSERT_TRUE(result) << result.message();
+}
+
+/**
+ * Generate a non-empty certificate request. Decrypt, parse and validate the contents.
+ */
+TEST_P(CertificateRequestV2Test, NonEmptyRequest) {
+ generateKeys(false /* testMode */, 1 /* numKeys */);
+
+ bytevec csr;
+
+ auto status = provisionable_->generateCertificateRequestV2(keysToSign_, challenge_, &csr);
+ ASSERT_TRUE(status.isOk()) << status.getMessage();
+
+ auto result = verifyProductionCsr(cborKeysToSign_, csr, provisionable_.get(), challenge_);
+ ASSERT_TRUE(result) << result.message();
+}
+
+/**
+ * Generate a non-empty certificate request. Make sure contents are reproducible but allow for the
+ * signature to be different since algorithms including ECDSA P-256 can include a random value.
+ */
+TEST_P(CertificateRequestV2Test, NonEmptyRequestReproducible) {
+ generateKeys(false /* testMode */, 1 /* numKeys */);
+
+ bytevec csr;
+
+ auto status = provisionable_->generateCertificateRequestV2(keysToSign_, challenge_, &csr);
+ ASSERT_TRUE(status.isOk()) << status.getMessage();
+
+ auto firstCsr = verifyProductionCsr(cborKeysToSign_, csr, provisionable_.get(), challenge_);
+ ASSERT_TRUE(firstCsr) << firstCsr.message();
+
+ status = provisionable_->generateCertificateRequestV2(keysToSign_, challenge_, &csr);
+ ASSERT_TRUE(status.isOk()) << status.getMessage();
+
+ auto secondCsr = verifyProductionCsr(cborKeysToSign_, csr, provisionable_.get(), challenge_);
+ ASSERT_TRUE(secondCsr) << secondCsr.message();
+
+ ASSERT_EQ(**firstCsr, **secondCsr);
+}
+
+/**
+ * Generate a non-empty certificate request with multiple keys.
+ */
+TEST_P(CertificateRequestV2Test, NonEmptyRequestMultipleKeys) {
+ generateKeys(false /* testMode */, rpcHardwareInfo.supportedNumKeysInCsr /* numKeys */);
+
+ bytevec csr;
+
+ auto status = provisionable_->generateCertificateRequestV2(keysToSign_, challenge_, &csr);
+ ASSERT_TRUE(status.isOk()) << status.getMessage();
+
+ auto result = verifyProductionCsr(cborKeysToSign_, csr, provisionable_.get(), challenge_);
+ ASSERT_TRUE(result) << result.message();
+}
+
+/**
+ * Generate a non-empty certificate request, but with the MAC corrupted on the keypair.
+ */
+TEST_P(CertificateRequestV2Test, NonEmptyRequestCorruptMac) {
+ generateKeys(false /* testMode */, 1 /* numKeys */);
+ auto result = corrupt_maced_key(keysToSign_[0]);
+ ASSERT_TRUE(result) << result.moveMessage();
+ MacedPublicKey keyWithCorruptMac = result.moveValue();
+
+ bytevec csr;
+ auto status =
+ provisionable_->generateCertificateRequestV2({keyWithCorruptMac}, challenge_, &csr);
+ ASSERT_FALSE(status.isOk()) << status.getMessage();
+ EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
+}
+
+/**
+ * Generate a non-empty certificate request in prod mode, with test keys. Must fail with
+ * STATUS_TEST_KEY_IN_PRODUCTION_REQUEST.
+ */
+TEST_P(CertificateRequestV2Test, NonEmptyRequest_testKeyInProdCert) {
+ generateKeys(true /* testMode */, 1 /* numKeys */);
+
+ bytevec csr;
+ auto status = provisionable_->generateCertificateRequestV2(keysToSign_, challenge_, &csr);
+ ASSERT_FALSE(status.isOk()) << status.getMessage();
+ ASSERT_EQ(status.getServiceSpecificError(),
+ BnRemotelyProvisionedComponent::STATUS_TEST_KEY_IN_PRODUCTION_REQUEST);
+}
+
+INSTANTIATE_REM_PROV_AIDL_TEST(CertificateRequestV2Test);
+
} // namespace aidl::android::hardware::security::keymint::test
diff --git a/security/keymint/aidl/vts/performance/KeyMintBenchmark.cpp b/security/keymint/aidl/vts/performance/KeyMintBenchmark.cpp
index 54b6fdc..0c61c25 100644
--- a/security/keymint/aidl/vts/performance/KeyMintBenchmark.cpp
+++ b/security/keymint/aidl/vts/performance/KeyMintBenchmark.cpp
@@ -16,16 +16,21 @@
#define LOG_TAG "keymint_benchmark"
+#include <iostream>
+
#include <base/command_line.h>
#include <benchmark/benchmark.h>
-#include <iostream>
#include <aidl/Vintf.h>
#include <aidl/android/hardware/security/keymint/ErrorCode.h>
#include <aidl/android/hardware/security/keymint/IKeyMintDevice.h>
#include <android/binder_manager.h>
#include <binder/IServiceManager.h>
+
#include <keymint_support/authorization_set.h>
+#include <keymint_support/openssl_utils.h>
+#include <openssl/curve25519.h>
+#include <openssl/x509.h>
#define SMALL_MESSAGE_SIZE 64
#define MEDIUM_MESSAGE_SIZE 1024
@@ -119,6 +124,22 @@
return {};
}
+ string getAlgorithmString(string transform) {
+ if (transform.find("AES") != string::npos) {
+ return "AES";
+ } else if (transform.find("Hmac") != string::npos) {
+ return "HMAC";
+ } else if (transform.find("DESede") != string::npos) {
+ return "TRIPLE_DES";
+ } else if (transform.find("RSA") != string::npos) {
+ return "RSA";
+ } else if (transform.find("EC") != string::npos) {
+ return "EC";
+ }
+ std::cerr << "Can't find algorithm for " << transform << std::endl;
+ return "";
+ }
+
Digest getDigest(string transform) {
if (transform.find("MD5") != string::npos) {
return Digest::MD5;
@@ -135,13 +156,59 @@
return Digest::SHA_2_512;
} else if (transform.find("RSA") != string::npos &&
transform.find("OAEP") != string::npos) {
- return Digest::SHA1;
+ if (securityLevel_ == SecurityLevel::STRONGBOX) {
+ return Digest::SHA_2_256;
+ } else {
+ return Digest::SHA1;
+ }
} else if (transform.find("Hmac") != string::npos) {
return Digest::SHA_2_256;
}
return Digest::NONE;
}
+ string getDigestString(string transform) {
+ if (transform.find("MD5") != string::npos) {
+ return "MD5";
+ } else if (transform.find("SHA1") != string::npos ||
+ transform.find("SHA-1") != string::npos) {
+ return "SHA1";
+ } else if (transform.find("SHA224") != string::npos) {
+ return "SHA_2_224";
+ } else if (transform.find("SHA256") != string::npos) {
+ return "SHA_2_256";
+ } else if (transform.find("SHA384") != string::npos) {
+ return "SHA_2_384";
+ } else if (transform.find("SHA512") != string::npos) {
+ return "SHA_2_512";
+ } else if (transform.find("RSA") != string::npos &&
+ transform.find("OAEP") != string::npos) {
+ if (securityLevel_ == SecurityLevel::STRONGBOX) {
+ return "SHA_2_256";
+ } else {
+ return "SHA1";
+ }
+ } else if (transform.find("Hmac") != string::npos) {
+ return "SHA_2_256";
+ }
+ return "";
+ }
+
+ optional<EcCurve> getCurveFromLength(int keySize) {
+ switch (keySize) {
+ case 224:
+ return EcCurve::P_224;
+ case 256:
+ return EcCurve::P_256;
+ case 384:
+ return EcCurve::P_384;
+ case 521:
+ return EcCurve::P_521;
+ default:
+ return std::nullopt;
+ }
+ }
+
bool GenerateKey(string transform, int keySize, bool sign = false) {
if (transform == key_transform_) {
return true;
@@ -184,6 +251,12 @@
}
if (algorithm == Algorithm::EC) {
authSet.SetDefaultValidity();
+ std::optional<EcCurve> curve = getCurveFromLength(keySize);
+ if (!curve) {
+ std::cerr << "Error: invalid EC-Curve from size " << keySize << std::endl;
+ return false;
+ }
+ authSet.Authorization(TAG_EC_CURVE, curve.value());
}
error_ = GenerateKey(authSet);
return error_ == ErrorCode::OK;
@@ -236,6 +309,109 @@
return GetReturnErrorCode(result);
}
+ /* Copied the function LocalRsaEncryptMessage from
+ * hardware/interfaces/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp in VTS.
+ * Replaced asserts with the condition check and return false in case of failure condition.
+ * Require return value to skip the benchmark test case from further execution in case
+ * LocalRsaEncryptMessage fails.
+ */
+ optional<string> LocalRsaEncryptMessage(const string& message, const AuthorizationSet& params) {
+ // Retrieve the public key from the leaf certificate.
+ if (cert_chain_.empty()) {
+ std::cerr << "Local RSA encrypt Error: invalid cert_chain_" << std::endl;
+ return "Failure";
+ }
+ X509_Ptr key_cert(parse_cert_blob(cert_chain_[0].encodedCertificate));
+ EVP_PKEY_Ptr pub_key(X509_get_pubkey(key_cert.get()));
+ RSA_Ptr rsa(EVP_PKEY_get1_RSA(const_cast<EVP_PKEY*>(pub_key.get())));
+
+ // Retrieve relevant tags.
+ Digest digest = Digest::NONE;
+ Digest mgf_digest = Digest::SHA1;
+ PaddingMode padding = PaddingMode::NONE;
+
+ auto digest_tag = params.GetTagValue(TAG_DIGEST);
+ if (digest_tag.has_value()) digest = digest_tag.value();
+ auto pad_tag = params.GetTagValue(TAG_PADDING);
+ if (pad_tag.has_value()) padding = pad_tag.value();
+ auto mgf_tag = params.GetTagValue(TAG_RSA_OAEP_MGF_DIGEST);
+ if (mgf_tag.has_value()) mgf_digest = mgf_tag.value();
+
+ const EVP_MD* md = openssl_digest(digest);
+ const EVP_MD* mgf_md = openssl_digest(mgf_digest);
+
+ // Set up encryption context.
+ EVP_PKEY_CTX_Ptr ctx(EVP_PKEY_CTX_new(pub_key.get(), /* engine= */ nullptr));
+ if (EVP_PKEY_encrypt_init(ctx.get()) <= 0) {
+ std::cerr << "Local RSA encrypt Error: Encryption init failed" << std::endl;
+ return "Failure";
+ }
+
+ int rc = -1;
+ switch (padding) {
+ case PaddingMode::NONE:
+ rc = EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_NO_PADDING);
+ break;
+ case PaddingMode::RSA_PKCS1_1_5_ENCRYPT:
+ rc = EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_PKCS1_PADDING);
+ break;
+ case PaddingMode::RSA_OAEP:
+ rc = EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_PKCS1_OAEP_PADDING);
+ break;
+ default:
+ break;
+ }
+ if (rc <= 0) {
+ std::cerr << "Local RSA encrypt Error: Set padding failed" << std::endl;
+ return "Failure";
+ }
+ if (padding == PaddingMode::RSA_OAEP) {
+ if (!EVP_PKEY_CTX_set_rsa_oaep_md(ctx.get(), md)) {
+ std::cerr << "Local RSA encrypt Error: Set digest failed: " << ERR_peek_last_error()
+ << std::endl;
+ return "Failure";
+ }
+ if (!EVP_PKEY_CTX_set_rsa_mgf1_md(ctx.get(), mgf_md)) {
+ std::cerr << "Local RSA encrypt Error: Set digest failed: " << ERR_peek_last_error()
+ << std::endl;
+ return "Failure";
+ }
+ }
+
+ // Determine output size.
+ size_t outlen;
+ if (EVP_PKEY_encrypt(ctx.get(), nullptr /* out */, &outlen,
+ reinterpret_cast<const uint8_t*>(message.data()),
+ message.size()) <= 0) {
+ std::cerr << "Local RSA encrypt Error: Determine output size failed: "
+ << ERR_peek_last_error() << std::endl;
+ return "Failure";
+ }
+
+ // Left-zero-pad the input if necessary.
+ const uint8_t* to_encrypt = reinterpret_cast<const uint8_t*>(message.data());
+ size_t to_encrypt_len = message.size();
+
+ std::unique_ptr<string> zero_padded_message;
+ if (padding == PaddingMode::NONE && to_encrypt_len < outlen) {
+ zero_padded_message.reset(new string(outlen, '\0'));
+ memcpy(zero_padded_message->data() + (outlen - to_encrypt_len), message.data(),
+ message.size());
+ to_encrypt = reinterpret_cast<const uint8_t*>(zero_padded_message->data());
+ to_encrypt_len = outlen;
+ }
+
+ // Do the encryption.
+ string output(outlen, '\0');
+ if (EVP_PKEY_encrypt(ctx.get(), reinterpret_cast<uint8_t*>(output.data()), &outlen,
+ to_encrypt, to_encrypt_len) <= 0) {
+ std::cerr << "Local RSA encrypt Error: Encryption failed: " << ERR_peek_last_error()
+ << std::endl;
+ return "Failure";
+ }
+ return output;
+ }
+
SecurityLevel securityLevel_;
string name_;
@@ -243,12 +419,13 @@
ErrorCode GenerateKey(const AuthorizationSet& key_desc,
const optional<AttestationKey>& attest_key = std::nullopt) {
key_blob_.clear();
+ cert_chain_.clear();
KeyCreationResult creationResult;
Status result = keymint_->generateKey(key_desc.vector_data(), attest_key, &creationResult);
if (result.isOk()) {
key_blob_ = std::move(creationResult.keyBlob);
+ cert_chain_ = std::move(creationResult.certificateChain);
creationResult.keyCharacteristics.clear();
- creationResult.certificateChain.clear();
}
return GetReturnErrorCode(result);
}
@@ -313,6 +490,11 @@
return ErrorCode::UNKNOWN_ERROR;
}
+ X509_Ptr parse_cert_blob(const vector<uint8_t>& blob) {
+ const uint8_t* p = blob.data();
+ return X509_Ptr(d2i_X509(nullptr /* allocate new */, &p, blob.size()));
+ }
+
std::shared_ptr<IKeyMintOperation> op_;
vector<Certificate> cert_chain_;
vector<uint8_t> key_blob_;
@@ -365,6 +547,10 @@
BENCHMARK_KM_MSG(encrypt, transform, keySize, msgSize) \
BENCHMARK_KM_MSG(decrypt, transform, keySize, msgSize)
+// Skip public key operations as they are not supported in KeyMint.
+#define BENCHMARK_KM_ASYM_CIPHER(transform, keySize, msgSize) \
+ BENCHMARK_KM_MSG(decrypt, transform, keySize, msgSize)
+
#define BENCHMARK_KM_CIPHER_ALL_MSGS(transform, keySize) \
BENCHMARK_KM_ALL_MSGS(encrypt, transform, keySize) \
BENCHMARK_KM_ALL_MSGS(decrypt, transform, keySize)
@@ -372,12 +558,43 @@
#define BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, keySize) \
BENCHMARK_KM_ALL_MSGS(sign, transform, keySize) \
BENCHMARK_KM_ALL_MSGS(verify, transform, keySize)
-// clang-format on
+
+// Skip public key operations as they are not supported in KeyMint.
+#define BENCHMARK_KM_ASYM_SIGNATURE_ALL_MSGS(transform, keySize) \
+ BENCHMARK_KM_ALL_MSGS(sign, transform, keySize) \
+ // clang-format on
/*
* ============= KeyGen TESTS ==================
*/
+
+static bool isValidSBKeySize(string transform, int keySize) {
+ std::optional<Algorithm> algorithm = keymintTest->getAlgorithm(transform);
+ switch (algorithm.value()) {
+ case Algorithm::AES:
+ return (keySize == 128 || keySize == 256);
+ case Algorithm::HMAC:
+ return (keySize % 8 == 0 && keySize >= 64 && keySize <= 512);
+ case Algorithm::TRIPLE_DES:
+ return (keySize == 168);
+ case Algorithm::RSA:
+ return (keySize == 2048);
+ case Algorithm::EC:
+ return (keySize == 256);
+ }
+ return false;
+}
+
static void keygen(benchmark::State& state, string transform, int keySize) {
+ // Skip the test for unsupported key size in StrongBox
+ if (keymintTest->securityLevel_ == SecurityLevel::STRONGBOX &&
+ !isValidSBKeySize(transform, keySize)) {
+ state.SkipWithError(("Skipped for STRONGBOX: Keysize: " + std::to_string(keySize) +
+ " is not supported in StrongBox for algorithm: " +
+ keymintTest->getAlgorithmString(transform))
+ .c_str());
+ return;
+ }
addDefaultLabel(state);
for (auto _ : state) {
if (!keymintTest->GenerateKey(transform, keySize)) {
@@ -413,8 +630,24 @@
/*
* ============= SIGNATURE TESTS ==================
*/
-
static void sign(benchmark::State& state, string transform, int keySize, int msgSize) {
+ // Skip the test for unsupported key size or unsupported digest in StrongBox
+ if (keymintTest->securityLevel_ == SecurityLevel::STRONGBOX) {
+ if (!isValidSBKeySize(transform, keySize)) {
+ state.SkipWithError(("Skipped for STRONGBOX: Keysize: " + std::to_string(keySize) +
+ " is not supported in StrongBox for algorithm: " +
+ keymintTest->getAlgorithmString(transform))
+ .c_str());
+ return;
+ }
+ if (keymintTest->getDigest(transform) != Digest::SHA_2_256) {
+ state.SkipWithError(
+ ("Skipped for STRONGBOX: Digest: " + keymintTest->getDigestString(transform) +
+ " is not supported in StrongBox")
+ .c_str());
+ return;
+ }
+ }
addDefaultLabel(state);
if (!keymintTest->GenerateKey(transform, keySize, true)) {
state.SkipWithError(
@@ -444,6 +677,23 @@
}
static void verify(benchmark::State& state, string transform, int keySize, int msgSize) {
+ // Skip the test for unsupported key size or unsupported digest in StrongBox
+ if (keymintTest->securityLevel_ == SecurityLevel::STRONGBOX) {
+ if (!isValidSBKeySize(transform, keySize)) {
+ state.SkipWithError(("Skipped for STRONGBOX: Keysize: " + std::to_string(keySize) +
+ " is not supported in StrongBox for algorithm: " +
+ keymintTest->getAlgorithmString(transform))
+ .c_str());
+ return;
+ }
+ if (keymintTest->getDigest(transform) != Digest::SHA_2_256) {
+ state.SkipWithError(
+ ("Skipped for STRONGBOX: Digest: " + keymintTest->getDigestString(transform) +
+ " is not supported in StrongBox")
+ .c_str());
+ return;
+ }
+ }
addDefaultLabel(state);
if (!keymintTest->GenerateKey(transform, keySize, true)) {
state.SkipWithError(
@@ -500,10 +750,10 @@
BENCHMARK_KM_SIGNATURE_ALL_HMAC_KEYS(HmacSHA512)
#define BENCHMARK_KM_SIGNATURE_ALL_ECDSA_KEYS(transform) \
- BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 224) \
- BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 256) \
- BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 384) \
- BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 521)
+ BENCHMARK_KM_ASYM_SIGNATURE_ALL_MSGS(transform, 224) \
+ BENCHMARK_KM_ASYM_SIGNATURE_ALL_MSGS(transform, 256) \
+ BENCHMARK_KM_ASYM_SIGNATURE_ALL_MSGS(transform, 384) \
+ BENCHMARK_KM_ASYM_SIGNATURE_ALL_MSGS(transform, 521)
BENCHMARK_KM_SIGNATURE_ALL_ECDSA_KEYS(NONEwithECDSA);
BENCHMARK_KM_SIGNATURE_ALL_ECDSA_KEYS(SHA1withECDSA);
@@ -513,13 +763,14 @@
BENCHMARK_KM_SIGNATURE_ALL_ECDSA_KEYS(SHA512withECDSA);
#define BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(transform) \
- BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 2048) \
- BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 3072) \
- BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 4096)
+ BENCHMARK_KM_ASYM_SIGNATURE_ALL_MSGS(transform, 2048) \
+ BENCHMARK_KM_ASYM_SIGNATURE_ALL_MSGS(transform, 3072) \
+ BENCHMARK_KM_ASYM_SIGNATURE_ALL_MSGS(transform, 4096)
BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(MD5withRSA);
BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA1withRSA);
BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA224withRSA);
+BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA256withRSA);
BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA384withRSA);
BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA512withRSA);
@@ -528,6 +779,7 @@
BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA224withRSA/PSS);
BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA384withRSA/PSS);
BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA512withRSA/PSS);
+
// clang-format on
/*
@@ -535,6 +787,15 @@
*/
static void encrypt(benchmark::State& state, string transform, int keySize, int msgSize) {
+ // Skip the test for unsupported key size in StrongBox
+ if (keymintTest->securityLevel_ == SecurityLevel::STRONGBOX &&
+ (!isValidSBKeySize(transform, keySize))) {
+ state.SkipWithError(("Skipped for STRONGBOX: Keysize: " + std::to_string(keySize) +
+ " is not supported in StrongBox for algorithm: " +
+ keymintTest->getAlgorithmString(transform))
+ .c_str());
+ return;
+ }
addDefaultLabel(state);
if (!keymintTest->GenerateKey(transform, keySize)) {
state.SkipWithError(
@@ -564,6 +825,15 @@
}
static void decrypt(benchmark::State& state, string transform, int keySize, int msgSize) {
+ // Skip the test for unsupported key size in StrongBox
+ if (keymintTest->securityLevel_ == SecurityLevel::STRONGBOX &&
+ (!isValidSBKeySize(transform, keySize))) {
+ state.SkipWithError(("Skipped for STRONGBOX: Keysize: " + std::to_string(keySize) +
+ " is not supported in StrongBox for algorithm: " +
+ keymintTest->getAlgorithmString(transform))
+ .c_str());
+ return;
+ }
addDefaultLabel(state);
if (!keymintTest->GenerateKey(transform, keySize)) {
state.SkipWithError(
@@ -573,23 +843,34 @@
AuthorizationSet out_params;
AuthorizationSet in_params = keymintTest->getOperationParams(transform);
string message = keymintTest->GenerateMessage(msgSize);
- auto error = keymintTest->Begin(KeyPurpose::ENCRYPT, in_params, &out_params);
- if (error != ErrorCode::OK) {
- state.SkipWithError(
- ("Encryption begin error, " + std::to_string(keymintTest->getError())).c_str());
- return;
+ optional<string> encryptedMessage;
+
+ if (keymintTest->getAlgorithm(transform).value() == Algorithm::RSA) {
+ // Public key operation not supported, doing local Encryption
+ encryptedMessage = keymintTest->LocalRsaEncryptMessage(message, in_params);
+ if ((keySize / 8) != (*encryptedMessage).size()) {
+ state.SkipWithError("Local Encryption falied");
+ return;
+ }
+ } else {
+ auto error = keymintTest->Begin(KeyPurpose::ENCRYPT, in_params, &out_params);
+ if (error != ErrorCode::OK) {
+ state.SkipWithError(
+ ("Encryption begin error, " + std::to_string(keymintTest->getError())).c_str());
+ return;
+ }
+ encryptedMessage = keymintTest->Process(message);
+ if (!encryptedMessage) {
+ state.SkipWithError(
+ ("Encryption error, " + std::to_string(keymintTest->getError())).c_str());
+ return;
+ }
+ in_params.push_back(out_params);
+ out_params.Clear();
}
- auto encryptedMessage = keymintTest->Process(message);
- if (!encryptedMessage) {
- state.SkipWithError(
- ("Encryption error, " + std::to_string(keymintTest->getError())).c_str());
- return;
- }
- in_params.push_back(out_params);
- out_params.Clear();
for (auto _ : state) {
state.PauseTiming();
- error = keymintTest->Begin(KeyPurpose::DECRYPT, in_params, &out_params);
+ auto error = keymintTest->Begin(KeyPurpose::DECRYPT, in_params, &out_params);
if (error != ErrorCode::OK) {
state.SkipWithError(
("Decryption begin error, " + std::to_string(keymintTest->getError())).c_str());
@@ -624,9 +905,9 @@
BENCHMARK_KM_CIPHER_ALL_MSGS(DESede/ECB/PKCS7Padding, 168);
#define BENCHMARK_KM_CIPHER_ALL_RSA_KEYS(transform, msgSize) \
- BENCHMARK_KM_CIPHER(transform, 2048, msgSize) \
- BENCHMARK_KM_CIPHER(transform, 3072, msgSize) \
- BENCHMARK_KM_CIPHER(transform, 4096, msgSize)
+ BENCHMARK_KM_ASYM_CIPHER(transform, 2048, msgSize) \
+ BENCHMARK_KM_ASYM_CIPHER(transform, 3072, msgSize) \
+ BENCHMARK_KM_ASYM_CIPHER(transform, 4096, msgSize)
BENCHMARK_KM_CIPHER_ALL_RSA_KEYS(RSA/ECB/NoPadding, SMALL_MESSAGE_SIZE);
BENCHMARK_KM_CIPHER_ALL_RSA_KEYS(RSA/ECB/PKCS1Padding, SMALL_MESSAGE_SIZE);
diff --git a/security/keymint/support/Android.bp b/security/keymint/support/Android.bp
index bf2ab02..efd6fc7 100644
--- a/security/keymint/support/Android.bp
+++ b/security/keymint/support/Android.bp
@@ -63,8 +63,12 @@
defaults: [
"keymint_use_latest_hal_aidl_ndk_shared",
],
+ static_libs: [
+ "android.hardware.security.rkp-V3-ndk",
+ ],
shared_libs: [
"libbase",
+ "libbinder_ndk",
"libcppbor_external",
"libcppcose_rkp",
"libcrypto",
@@ -77,6 +81,7 @@
name: "libkeymint_remote_prov_support_test",
srcs: ["remote_prov_utils_test.cpp"],
static_libs: [
+ "android.hardware.security.rkp-V3-ndk",
"libgmock",
"libgtest_main",
],
diff --git a/security/keymint/support/include/remote_prov/remote_prov_utils.h b/security/keymint/support/include/remote_prov/remote_prov_utils.h
index f3b8608..1b94c62 100644
--- a/security/keymint/support/include/remote_prov/remote_prov_utils.h
+++ b/security/keymint/support/include/remote_prov/remote_prov_utils.h
@@ -16,7 +16,9 @@
#pragma once
+#include <memory>
#include <vector>
+#include "aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.h"
#include <keymaster/cppcose/cppcose.h>
@@ -139,4 +141,54 @@
JsonOutput jsonEncodeCsrWithBuild(const std::string instance_name,
const cppbor::Array& csr);
+/**
+ * Parses a DeviceInfo structure from the given CBOR data. The parsed data is then validated to
+ * ensure it contains the minimum required data at the time of manufacturing. This is only a
+ * partial validation, as some fields may not be provisioned yet at the time this information
+ * is parsed in the manufacturing process.
+ */
+ErrMsgOr<std::unique_ptr<cppbor::Map>> parseAndValidateFactoryDeviceInfo(
+ const std::vector<uint8_t>& deviceInfoBytes, IRemotelyProvisionedComponent* provisionable);
+
+/**
+ * Parses a DeviceInfo structure from the given CBOR data. The parsed data is then validated to
+ * ensure it is formatted correctly and that it contains the required values for Remote Key
+ * Provisioning. This is a full validation, and assumes the device is provisioned as if it is
+ * suitable for the end user.
+ */
+ErrMsgOr<std::unique_ptr<cppbor::Map>> parseAndValidateProductionDeviceInfo(
+ const std::vector<uint8_t>& deviceInfoBytes, IRemotelyProvisionedComponent* provisionable);
+
+/**
+ * Verify the protected data as if the device is still early in the factory process and may not
+ * have all device identifiers provisioned yet.
+ */
+ErrMsgOr<std::vector<BccEntryData>> verifyFactoryProtectedData(
+ const DeviceInfo& deviceInfo, const cppbor::Array& keysToSign,
+ const std::vector<uint8_t>& keysToSignMac, const ProtectedData& protectedData,
+ const EekChain& eekChain, const std::vector<uint8_t>& eekId, int32_t supportedEekCurve,
+ IRemotelyProvisionedComponent* provisionable, const std::vector<uint8_t>& challenge);
+/**
+ * Verify the protected data as if the device is a final production sample.
+ */
+ErrMsgOr<std::vector<BccEntryData>> verifyProductionProtectedData(
+ const DeviceInfo& deviceInfo, const cppbor::Array& keysToSign,
+ const std::vector<uint8_t>& keysToSignMac, const ProtectedData& protectedData,
+ const EekChain& eekChain, const std::vector<uint8_t>& eekId, int32_t supportedEekCurve,
+ IRemotelyProvisionedComponent* provisionable, const std::vector<uint8_t>& challenge);
+
+/**
+ * Verify the CSR as if the device is still early in the factory process and may not
+ * have all device identifiers provisioned yet.
+ */
+ErrMsgOr<std::unique_ptr<cppbor::Array>> verifyFactoryCsr(
+ const cppbor::Array& keysToSign, const std::vector<uint8_t>& csr,
+ IRemotelyProvisionedComponent* provisionable, const std::vector<uint8_t>& challenge);
+/**
+ * Verify the CSR as if the device is a final production sample.
+ */
+ErrMsgOr<std::unique_ptr<cppbor::Array>> verifyProductionCsr(
+ const cppbor::Array& keysToSign, const std::vector<uint8_t>& csr,
+ IRemotelyProvisionedComponent* provisionable, const std::vector<uint8_t>& challenge);
+
} // namespace aidl::android::hardware::security::keymint::remote_prov
diff --git a/security/keymint/support/remote_prov_utils.cpp b/security/keymint/support/remote_prov_utils.cpp
index 0dbea5b..7e164fd 100644
--- a/security/keymint/support/remote_prov_utils.cpp
+++ b/security/keymint/support/remote_prov_utils.cpp
@@ -15,7 +15,11 @@
*/
#include <iterator>
+#include <memory>
+#include <set>
+#include <string>
#include <tuple>
+#include "aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.h"
#include <aidl/android/hardware/security/keymint/RpcHardwareInfo.h>
#include <android-base/properties.h>
@@ -28,6 +32,7 @@
#include <openssl/base64.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
+#include <openssl/x509.h>
#include <remote_prov/remote_prov_utils.h>
namespace aidl::android::hardware::security::keymint::remote_prov {
@@ -41,6 +46,8 @@
using EC_KEY_Ptr = bssl::UniquePtr<EC_KEY>;
using EVP_PKEY_Ptr = bssl::UniquePtr<EVP_PKEY>;
using EVP_PKEY_CTX_Ptr = bssl::UniquePtr<EVP_PKEY_CTX>;
+using X509_Ptr = bssl::UniquePtr<X509>;
+using CRYPTO_BUFFER_Ptr = bssl::UniquePtr<CRYPTO_BUFFER>;
ErrMsgOr<bytevec> ecKeyGetPrivateKey(const EC_KEY* ecKey) {
// Extract private key.
@@ -441,4 +448,589 @@
return JsonOutput::Ok(Json::writeString(factory, json));
}
+std::string checkMapEntry(bool isFactory, const cppbor::Map& devInfo, cppbor::MajorType majorType,
+ const std::string& entryName) {
+ const std::unique_ptr<cppbor::Item>& val = devInfo.get(entryName);
+ if (!val) {
+ return entryName + " is missing.\n";
+ }
+ if (val->type() != majorType) {
+ return entryName + " has the wrong type.\n";
+ }
+ if (isFactory) {
+ return "";
+ }
+ switch (majorType) {
+ case cppbor::TSTR:
+ if (val->asTstr()->value().size() <= 0) {
+ return entryName + " is present but the value is empty.\n";
+ }
+ break;
+ case cppbor::BSTR:
+ if (val->asBstr()->value().size() <= 0) {
+ return entryName + " is present but the value is empty.\n";
+ }
+ break;
+ default:
+ break;
+ }
+ return "";
+}
+
+std::string checkMapEntry(bool isFactory, const cppbor::Map& devInfo, cppbor::MajorType majorType,
+ const std::string& entryName, const cppbor::Array& allowList) {
+ std::string error = checkMapEntry(isFactory, devInfo, majorType, entryName);
+ if (!error.empty()) {
+ return error;
+ }
+
+ if (isFactory) {
+ return "";
+ }
+
+ const std::unique_ptr<cppbor::Item>& val = devInfo.get(entryName);
+ for (auto i = allowList.begin(); i != allowList.end(); ++i) {
+ if (**i == *val) {
+ return "";
+ }
+ }
+ return entryName + " has an invalid value.\n";
+}
+
+ErrMsgOr<std::unique_ptr<cppbor::Map>> parseAndValidateDeviceInfo(
+ const std::vector<uint8_t>& deviceInfoBytes, IRemotelyProvisionedComponent* provisionable,
+ bool isFactory) {
+ const cppbor::Array kValidVbStates = {"green", "yellow", "orange"};
+ const cppbor::Array kValidBootloaderStates = {"locked", "unlocked"};
+ const cppbor::Array kValidSecurityLevels = {"tee", "strongbox"};
+ const cppbor::Array kValidAttIdStates = {"locked", "open"};
+ const cppbor::Array kValidFused = {0, 1};
+
+ struct AttestationIdEntry {
+ const char* id;
+ bool alwaysValidate;
+ };
+ constexpr AttestationIdEntry kAttestationIdEntrySet[] = {{"brand", false},
+ {"manufacturer", true},
+ {"product", false},
+ {"model", false},
+ {"device", false}};
+
+ auto [parsedVerifiedDeviceInfo, ignore1, errMsg] = cppbor::parse(deviceInfoBytes);
+ if (!parsedVerifiedDeviceInfo) {
+ return errMsg;
+ }
+
+ std::unique_ptr<cppbor::Map> parsed(parsedVerifiedDeviceInfo.release()->asMap());
+ if (!parsed) {
+ return "DeviceInfo must be a CBOR map.";
+ }
+
+ if (parsed->clone()->asMap()->canonicalize().encode() != deviceInfoBytes) {
+ return "DeviceInfo ordering is non-canonical.";
+ }
+
+ RpcHardwareInfo info;
+ provisionable->getHardwareInfo(&info);
+ if (info.versionNumber < 3) {
+ const std::unique_ptr<cppbor::Item>& version = parsed->get("version");
+ if (!version) {
+ return "Device info is missing version";
+ }
+ if (!version->asUint()) {
+ return "version must be an unsigned integer";
+ }
+ if (version->asUint()->value() != info.versionNumber) {
+ return "DeviceInfo version (" + std::to_string(version->asUint()->value()) +
+ ") does not match the remotely provisioned component version (" +
+ std::to_string(info.versionNumber) + ").";
+ }
+ }
+
+ std::string error;
+ switch (info.versionNumber) {
+ case 3:
+ case 2:
+ for (const auto& entry : kAttestationIdEntrySet) {
+ error += checkMapEntry(isFactory && !entry.alwaysValidate, *parsed, cppbor::TSTR,
+ entry.id);
+ }
+ if (!error.empty()) {
+ return error +
+ "Attestation IDs are missing or malprovisioned. If this test is being\n"
+ "run against an early proto or EVT build, this error is probably WAI\n"
+ "and indicates that Device IDs were not provisioned in the factory. If\n"
+ "this error is returned on a DVT or later build revision, then\n"
+ "something is likely wrong with the factory provisioning process.";
+ }
+ // TODO: Refactor the KeyMint code that validates these fields and include it here.
+ error += checkMapEntry(isFactory, *parsed, cppbor::TSTR, "vb_state", kValidVbStates);
+ error += checkMapEntry(isFactory, *parsed, cppbor::TSTR, "bootloader_state",
+ kValidBootloaderStates);
+ error += checkMapEntry(isFactory, *parsed, cppbor::BSTR, "vbmeta_digest");
+ error += checkMapEntry(isFactory, *parsed, cppbor::UINT, "system_patch_level");
+ error += checkMapEntry(isFactory, *parsed, cppbor::UINT, "boot_patch_level");
+ error += checkMapEntry(isFactory, *parsed, cppbor::UINT, "vendor_patch_level");
+ error += checkMapEntry(isFactory, *parsed, cppbor::UINT, "fused", kValidFused);
+ error += checkMapEntry(isFactory, *parsed, cppbor::TSTR, "security_level",
+ kValidSecurityLevels);
+ if (parsed->get("security_level") && parsed->get("security_level")->asTstr() &&
+ parsed->get("security_level")->asTstr()->value() == "tee") {
+ error += checkMapEntry(isFactory, *parsed, cppbor::TSTR, "os_version");
+ }
+ break;
+ case 1:
+ error += checkMapEntry(isFactory, *parsed, cppbor::TSTR, "security_level",
+ kValidSecurityLevels);
+ error += checkMapEntry(isFactory, *parsed, cppbor::TSTR, "att_id_state",
+ kValidAttIdStates);
+ break;
+ default:
+ return "Unrecognized version: " + std::to_string(info.versionNumber);
+ }
+
+ if (!error.empty()) {
+ return error;
+ }
+
+ return std::move(parsed);
+}
+
+ErrMsgOr<std::unique_ptr<cppbor::Map>> parseAndValidateFactoryDeviceInfo(
+ const std::vector<uint8_t>& deviceInfoBytes, IRemotelyProvisionedComponent* provisionable) {
+ return parseAndValidateDeviceInfo(deviceInfoBytes, provisionable, /*isFactory=*/true);
+}
+
+ErrMsgOr<std::unique_ptr<cppbor::Map>> parseAndValidateProductionDeviceInfo(
+ const std::vector<uint8_t>& deviceInfoBytes, IRemotelyProvisionedComponent* provisionable) {
+ return parseAndValidateDeviceInfo(deviceInfoBytes, provisionable, /*isFactory=*/false);
+}
+
+ErrMsgOr<bytevec> getSessionKey(ErrMsgOr<std::pair<bytevec, bytevec>>& senderPubkey,
+ const EekChain& eekChain, int32_t supportedEekCurve) {
+ if (supportedEekCurve == RpcHardwareInfo::CURVE_25519 ||
+ supportedEekCurve == RpcHardwareInfo::CURVE_NONE) {
+ return x25519_HKDF_DeriveKey(eekChain.last_pubkey, eekChain.last_privkey,
+ senderPubkey->first, false /* senderIsA */);
+ } else {
+ return ECDH_HKDF_DeriveKey(eekChain.last_pubkey, eekChain.last_privkey, senderPubkey->first,
+ false /* senderIsA */);
+ }
+}
+
+ErrMsgOr<std::vector<BccEntryData>> verifyProtectedData(
+ const DeviceInfo& deviceInfo, const cppbor::Array& keysToSign,
+ const std::vector<uint8_t>& keysToSignMac, const ProtectedData& protectedData,
+ const EekChain& eekChain, const std::vector<uint8_t>& eekId, int32_t supportedEekCurve,
+ IRemotelyProvisionedComponent* provisionable, const std::vector<uint8_t>& challenge,
+ bool isFactory) {
+ auto [parsedProtectedData, _, protDataErrMsg] = cppbor::parse(protectedData.protectedData);
+ if (!parsedProtectedData) {
+ return protDataErrMsg;
+ }
+ if (!parsedProtectedData->asArray()) {
+ return "Protected data is not a CBOR array.";
+ }
+ if (parsedProtectedData->asArray()->size() != kCoseEncryptEntryCount) {
+ return "The protected data COSE_encrypt structure must have " +
+ std::to_string(kCoseEncryptEntryCount) + " entries, but it only has " +
+ std::to_string(parsedProtectedData->asArray()->size());
+ }
+
+ auto senderPubkey = getSenderPubKeyFromCoseEncrypt(parsedProtectedData);
+ if (!senderPubkey) {
+ return senderPubkey.message();
+ }
+ if (senderPubkey->second != eekId) {
+ return "The COSE_encrypt recipient does not match the expected EEK identifier";
+ }
+
+ auto sessionKey = getSessionKey(senderPubkey, eekChain, supportedEekCurve);
+ if (!sessionKey) {
+ return sessionKey.message();
+ }
+
+ auto protectedDataPayload =
+ decryptCoseEncrypt(*sessionKey, parsedProtectedData.get(), bytevec{} /* aad */);
+ if (!protectedDataPayload) {
+ return protectedDataPayload.message();
+ }
+
+ auto [parsedPayload, __, payloadErrMsg] = cppbor::parse(*protectedDataPayload);
+ if (!parsedPayload) {
+ return "Failed to parse payload: " + payloadErrMsg;
+ }
+ if (!parsedPayload->asArray()) {
+ return "The protected data payload must be an Array.";
+ }
+ if (parsedPayload->asArray()->size() != 3U && parsedPayload->asArray()->size() != 2U) {
+ return "The protected data payload must contain SignedMAC and BCC. It may optionally "
+ "contain AdditionalDKSignatures. However, the parsed payload has " +
+ std::to_string(parsedPayload->asArray()->size()) + " entries.";
+ }
+
+ auto& signedMac = parsedPayload->asArray()->get(0);
+ auto& bcc = parsedPayload->asArray()->get(1);
+ if (!signedMac->asArray()) {
+ return "The SignedMAC in the protected data payload is not an Array.";
+ }
+ if (!bcc->asArray()) {
+ return "The BCC in the protected data payload is not an Array.";
+ }
+
+ // BCC is [ pubkey, + BccEntry]
+ auto bccContents = validateBcc(bcc->asArray());
+ if (!bccContents) {
+ return bccContents.message() + "\n" + prettyPrint(bcc.get());
+ }
+ if (bccContents->size() == 0U) {
+ return "The BCC is empty. It must contain at least one entry.";
+ }
+
+ auto deviceInfoResult =
+ parseAndValidateDeviceInfo(deviceInfo.deviceInfo, provisionable, isFactory);
+ if (!deviceInfoResult) {
+ return deviceInfoResult.message();
+ }
+ std::unique_ptr<cppbor::Map> deviceInfoMap = deviceInfoResult.moveValue();
+ auto& signingKey = bccContents->back().pubKey;
+ auto macKey = verifyAndParseCoseSign1(signedMac->asArray(), signingKey,
+ cppbor::Array() // SignedMacAad
+ .add(challenge)
+ .add(std::move(deviceInfoMap))
+ .add(keysToSignMac)
+ .encode());
+ if (!macKey) {
+ return macKey.message();
+ }
+
+ auto coseMac0 = cppbor::Array()
+ .add(cppbor::Map() // protected
+ .add(ALGORITHM, HMAC_256)
+ .canonicalize()
+ .encode())
+ .add(cppbor::Map()) // unprotected
+ .add(keysToSign.encode()) // payload (keysToSign)
+ .add(keysToSignMac); // tag
+
+ auto macPayload = verifyAndParseCoseMac0(&coseMac0, *macKey);
+ if (!macPayload) {
+ return macPayload.message();
+ }
+
+ return *bccContents;
+}
+
+ErrMsgOr<std::vector<BccEntryData>> verifyFactoryProtectedData(
+ const DeviceInfo& deviceInfo, const cppbor::Array& keysToSign,
+ const std::vector<uint8_t>& keysToSignMac, const ProtectedData& protectedData,
+ const EekChain& eekChain, const std::vector<uint8_t>& eekId, int32_t supportedEekCurve,
+ IRemotelyProvisionedComponent* provisionable, const std::vector<uint8_t>& challenge) {
+ return verifyProtectedData(deviceInfo, keysToSign, keysToSignMac, protectedData, eekChain,
+ eekId, supportedEekCurve, provisionable, challenge,
+ /*isFactory=*/true);
+}
+
+ErrMsgOr<std::vector<BccEntryData>> verifyProductionProtectedData(
+ const DeviceInfo& deviceInfo, const cppbor::Array& keysToSign,
+ const std::vector<uint8_t>& keysToSignMac, const ProtectedData& protectedData,
+ const EekChain& eekChain, const std::vector<uint8_t>& eekId, int32_t supportedEekCurve,
+ IRemotelyProvisionedComponent* provisionable, const std::vector<uint8_t>& challenge) {
+ return verifyProtectedData(deviceInfo, keysToSign, keysToSignMac, protectedData, eekChain,
+ eekId, supportedEekCurve, provisionable, challenge,
+ /*isFactory=*/false);
+}
+
+ErrMsgOr<X509_Ptr> parseX509Cert(const std::vector<uint8_t>& cert) {
+ CRYPTO_BUFFER_Ptr certBuf(CRYPTO_BUFFER_new(cert.data(), cert.size(), nullptr));
+ if (!certBuf.get()) {
+ return "Failed to create crypto buffer.";
+ }
+ X509_Ptr result(X509_parse_from_buffer(certBuf.get()));
+ if (!result.get()) {
+ return "Failed to parse certificate.";
+ }
+ return result;
+}
+
+std::string getX509IssuerName(const X509_Ptr& cert) {
+ char* name = X509_NAME_oneline(X509_get_issuer_name(cert.get()), nullptr, 0);
+ std::string result(name);
+ OPENSSL_free(name);
+ return result;
+}
+
+std::string getX509SubjectName(const X509_Ptr& cert) {
+ char* name = X509_NAME_oneline(X509_get_subject_name(cert.get()), nullptr, 0);
+ std::string result(name);
+ OPENSSL_free(name);
+ return result;
+}
+
+// Validates the certificate chain and returns the leaf public key.
+ErrMsgOr<bytevec> validateCertChain(const cppbor::Array& chain) {
+ uint8_t rawPubKey[64];
+ size_t rawPubKeySize = sizeof(rawPubKey);
+ for (size_t i = 0; i < chain.size(); ++i) {
+ // Root must be self-signed.
+ size_t signingCertIndex = (i > 1) ? i - 1 : i;
+ auto& keyCertItem = chain[i];
+ auto& signingCertItem = chain[signingCertIndex];
+ if (!keyCertItem || !keyCertItem->asBstr()) {
+ return "Key certificate must be a Bstr.";
+ }
+ if (!signingCertItem || !signingCertItem->asBstr()) {
+ return "Signing certificate must be a Bstr.";
+ }
+
+ auto keyCert = parseX509Cert(keyCertItem->asBstr()->value());
+ if (!keyCert) {
+ return keyCert.message();
+ }
+ auto signingCert = parseX509Cert(keyCertItem->asBstr()->value());
+ if (!signingCert) {
+ return signingCert.message();
+ }
+
+ EVP_PKEY_Ptr pubKey(X509_get_pubkey(keyCert->get()));
+ if (!pubKey.get()) {
+ return "Failed to get public key.";
+ }
+ EVP_PKEY_Ptr signingPubKey(X509_get_pubkey(signingCert->get()));
+ if (!signingPubKey.get()) {
+ return "Failed to get signing public key.";
+ }
+
+ if (!X509_verify(keyCert->get(), signingPubKey.get())) {
+ return "Verification of certificate " + std::to_string(i) +
+ " faile. OpenSSL error string: " + ERR_error_string(ERR_get_error(), NULL);
+ }
+
+ auto certIssuer = getX509IssuerName(*keyCert);
+ auto signerSubj = getX509SubjectName(*signingCert);
+ if (certIssuer != signerSubj) {
+ return "Certificate " + std::to_string(i) + " has wrong issuer. Signer subject is " +
+ signerSubj + " Issuer subject is " + certIssuer;
+ }
+
+ rawPubKeySize = sizeof(rawPubKey);
+ if (!EVP_PKEY_get_raw_public_key(pubKey.get(), rawPubKey, &rawPubKeySize)) {
+ return "Failed to get raw public key.";
+ }
+ }
+
+ return bytevec(rawPubKey, rawPubKey + rawPubKeySize);
+}
+
+std::string validateUdsCerts(const cppbor::Map& udsCerts, const bytevec& udsPub) {
+ for (const auto& [signerName, udsCertChain] : udsCerts) {
+ if (!signerName || !signerName->asTstr()) {
+ return "Signer Name must be a Tstr.";
+ }
+ if (!udsCertChain || !udsCertChain->asArray()) {
+ return "UDS certificate chain must be an Array.";
+ }
+ if (udsCertChain->asArray()->size() < 2) {
+ return "UDS certificate chain must have at least two entries: root and leaf.";
+ }
+
+ auto leafPubKey = validateCertChain(*udsCertChain->asArray());
+ if (!leafPubKey) {
+ return leafPubKey.message();
+ }
+ if (*leafPubKey != udsPub) {
+ return "Leaf public key in UDS certificat chain doesn't match UDS public key.";
+ }
+ }
+ return "";
+}
+
+ErrMsgOr<std::unique_ptr<cppbor::Array>> parseAndValidateCsrPayload(
+ const cppbor::Array& keysToSign, const std::vector<uint8_t>& csrPayload,
+ IRemotelyProvisionedComponent* provisionable, bool isFactory) {
+ auto [parsedCsrPayload, _, errMsg] = cppbor::parse(csrPayload);
+ if (!parsedCsrPayload) {
+ return errMsg;
+ }
+
+ std::unique_ptr<cppbor::Array> parsed(parsedCsrPayload.release()->asArray());
+ if (!parsed) {
+ return "CSR payload is not a CBOR array.";
+ }
+
+ if (parsed->size() != 4U) {
+ return "CSR payload must contain version, certificate type, device info, keys. "
+ "However, the parsed CSR payload has " +
+ std::to_string(parsed->size()) + " entries.";
+ }
+
+ auto signedVersion = parsed->get(0)->asUint();
+ auto signedCertificateType = parsed->get(1)->asTstr();
+ auto signedDeviceInfo = parsed->get(2)->asMap();
+ auto signedKeys = parsed->get(3)->asArray();
+
+ if (!signedVersion || signedVersion->value() != 3U) {
+ return "CSR payload version must be an unsigned integer and must be equal to 3.";
+ }
+ if (!signedCertificateType) {
+ // Certificate type is allowed to be extendend by vendor, i.e. we can't
+ // enforce its value.
+ return "Certificate type must be a Tstr.";
+ }
+ if (!signedDeviceInfo) {
+ return "Device info must be an Map.";
+ }
+ if (!signedKeys) {
+ return "Keys must be an Array.";
+ }
+
+ auto result = parseAndValidateDeviceInfo(signedDeviceInfo->encode(), provisionable, isFactory);
+ if (!result) {
+ return result.message();
+ }
+
+ if (signedKeys->encode() != keysToSign.encode()) {
+ return "Signed keys do not match.";
+ }
+
+ return std::move(parsed);
+}
+
+ErrMsgOr<bytevec> parseAndValidateAuthenticatedRequestSignedPayload(
+ const std::vector<uint8_t>& signedPayload, const std::vector<uint8_t>& challenge) {
+ auto [parsedSignedPayload, _, errMsg] = cppbor::parse(signedPayload);
+ if (!parsedSignedPayload) {
+ return errMsg;
+ }
+ if (!parsedSignedPayload->asArray()) {
+ return "SignedData payload is not a CBOR array.";
+ }
+ if (parsedSignedPayload->asArray()->size() != 2U) {
+ return "SignedData payload must contain the challenge and request. However, the parsed "
+ "SignedData payload has " +
+ std::to_string(parsedSignedPayload->asArray()->size()) + " entries.";
+ }
+
+ auto signedChallenge = parsedSignedPayload->asArray()->get(0)->asBstr();
+ auto signedRequest = parsedSignedPayload->asArray()->get(1)->asBstr();
+
+ if (!signedChallenge) {
+ return "Challenge must be a Bstr.";
+ }
+
+ if (challenge.size() < 32 || challenge.size() > 64) {
+ return "Challenge size must be between 32 and 64 bytes inclusive. "
+ "However, challenge is " +
+ std::to_string(challenge.size()) + " bytes long.";
+ }
+
+ auto challengeBstr = cppbor::Bstr(challenge);
+ if (*signedChallenge != challengeBstr) {
+ return "Signed challenge does not match."
+ "\n Actual: " +
+ cppbor::prettyPrint(signedChallenge->asBstr(), 64 /* maxBStrSize */) +
+ "\nExpected: " + cppbor::prettyPrint(&challengeBstr, 64 /* maxBStrSize */);
+ }
+
+ if (!signedRequest) {
+ return "Request must be a Bstr.";
+ }
+
+ return signedRequest->value();
+}
+
+ErrMsgOr<bytevec> parseAndValidateAuthenticatedRequest(const std::vector<uint8_t>& request,
+ const std::vector<uint8_t>& challenge) {
+ auto [parsedRequest, _, csrErrMsg] = cppbor::parse(request);
+ if (!parsedRequest) {
+ return csrErrMsg;
+ }
+ if (!parsedRequest->asArray()) {
+ return "AuthenticatedRequest is not a CBOR array.";
+ }
+ if (parsedRequest->asArray()->size() != 4U) {
+ return "AuthenticatedRequest must contain version, UDS certificates, DICE chain, and "
+ "signed data. However, the parsed AuthenticatedRequest has " +
+ std::to_string(parsedRequest->asArray()->size()) + " entries.";
+ }
+
+ auto version = parsedRequest->asArray()->get(0)->asUint();
+ auto udsCerts = parsedRequest->asArray()->get(1)->asMap();
+ auto diceCertChain = parsedRequest->asArray()->get(2)->asArray();
+ auto signedData = parsedRequest->asArray()->get(3)->asArray();
+
+ if (!version || version->value() != 1U) {
+ return "AuthenticatedRequest version must be an unsigned integer and must be equal to 1.";
+ }
+ if (!udsCerts) {
+ return "AuthenticatedRequest UdsCerts must be an Map.";
+ }
+ if (!diceCertChain) {
+ return "AuthenticatedRequest DiceCertChain must be an Array.";
+ }
+ if (!signedData) {
+ return "AuthenticatedRequest SignedData must be an Array.";
+ }
+
+ // DICE chain is [ pubkey, + DiceChainEntry ]. Its format is the same as BCC from RKP v1-2.
+ auto diceContents = validateBcc(diceCertChain);
+ if (!diceContents) {
+ return diceContents.message() + "\n" + prettyPrint(diceCertChain);
+ }
+ if (diceContents->size() == 0U) {
+ return "The DICE chain is empty. It must contain at least one entry.";
+ }
+
+ auto& udsPub = diceContents->back().pubKey;
+
+ auto error = validateUdsCerts(*udsCerts, udsPub);
+ if (!error.empty()) {
+ return error;
+ }
+
+ auto signedPayload = verifyAndParseCoseSign1(signedData, udsPub, {} /* aad */);
+ if (!signedPayload) {
+ return signedPayload.message();
+ }
+
+ auto payload = parseAndValidateAuthenticatedRequestSignedPayload(*signedPayload, challenge);
+ if (!payload) {
+ return payload.message();
+ }
+
+ return payload;
+}
+
+ErrMsgOr<std::unique_ptr<cppbor::Array>> verifyCsr(const cppbor::Array& keysToSign,
+ const std::vector<uint8_t>& csr,
+ IRemotelyProvisionedComponent* provisionable,
+ const std::vector<uint8_t>& challenge,
+ bool isFactory) {
+ RpcHardwareInfo info;
+ provisionable->getHardwareInfo(&info);
+ if (info.versionNumber != 3) {
+ return "Remotely provisioned component version (" + std::to_string(info.versionNumber) +
+ ") does not match expected version (3).";
+ }
+
+ auto csrPayload = parseAndValidateAuthenticatedRequest(csr, challenge);
+ if (!csrPayload) {
+ return csrPayload.message();
+ }
+
+ return parseAndValidateCsrPayload(keysToSign, *csrPayload, provisionable, isFactory);
+}
+
+ErrMsgOr<std::unique_ptr<cppbor::Array>> verifyFactoryCsr(
+ const cppbor::Array& keysToSign, const std::vector<uint8_t>& csr,
+ IRemotelyProvisionedComponent* provisionable, const std::vector<uint8_t>& challenge) {
+ return verifyCsr(keysToSign, csr, provisionable, challenge, /*isFactory=*/true);
+}
+
+ErrMsgOr<std::unique_ptr<cppbor::Array>> verifyProductionCsr(
+ const cppbor::Array& keysToSign, const std::vector<uint8_t>& csr,
+ IRemotelyProvisionedComponent* provisionable, const std::vector<uint8_t>& challenge) {
+ return verifyCsr(keysToSign, csr, provisionable, challenge, /*isFactory=*/false);
+}
+
} // namespace aidl::android::hardware::security::keymint::remote_prov
diff --git a/security/rkp/CHANGELOG.md b/security/rkp/CHANGELOG.md
new file mode 100644
index 0000000..715cf28
--- /dev/null
+++ b/security/rkp/CHANGELOG.md
@@ -0,0 +1,46 @@
+# Remote Provisioning Changelog
+
+This document provides an exact description of which changes have occurred in the
+`IRemotelyProvisionedComponent` HAL interface in each Android release.
+
+## Releases
+* **Android S (12):** IRemotelyProvisionedComponent v1
+* **Android T (13):** IRemotelyProvisionedComponent v2
+* **Android U (14):** IRemotelyProvisionedComponent v3
+
+## IRemotelyProvisionedComponent 1 -> 2
+* DeviceInfo
+ * Most entries are no longer optional.
+ * `att_id_state` is now `fused`. `fused` is used to indicate if SecureBoot is enabled.
+ * `version` is now `2`.
+ * `board` has been removed.
+ * `device` has been added.
+* RpcHardwareInfo
+ * `uniqueId` String added as a field in order to differentiate IRPC instances on device.
+
+## IRemotelyProvisionedComponent 2 -> 3
+* The RKP HAL now builds separately from KeyMint.
+ * The HAL remains under the `android.hardware.security.keymint` package for
+ compatibility with previous releases. ABI compatibility requires this.
+ * Dependencies on the RKP HAL must add a dependency on
+ `"android.hardware.security.rkp"` generated code (instead of
+ `"android.hardward.security.keymint"`).
+* ProtectedData has been removed.
+* DeviceInfo
+ * `version` has moved to a top-level field within the CSR generated by the HAL.
+* IRemotelyProvisionedComponent
+ * The need for an EEK has been removed. There is no longer an encrypted portion of the CSR.
+ * Keys for new CSR format must be generated with test mode set to false, effectively removing test
+ mode in the new CSR flow. Old behavior is kept unchanged for backwards compatibility.
+ * The schema for the CSR itself has been significantly simplified, please see
+ IRemotelyProvisionedComponent.aidl for more details. Notably,
+ * the chain of signing, MACing, and encryption operations has been replaced with a single
+ COSE_Sign1 object.
+ * CertificateType has been added to identify the type of certificate being requested.
+ * The structure has been composed to enable a clear split between what is required to validate a
+ payload and the implementation-defined payload itself. This is done by creating a typed
+ `AuthenticatedRequest<T>` object representing the top level data required to authenticate
+ the data provided in the payload, `T`.
+* RpcHardwareInfo
+ * `supportedNumKeysInCsr` added to report the maximum number of keys supported in a CSR.
+ * `supportedEekCurve` is no longer used, due to the removal of the EEK from the scheme.
diff --git a/security/rkp/README.md b/security/rkp/README.md
new file mode 100644
index 0000000..5fb4948
--- /dev/null
+++ b/security/rkp/README.md
@@ -0,0 +1,374 @@
+# Remote Provisioning HAL
+
+## Objective
+
+Design a HAL to support over-the-air provisioning of certificates for asymmetric
+keys. The HAL must interact effectively with Keystore (and other daemons) and
+protect device privacy and security.
+
+Note that this API was originally designed for KeyMint, with the intention that
+it should be usable for other HALs that require certificate provisioning.
+Throughout this document we'll refer to the Keystore and KeyMint (formerly
+called Keymaster) components, but only for concreteness and convenience; those
+labels could be replaced with the names of any system and secure area
+components, respectively, that need certificates provisioned.
+
+## Key design decisions
+
+### General approach
+
+To more securely and reliably get keys and certificates to Android devices, we
+need to create a system where no party outside of the device's secure components
+is responsible for managing private keys. The strategy we've chosen is to
+deliver certificates over the air, using an asymmetric key pair created
+on-device in the factory as a root of trust to create an authenticated, secure
+channel. In this document we refer to this device-unique asymmetric key pair as
+Device Key (DK), its public half DK\_pub, its private half DK\_priv and a Device
+Key Certificate containing DK\_pub is denoted DKC.
+
+In order for the provisioning service to use DK (or a key authenticated by DK),
+it must know whether a given DK\_pub is known and trusted. To prove trust, we
+ask device OEMs to use one of two mechanisms:
+
+1. (Preferred, recommended) The device OEM extracts DK\_pub from each device it
+ manufactures and uploads the public keys to a backend server.
+
+1. The device OEM signs the DK\_pub to produce DKC and stores it on the device.
+ This has the advantage that they don't need to upload a DK\_pub for every
+ device immediately, but the disadvantage that they have to manage their
+ private signing keys, which means they have to have HSMs, configure and
+ secure them correctly, etc. Some backend providers may also require that the
+ OEM passes a factory security audit, and additionally promises to upload the
+ keys eventually as well.
+
+Note that in the full elaboration of this plan, DK\_pub is not the key used to
+establish a secure channel. Instead, DK\_pub is just the first public key in a
+chain of public keys which ends with the KeyMint public key, KM\_pub. All keys
+in the chain are device-unique and are joined in a certificate chain called the
+_Boot Certificate Chain_ (BCC), because in phases 2 and 3 of the remote
+provisioning project it is a chain of certificates corresponding to boot phases.
+We speak of the BCC even for phase 1, though in phase 1 it contains only a
+single self-signed DKC. This is described in more depth in the Phases section
+below.
+
+The BCC is authenticated by DK\_pub. To authenticate DK\_pub, we may have
+additional DKCs, from the SoC vendor, the device OEM, or both. Those are not
+part of the BCC but included as optional fields in the certificate request
+structure.
+
+The format of the the DK and BCC is specified within [Open Profile for DICE]
+(https://pigweed.googlesource.com/open-dice/+/HEAD/docs/specification.md). To
+map phrases within this document to their equivalent terminology in the DICE
+specification, read the terms as follows: the DK corresponds to the UDS-derived
+key pair, DKC corresponds to the UDS certificate, and the BCC entries between
+DK\_pub and KM\_pub correspond to a chain of CDI certificates.
+
+Note: In addition to allowing 32 byte hash values for fields in the BCC payload,
+this spec additionally constrains some of the choices allowed in open-DICE.
+Specifically, these include which entries are required and which are optional in
+the BCC payload, and which algorithms are acceptable for use.
+
+### Phases
+
+RKP will be deployed in three phases, in terms of managing the root of trust
+binding between the device and the backend. To briefly describe them:
+
+* Phase 1: In phase 1 there is only one entry in the BCC; DK_pub and KM_pub are
+ the same key and the certificate is self-signed.
+* Phase 2: This is identical to phase 1, except it leverages the hardware root
+ of trust process described by DICE. Instead of trust being rooted in the TEE,
+ it is now rooted in the ROM by key material blown into fuses which are only
+ accessible to the ROM code.
+* Phase 3: This is identical to Phase 2, except the SoC vendor also does the
+ public key extraction or certification in their facilities, along with the OEM
+ doing it in the factory. This tightens up the "supply chain" and aims to make
+ key upload management more secure.
+
+### Privacy considerations
+
+Because DK and the DKCs are unique, immutable, unspoofable hardware-bound
+identifiers for the device, we must limit access to them to the absolute minimum
+possible. We do this in two ways:
+
+1. We require KeyMint (which knows the BCC and either knows or at least has the
+ability to use KM\_priv) to refuse to ever divulge the BCC or additional
+signatures in plaintext. Instead, KeyMint requires the caller to provide an
+_Endpoint Encryption Key_ (EEK), with which it will encrypt the data before
+returning it. When provisioning production keys, the EEK must be signed by an
+approved authority whose public key is embedded in KeyMint. When certifying test
+keys, KeyMint will accept any EEK without checking the signature, but will
+encrypt and return a test BCC, rather than the real one. The result is that
+only an entity in possession of an Trusted EEK (TEEK) private key can discover
+the plaintext of the production BCC.
+1. Having thus limited access to the public keys to the trusted party only, we
+need to prevent the entity from abusing this unique device identifier. The
+approach and mechanisms for doing that are beyond the scope of this document
+(they must be addressed in the server design), but generally involve taking care
+to ensure that we do not create any links between user IDs, IP addresses or
+issued certificates and the device pubkey.
+
+Although the details of the mechanisms for preventing the entity from abusing
+the BCC are, as stated, beyond the scope of this document, there is a subtle
+design decision here made specifically to enable abuse prevention. Specifically
+the `CertificateRequest` message sent to the server is (in
+[CDDL](https://tools.ietf.org/html/rfc8610)):
+
+```
+cddl
+CertificateRequest = [
+ DeviceInfo,
+ challenge : bstr,
+ ProtectedData,
+ MacedKeysToSign
+]
+```
+
+The public keys to be attested by the server are in `MacedKeysToSign`, which is
+a COSE\_Mac0 structure, MACed with a key that is found in `ProtectedData`. The
+MAC key is signed by DK\_pub.
+
+This structure allows the backend component that has access to EEK\_priv to
+decrypt `ProtectedData`, validate that the request is from an authorized device,
+check that the request is fresh and verify and extract the MAC key. That backend
+component never sees any data related to the keys to be signed, but can provide
+the MAC key to another backend component that can verify `MacedKeysToSign` and
+proceed to generate the certificates.
+
+In this way, we can partition the provisioning server into one component that
+knows the device identity, as represented by DK\_pub, but never sees the keys to
+be certified or certificates generated, and another component that sees the keys
+to be certified and certificates generated but does not know the device
+identity.
+
+### Key and cryptographic message formatting
+
+For simplicity of generation and parsing, compactness of wire representation,
+and flexibility and standardization, we've settled on using the CBOR Object
+Signing and Encryption (COSE) standard, defined in [RFC
+8152](https://tools.ietf.org/html/rfc8152). COSE provides compact and reasonably
+simple, yet easily-extensible, wire formats for:
+
+* Keys,
+* MACed messages,
+* Signed messages, and
+* Encrypted messages
+
+COSE enables easy layering of these message formats, such as using a COSE\_Sign
+structure to contain a COSE\_Key with a public key in it. We call this a
+"certificate".
+
+Due to the complexity of the standard, we'll spell out the COSE structures
+completely in this document and in the HAL and other documentation, so that
+although implementors will need to understand CBOR and the CBOR Data Definition
+Language ([CDDL, defined in RFC 8610](https://tools.ietf.org/html/rfc8610)),
+they shouldn't need to understand COSE.
+
+Note, however, that the certificate chains returned from the provisioning server
+are standard X.509 certificates.
+
+### Algorithm choices
+
+This document uses:
+
+* ECDSA P-256 for attestation signing keys;
+* Remote provisioning protocol signing keys:
+ * Ed25519 / P-256
+* ECDH keys:
+ * X25519 / P-256
+* AES-GCM for all encryption;
+* SHA-256 for all message digesting;
+* HMAC-SHA-256 for all MACing; and
+* HKDF-SHA-256 for all key derivation.
+
+We believe that Curve25519 offers the best tradeoff in terms of security,
+efficiency and global trustworthiness, and that it is now sufficiently
+widely-used and widely-implemented to make it a practical choice.
+
+However, since Secure Elements (SE) do not currently offer support for curve
+25519, we are allowing implementations to instead make use of EC P-256 for
+signing and ECDH. To put it simply, the device unique key pair will be a P-256
+key pair for ECDSA instead of Ed25519, and the ProtectedData COSE\_Encrypt
+message will have its payload encrypted with P-256 ECDH key exchange instead of
+X25519.
+
+The CDDL in the rest of the document will use the '/' operator to show areas
+where either curve 25519 or P-256 may be used. Since there is no easy way to
+bind choices across different CDDL groups, it is important that the implementor
+stays consistent in which type is chosen. E.g. taking ES256 as the choice for
+algorithm implies the implementor should also choose the P256 public key group
+further down in the COSE structure.
+
+### Testability
+
+It's critical that the remote provisioning implementation be testable, to
+minimize the probability that broken devices are sold to end users. To support
+testing, the remote provisioning HAL methods take a `testMode` argument. Keys
+created in test mode are tagged to indicate this. The provisioning server will
+check for the test mode tag and issue test certificates that do not chain back
+to a trusted public key. In test mode, any EEK will be accepted, enabling
+testing tools to use EEKs for which they have the private key so they can
+validate the content of certificate requests. The BCC included in the
+`CertificateRequest` must contain freshly-generated keys, not the real BCC keys.
+
+Keystore (or similar) will need to be able to handle both testMode keys and
+production keys and keep them distinct, generating test certificate requests
+when asked with a test EEK and production certificate requests when asked with a
+production EEK. Likewise, the interface used to instruct Keystore to create keys
+will need to be able to specify whether test or production keys are desired.
+
+## Design
+
+### Certificate provisioning flow
+
+TODO(jbires): Replace this with a `.png` containing a sequence diagram. The
+provisioning flow looks something like this:
+
+Provisioner -> Keystore: Prepare N keys
+Keystore -> KeyMint: generateKeyPair
+KeyMint -> KeyMint: Generate key pair
+KeyMint --> Keystore: key\_blob,pubkey
+Keystore -> Keystore: Store key\_blob,pubkey
+Provisioner -> Server: Get TEEK
+Server --> Provisioner: TEEK
+Provisioner -> Keystore: genCertReq(N, TEEK)
+Keystore -> KeyMint: genCertReq(pubkeys, TEEK)
+KeyMint -> KeyMint: Sign pubkeys & encrypt BCC
+KeyMint --> Keystore: signature, encrypted BCC
+Keystore -> Keystore: Construct cert\_request
+Keystore --> Provisioner: cert\_request
+Provisioner --> Server: cert\_request
+Server -> Server: Validate cert\_request
+Server -> Server: Generate certificates
+Server --> Provisioner: certificates
+Provisioner -> Keystore: certificates
+Keystore -> Keystore: Store certificates
+
+The actors in the above diagram are:
+
+* **Server** is the backend certificate provisioning server. It has access to
+ the uploaded device public keys and is responsible for providing encryption
+ keys, decrypting and validating requests, and generating certificates in
+ response to requests.
+* **Provisioner** is an application that is responsible for communicating with
+ the server and all of the system components that require key certificates
+ from the server. It also implements the policy that defines how many key
+ pairs each client should keep in their pool.
+* **Keystore** is the [Android keystore
+ daemon](https://developer.android.com/training/articles/keystore) (or, more
+ generally, whatever system component manages communications with a
+ particular secure aread component).
+* **KeyMint** is the secure area component that manages cryptographic keys and
+ performs attestations (or perhaps some other secure area component).
+
+### `BCC`
+
+The _Boot Certificate Chain_ (BCC) is the chain of certificates that contains
+DK\_pub as well as other often device-unique certificates. The BCC is
+represented as a COSE\_Key containing DK\_pub followed by an array of
+COSE\_Sign1 "certificates" containing public keys and optional additional
+information, ordered from root to leaf, with each certificate signing the next.
+The first certificate in the array is signed by DK\_pub, the last certificate
+has the KeyMint (or whatever) signing key's public key, KM\_pub. In phase 1
+there is only one entry; DK\_pub and KM\_pub are the same key and the
+certificate is self-signed.
+
+Each COSE\_Sign1 certificate is a CBOR Web Token (CWT) as described in [RFC
+8392](https://tools.ietf.org/html/rfc8392) with additional fields as described
+in the Open Profile for DICE. Of these additional fields, only the
+_subjectPublicKey_ and _keyUsage_ fields are expected to be present for the
+KM\_pub entry (that is, the last entry) in a BCC, but all fields required by the
+Open Profile for DICE are expected for other entries (each of which corresponds
+to a particular firmware component or boot stage). The CWT fields _iss_ and
+_sub_ identify the issuer and subject of the certificate and are consistent
+along the BCC entries; the issuer of a given entry matches the subject of the
+previous entry.
+
+The BCC is designed to be constructed using the Open Profile for DICE. In this
+case the DK key pair is derived from the UDS as described by that profile and
+all BCC entries before the leaf are CBOR CDI certificates chained from DK\_pub.
+The KM key pair is not part of the derived DICE chain. It is generated (not
+derived) by the KeyMint module, certified by the last key in the DICE chain, and
+added as the leaf BCC entry. The key usage field in this leaf certificate must
+indicate the key is not used to sign certificates. If a UDS certificate is
+available on the device it should appear in the certificate request as the leaf
+of a DKCertChain in AdditionalDKSignatures (see
+[CertificateRequest](#certificaterequest)).
+
+The Open Profile for DICE allows for an arbitrary configuration descriptor. For
+BCC entries, this configuration descriptor is a CBOR map with the following
+optional fields. If no fields are relevant, an empty map should be encoded.
+Additional implementation-specific fields may be added using key values not in
+the range \[-70000, -70999\] (these are reserved for future additions here).
+
+```
+| Name | Key | Value type | Meaning |
+| ----------------- | ------ | ---------- | ----------------------------------|
+| Component name | -70002 | tstr | Name of firmware component / boot |
+: : : : stage :
+| Component version | -70003 | int | Version of firmware component / |
+: : : : boot stage :
+| Resettable | -70004 | null | If present, key changes on factory|
+: : : : reset :
+```
+
+Please see
+[ProtectedData.aidl](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/ProtectedData.aidl)
+for a full CDDL definition of the BCC.
+
+### `CertificateRequest`
+
+The full CBOR message that will be sent to the server to request certificates
+is:
+
+```cddl
+CertificateRequest = [
+ DeviceInfo,
+ challenge : bstr, // Provided by the server
+ ProtectedData, // See ProtectedData.aidl
+ MacedKeysToSign // See IRemotelyProvisionedComponent.aidl
+]
+
+DeviceInfo = [
+ VerifiedDeviceInfo, // See DeviceInfo.aidl
+ UnverifiedDeviceInfo
+]
+
+// Unverified info is anything provided by the HLOS. Subject to change out of
+// step with the HAL.
+UnverifiedDeviceInfo = {
+ ? "fingerprint" : tstr,
+}
+
+```
+
+It will be the responsibility of Keystore and the Provisioner to construct the
+`CertificateRequest`. The HAL provides a method to generate the elements that
+need to be constructed on the secure side, which are the tag field of
+`MacedKeysToSign`, `VerifiedDeviceInfo`, and the ciphertext field of
+`ProtectedData`.
+
+### HAL
+
+The remote provisioning HAL provides a simple interface that can be implemented
+by multiple secure components that require remote provisioning. It would be
+slightly simpler to extend the KeyMint API, but that approach would only serve
+the needs of KeyMint, this is more general.
+
+NOTE the data structures defined in this HAL may look a little bloated and
+complex. This is because the COSE data structures are fully spelled-out; we
+could make it much more compact by not re-specifying the standardized elements
+and instead just referencing the standard, but it seems better to fully specify
+them. If the apparent complexity seems daunting, consider what the same would
+look like if traditional ASN.1 DER-based structures from X.509 and related
+standards were used and also fully elaborated.
+
+Please see the related HAL documentation directly in the source code at the
+following links:
+
+* [IRemotelyProvisionedComponent
+ HAL](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl)
+* [ProtectedData](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/ProtectedData.aidl)
+* [MacedPublicKey](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/MacedPublicKey.aidl)
+* [RpcHardwareInfo](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl)
+* [DeviceInfo](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/DeviceInfo.aidl)
+
diff --git a/security/rkp/aidl/Android.bp b/security/rkp/aidl/Android.bp
new file mode 100644
index 0000000..5285477
--- /dev/null
+++ b/security/rkp/aidl/Android.bp
@@ -0,0 +1,41 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+aidl_interface {
+ name: "android.hardware.security.rkp",
+ vendor_available: true,
+ srcs: [
+ // This HAL was originally part of keymint.
+ "android/hardware/security/keymint/*.aidl",
+
+ // in the future
+ // "android/hardware/security/rkp/*.aidl",
+ ],
+ stability: "vintf",
+ backend: {
+ java: {
+ min_sdk_version: "33",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.rkpd",
+ ],
+ },
+ rust: {
+ enabled: true,
+ },
+ },
+ versions_with_info: [
+ {
+ version: "1",
+ },
+ {
+ version: "2",
+ },
+ ],
+}
diff --git a/security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/.hash b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/.hash
new file mode 100644
index 0000000..404553b
--- /dev/null
+++ b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/.hash
@@ -0,0 +1 @@
+d285480d2e0002adc0ace80edf34aa725679512e
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/android/hardware/security/keymint/DeviceInfo.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/android/hardware/security/keymint/DeviceInfo.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/android/hardware/security/keymint/DeviceInfo.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/android/hardware/security/keymint/DeviceInfo.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/android/hardware/security/keymint/MacedPublicKey.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/android/hardware/security/keymint/MacedPublicKey.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/android/hardware/security/keymint/MacedPublicKey.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/android/hardware/security/keymint/MacedPublicKey.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/android/hardware/security/keymint/ProtectedData.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/android/hardware/security/keymint/ProtectedData.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/android/hardware/security/keymint/ProtectedData.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/android/hardware/security/keymint/ProtectedData.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/android/hardware/security/keymint/RpcHardwareInfo.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/android/hardware/security/keymint/RpcHardwareInfo.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/android/hardware/security/keymint/RpcHardwareInfo.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/android/hardware/security/keymint/RpcHardwareInfo.aidl
diff --git a/security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/.hash b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/.hash
new file mode 100644
index 0000000..8700d33
--- /dev/null
+++ b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/.hash
@@ -0,0 +1 @@
+c8d34e56ae0807b61f028019622d8b60a37e0a8b
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/android/hardware/security/keymint/DeviceInfo.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/android/hardware/security/keymint/DeviceInfo.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/android/hardware/security/keymint/DeviceInfo.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/android/hardware/security/keymint/DeviceInfo.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/android/hardware/security/keymint/MacedPublicKey.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/android/hardware/security/keymint/MacedPublicKey.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/android/hardware/security/keymint/MacedPublicKey.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/android/hardware/security/keymint/MacedPublicKey.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/android/hardware/security/keymint/ProtectedData.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/android/hardware/security/keymint/ProtectedData.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/android/hardware/security/keymint/ProtectedData.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/android/hardware/security/keymint/ProtectedData.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/android/hardware/security/keymint/RpcHardwareInfo.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/android/hardware/security/keymint/RpcHardwareInfo.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/android/hardware/security/keymint/RpcHardwareInfo.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/android/hardware/security/keymint/RpcHardwareInfo.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/DeviceInfo.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/current/android/hardware/security/keymint/DeviceInfo.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/DeviceInfo.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/current/android/hardware/security/keymint/DeviceInfo.aidl
diff --git a/security/rkp/aidl/aidl_api/android.hardware.security.rkp/current/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/current/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
new file mode 100644
index 0000000..626ece8
--- /dev/null
+++ b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/current/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.keymint;
+/* @hide */
+@VintfStability
+interface IRemotelyProvisionedComponent {
+ android.hardware.security.keymint.RpcHardwareInfo getHardwareInfo();
+ byte[] generateEcdsaP256KeyPair(in boolean testMode, out android.hardware.security.keymint.MacedPublicKey macedPublicKey);
+ byte[] generateCertificateRequest(in boolean testMode, in android.hardware.security.keymint.MacedPublicKey[] keysToSign, in byte[] endpointEncryptionCertChain, in byte[] challenge, out android.hardware.security.keymint.DeviceInfo deviceInfo, out android.hardware.security.keymint.ProtectedData protectedData);
+ byte[] generateCertificateRequestV2(in android.hardware.security.keymint.MacedPublicKey[] keysToSign, in byte[] challenge);
+ const int STATUS_FAILED = 1;
+ const int STATUS_INVALID_MAC = 2;
+ const int STATUS_PRODUCTION_KEY_IN_TEST_REQUEST = 3;
+ const int STATUS_TEST_KEY_IN_PRODUCTION_REQUEST = 4;
+ const int STATUS_INVALID_EEK = 5;
+ const int STATUS_REMOVED = 6;
+}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/MacedPublicKey.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/current/android/hardware/security/keymint/MacedPublicKey.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/MacedPublicKey.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/current/android/hardware/security/keymint/MacedPublicKey.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/ProtectedData.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/current/android/hardware/security/keymint/ProtectedData.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/ProtectedData.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/current/android/hardware/security/keymint/ProtectedData.aidl
diff --git a/security/rkp/aidl/aidl_api/android.hardware.security.rkp/current/android/hardware/security/keymint/RpcHardwareInfo.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/current/android/hardware/security/keymint/RpcHardwareInfo.aidl
new file mode 100644
index 0000000..b1f99e1
--- /dev/null
+++ b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/current/android/hardware/security/keymint/RpcHardwareInfo.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.keymint;
+/* @hide */
+@RustDerive(Clone=true, Eq=true, Hash=true, Ord=true, PartialEq=true, PartialOrd=true) @VintfStability
+parcelable RpcHardwareInfo {
+ int versionNumber;
+ @utf8InCpp String rpcAuthorName;
+ int supportedEekCurve = 0;
+ @nullable @utf8InCpp String uniqueId;
+ int supportedNumKeysInCsr = 4;
+ const int CURVE_NONE = 0;
+ const int CURVE_P256 = 1;
+ const int CURVE_25519 = 2;
+ const int MIN_SUPPORTED_NUM_KEYS_IN_CSR = 20;
+}
diff --git a/security/rkp/aidl/android/hardware/security/keymint/DeviceInfo.aidl b/security/rkp/aidl/android/hardware/security/keymint/DeviceInfo.aidl
new file mode 100644
index 0000000..f0af619
--- /dev/null
+++ b/security/rkp/aidl/android/hardware/security/keymint/DeviceInfo.aidl
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.security.keymint;
+
+/**
+ * DeviceInfo contains information about the device that's fed in as AAD in the signature of the
+ * device private key over the MAC key used for the bundle of public keys. These values are intended
+ * to be checked by the server to verify that the certificate signing request crafted by
+ * an IRemotelyProvisionedComponent HAL instance is coming from the expected device based
+ * on values initially uploaded during device manufacture in the factory.
+ * @hide
+ */
+@VintfStability
+parcelable DeviceInfo {
+ /**
+ * DeviceInfo is a CBOR Map structure described by the following CDDL. DeviceInfo must be
+ * canonicalized according to the specification in RFC 7049. The ordering presented here is
+ * non-canonical to group similar entries semantically.
+ *
+ * DeviceInfo = {
+ * "brand" : tstr,
+ * "manufacturer" : tstr,
+ * "product" : tstr,
+ * "model" : tstr,
+ * "device" : tstr,
+ * "vb_state" : "green" / "yellow" / "orange", ; Taken from the AVB values
+ * "bootloader_state" : "locked" / "unlocked", ; Taken from the AVB values
+ * "vbmeta_digest": bstr, ; Taken from the AVB values
+ * ? "os_version" : tstr, ; Same as
+ * ; android.os.Build.VERSION.release
+ * ; Not optional for TEE.
+ * "system_patch_level" : uint, ; YYYYMMDD
+ * "boot_patch_level" : uint, ; YYYYMMDD
+ * "vendor_patch_level" : uint, ; YYYYMMDD
+ * "security_level" : "tee" / "strongbox",
+ * "fused": 1 / 0, ; 1 if secure boot is enforced for the processor that the IRPC
+ * ; implementation is contained in. 0 otherwise.
+ * }
+ */
+ byte[] deviceInfo;
+}
diff --git a/security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl b/security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
new file mode 100644
index 0000000..5485db3
--- /dev/null
+++ b/security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
@@ -0,0 +1,477 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.security.keymint;
+
+import android.hardware.security.keymint.DeviceInfo;
+import android.hardware.security.keymint.MacedPublicKey;
+import android.hardware.security.keymint.ProtectedData;
+import android.hardware.security.keymint.RpcHardwareInfo;
+
+/**
+ * An IRemotelyProvisionedComponent is a secure-side component for which certificates can be
+ * remotely provisioned. It provides an interface for generating asymmetric key pairs and then
+ * creating a CertificateRequest that contains the generated public keys, plus other information to
+ * authenticate the request origin. The CertificateRequest can be sent to a server, which can
+ * validate the request and create certificates.
+ *
+ * This interface does not provide any way to use the generated and certified key pairs. It's
+ * intended to be implemented by a HAL service that does other things with keys (e.g. KeyMint).
+ *
+ * The root of trust for secure provisioning is something called the Device Identifier Composition
+ * Engine (DICE) Chain. The DICE Chain is a chain of certificates, represented as COSE_Sign1 objects
+ * containing CBOR Web Tokens (CWT) which have descriptions about the stage of firmware being
+ * signed, including a COSE_Key representation of that stage's public key.
+ *
+ * DICE Chain Design
+ * =================
+ *
+ * For a more exhaustive and thorough look at DICE and the implementation used within this protocol,
+ * please see: https://pigweed.googlesource.com/open-dice/+/HEAD/docs/specification.md
+ *
+ * The DICE Chain is designed to mirror the boot stages of a device, and to prove the content and
+ * integrity of each firmware image. In a proper DICE Chain, each boot stage hashes its own private
+ * key material with the code and any relevant configuration parameters of the next stage to produce
+ * a Compound Device Identifier, or CDI, which is used as the secret key material for the next
+ * stage. From the CDI, a key pair - CDI_*_Pub and CDI_*_Priv - is derived and certified for the
+ * next stage by the current stages CDI_*_Priv. The next stage is then loaded and given its CDI and
+ * the DICE certificate chain generated so far in a manner that does not leak the previous stage's
+ * CDI_*_Priv or CDI to later boot stages. The final, "leaf" CDI certificate contains a public key,
+ * denoted CDI_Leaf_Pub, whose corresponding private key, denoted CDI_Leaf_Priv, is available for
+ * use by the IRemotelyProvisionedComponent.
+ *
+ * The root keypair is generated by immutable code (e.g. ROM), from a Unique Device Secret (UDS).
+ * The keypair that is generated from it can be referred to as the UDS_Pub/UDS_Priv keys. After the
+ * device-unique secret is used, it must be made unavailable to any later boot stage.
+ *
+ * In this way, booting the device incrementally builds a certificate chain that (a) identifies and
+ * validates the integrity of every stage and (b) contains a set of public keys that correspond to
+ * private keys, one known to each stage. Any stage can compute the secrets of all later stages
+ * (given the necessary input), but no stage can compute the secret of any preceding stage. Updating
+ * the firmware or configuration of any stage changes the key pair of that stage, and of all
+ * subsequent stages, and no attacker who compromised the previous version of the updated firmware
+ * can know or predict the post-update key pairs. It is recommended and expected that the DICE Chain
+ * is constructed using the Open Profile for DICE.
+ *
+ * When the provisioning server receives a message signed by CDI_Leaf_Priv and containing a DICE
+ * chain that chains from UDS_Pub to CDI_Leaf_Pub, it can be certain that (barring vulnerabilities
+ * in some boot stage), the CertificateRequest came from the device associated with UDS_Pub, running
+ * the specific software identified by the certificates in the chain. If the server has some
+ * mechanism for knowing the hash values of compromised stages, it can determine whether signing
+ * certificates is appropriate.
+ *
+ * Degenerate DICE Chains
+ * ======================
+ *
+ * While a proper DICE Chain, as described above, reflects the complete boot sequence from boot ROM
+ * to the secure area image of the IRemotelyProvisionedComponent, it's also possible to use a
+ * "degenerate" DICE Chain which consists only of a single, self-signed certificate containing the
+ * public key of a hardware-bound key pair. This is an appropriate solution for devices which
+ * haven't implemented everything necessary to produce a proper DICE Chain, but can derive a unique
+ * key pair in the secure area. In this degenerate case, UDS_Pub is the same as CDI_Leaf_Pub.
+ *
+ * DICE Chain Privacy
+ * ==================
+ *
+ * Because the DICE Chain constitutes an unspoofable, device-unique identifier, special care is
+ * taken to prevent its availability to entities who may wish to track devices. Three precautions
+ * are taken:
+ *
+ * 1) The DICE chain is only handled by the native Remote Key Provisioning Daemon (RKPD) service on
+ * the HLOS and is not exposed to apps running on device.
+ *
+ * 2) The CDI_Leaf_Priv key cannot be used to sign arbitrary data.
+ *
+ * 3) Backend infrastructure does not correlate UDS_Pub with the certificates signed and sent back
+ * to the device.
+ *
+ * Versioning
+ * ==========
+ * Versions 1 and 2 of the schema, as previously defined in DeviceInfo.aidl, diverge in
+ * functionality from Version 3. Version 3 removes the need to have testMode in function calls and
+ * deprecates the Endpoint Encryption Key (EEK) as well. Vendors implementing Version 1
+ * (Android S/12) or Version 2 (Android T/13) do not need to implement generateCertificateRequestV2.
+ * Vendors implementing Version 3 (Android U/14) need to implement generateCertificateRequestV2.
+ *
+ * For better coverage of changes from version to version, please see RKP_CHANGELOG.md in the root
+ * of the keymint interface directory.
+ *
+ * @hide
+ */
+@VintfStability
+interface IRemotelyProvisionedComponent {
+ const int STATUS_FAILED = 1;
+ const int STATUS_INVALID_MAC = 2;
+ // --------- START: Versions 1 and 2 Only ----------
+ const int STATUS_PRODUCTION_KEY_IN_TEST_REQUEST = 3;
+ const int STATUS_TEST_KEY_IN_PRODUCTION_REQUEST = 4;
+ const int STATUS_INVALID_EEK = 5;
+ // --------- END: Versions 1 and 2 Only ------------
+ const int STATUS_REMOVED = 6;
+
+ /**
+ * @return info which contains information about the underlying IRemotelyProvisionedComponent
+ * hardware, such as version number, component name, author name, and supported curve.
+ */
+ RpcHardwareInfo getHardwareInfo();
+
+ /**
+ * generateKeyPair generates a new ECDSA P-256 key pair that can be attested by the remote
+ * server.
+ *
+ * @param in boolean testMode indicates whether the generated key is for testing only. Test keys
+ * are marked (see the definition of PublicKey in the MacedPublicKey structure) to
+ * prevent them from being confused with production keys.
+ *
+ * @param out MacedPublicKey macedPublicKey contains the public key of the generated key pair,
+ * MACed so that generateCertificateRequest can easily verify, without the
+ * privateKeyHandle, that the contained public key is for remote certification.
+ *
+ * @return data representing a handle to the private key. The format is implementation-defined,
+ * but note that specific services may define a required format. KeyMint does.
+ */
+ byte[] generateEcdsaP256KeyPair(in boolean testMode, out MacedPublicKey macedPublicKey);
+
+ /**
+ * This method can be removed in version 3 of the HAL. The header is kept around for
+ * backwards compatibility purposes. From v3, this method is allowed to raise a
+ * ServiceSpecificException with an error code of STATUS_REMOVED.
+ *
+ * For v1 and v2 implementations:
+ * generateCertificateRequest creates a certificate request to be sent to the provisioning
+ * server.
+ *
+ * @param in boolean testMode indicates whether the generated certificate request is for testing
+ * only.
+ *
+ * @param in MacedPublicKey[] keysToSign contains the set of keys to certify. The
+ * IRemotelyProvisionedComponent must validate the MACs on each key. If any entry in the
+ * array lacks a valid MAC, the method must return STATUS_INVALID_MAC.
+ *
+ * If testMode is true, the keysToCertify array must contain only keys flagged as test
+ * keys. Otherwise, the method must return STATUS_PRODUCTION_KEY_IN_TEST_REQUEST.
+ *
+ * If testMode is false, the keysToCertify array must not contain any keys flagged as
+ * test keys. Otherwise, the method must return STATUS_TEST_KEY_IN_PRODUCTION_REQUEST.
+ *
+ * @param in endpointEncryptionKey contains an X25519 public key which will be used to encrypt
+ * the BCC. For flexibility, this is represented as a certificate chain, represented as a
+ * CBOR array of COSE_Sign1 objects, ordered from root to leaf. The leaf contains the
+ * X25519 encryption key, each other element is an Ed25519 key signing the next in the
+ * chain. The root is self-signed. An implementor may also choose to use P256 as an
+ * alternative curve for signing and encryption instead of Curve 25519.
+ *
+ * EekChain = [ + SignedSignatureKey, SignedEek ]
+ *
+ * SignedSignatureKey = [ ; COSE_Sign1
+ * protected: bstr .cbor {
+ * 1 : AlgorithmEdDSA / AlgorithmES256, ; Algorithm
+ * },
+ * unprotected: {},
+ * payload: bstr .cbor SignatureKeyEd25519 /
+ * bstr .cbor SignatureKeyP256,
+ * signature: bstr PureEd25519(.cbor SignatureKeySignatureInput) /
+ * bstr ECDSA(.cbor SignatureKeySignatureInput)
+ * ]
+ *
+ * SignatureKeyEd25519 = { ; COSE_Key
+ * 1 : 1, ; Key type : Octet Key Pair
+ * 3 : AlgorithmEdDSA, ; Algorithm
+ * -1 : 6, ; Curve : Ed25519
+ * -2 : bstr ; Ed25519 public key
+ * }
+ *
+ * SignatureKeyP256 = { ; COSE_Key
+ * 1 : 2, ; Key type : EC2
+ * 3 : AlgorithmES256, ; Algorithm
+ * -1 : 1, ; Curve: P256
+ * -2 : bstr, ; X coordinate
+ * -3 : bstr ; Y coordinate
+ * }
+ *
+ * SignatureKeySignatureInput = [
+ * context: "Signature1",
+ * body_protected: bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 },
+ * external_aad: bstr .size 0,
+ * payload: bstr .cbor SignatureKeyEd25519 /
+ * bstr .cbor SignatureKeyP256
+ * ]
+ *
+ * ; COSE_Sign1
+ * SignedEek = [
+ * protected: bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 },
+ * unprotected: {},
+ * payload: bstr .cbor EekX25519 / .cbor EekP256,
+ * signature: bstr PureEd25519(.cbor EekSignatureInput) /
+ * bstr ECDSA(.cbor EekSignatureInput)
+ * ]
+ *
+ * EekX25519 = { ; COSE_Key
+ * 1 : 1, ; Key type : Octet Key Pair
+ * 2 : bstr ; KID : EEK ID
+ * 3 : -25, ; Algorithm : ECDH-ES + HKDF-256
+ * -1 : 4, ; Curve : X25519
+ * -2 : bstr ; X25519 public key
+ * }
+ *
+ * EekP256 = { ; COSE_Key
+ * 1 : 2, ; Key type : EC2
+ * 2 : bstr ; KID : EEK ID
+ * 3 : -25, ; Algorithm : ECDH-ES + HKDF-256
+ * -1 : 1, ; Curve : P256
+ * -2 : bstr ; Sender X coordinate
+ * -3 : bstr ; Sender Y coordinate
+ * }
+ *
+ * EekSignatureInput = [
+ * context: "Signature1",
+ * body_protected: bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 },
+ * external_aad: bstr .size 0,
+ * payload: bstr .cbor EekX25519 / .cbor EekP256
+ * ]
+ *
+ * AlgorithmES256 = -7 ; RFC 8152 section 8.1
+ * AlgorithmEdDSA = -8 ; RFC 8152 section 8.2
+ *
+ * If the contents of endpointEncryptionKey do not match the SignedEek structure above,
+ * the method must return STATUS_INVALID_EEK.
+ *
+ * If testMode is true, the method must ignore the length and content of the signatures
+ * in the chain, which implies that it must not attempt to validate the signature.
+ *
+ * If testMode is false, the method must validate the chain signatures, and must verify
+ * that the public key in the root certificate is in its pre-configured set of
+ * authorized EEK root keys. If the public key is not in the database, or if signature
+ * verification fails, the method must return STATUS_INVALID_EEK.
+ *
+ * @param in challenge contains a byte string from the provisioning server that must be signed
+ * by the secure area. See the description of the 'signature' output parameter for
+ * details.
+ *
+ * @param out DeviceInfo contains the VerifiedDeviceInfo portion of the DeviceInfo array in
+ * CertificateRequest. The structure is described within the DeviceInfo.aidl file.
+ *
+ * @param out ProtectedData contains the encrypted BCC and the ephemeral MAC key used to
+ * authenticate the keysToSign (see keysToSignMac output argument).
+ *
+ * @return The MAC of KeysToSign in the CertificateRequest structure. Specifically, it contains:
+ *
+ * HMAC-256(EK_mac, .cbor KeysToMacStructure)
+ *
+ * Where EK_mac is an ephemeral MAC key, found in ProtectedData (see below). The MACed
+ * data is the "tag" field of a COSE_Mac0 structure like:
+ *
+ * MacedKeys = [ ; COSE_Mac0
+ * protected : bstr .cbor {
+ * 1 : 5, ; Algorithm : HMAC-256
+ * },
+ * unprotected : {},
+ * ; Payload is PublicKeys from keysToSign argument, in provided order.
+ * payload: bstr .cbor [ * PublicKey ],
+ * tag: bstr
+ * ]
+ *
+ * KeysToMacStructure = [
+ * context : "MAC0",
+ * protected : bstr .cbor { 1 : 5 }, ; Algorithm : HMAC-256
+ * external_aad : bstr .size 0,
+ * ; Payload is PublicKeys from keysToSign argument, in provided order.
+ * payload : bstr .cbor [ * PublicKey ]
+ * ]
+ */
+ byte[] generateCertificateRequest(in boolean testMode, in MacedPublicKey[] keysToSign,
+ in byte[] endpointEncryptionCertChain, in byte[] challenge, out DeviceInfo deviceInfo,
+ out ProtectedData protectedData);
+
+ /**
+ * generateCertificateRequestV2 creates a certificate signing request to be sent to the
+ * provisioning server.
+ *
+ * @param in MacedPublicKey[] keysToSign contains the set of keys to certify. The
+ * IRemotelyProvisionedComponent must validate the MACs on each key. If any entry in the
+ * array lacks a valid MAC, the method must return STATUS_INVALID_MAC. This method must
+ * not accept test keys. If any entry in the array is a test key, the method must return
+ * STATUS_TEST_KEY_IN_PRODUCTION_REQUEST.
+ *
+ * @param in challenge contains a byte string from the provisioning server which will be
+ * included in the signed data of the CSR structure. Different provisioned backends may
+ * use different semantic data for this field, but the supported sizes must be between 32
+ * and 64 bytes, inclusive.
+ *
+ * @return the following CBOR Certificate Signing Request (Csr) serialized into a byte array:
+ *
+ * Csr = AuthenticatedRequest<CsrPayload>
+ *
+ * CsrPayload = [ ; CBOR Array defining the payload for Csr
+ * version: 3, ; The CsrPayload CDDL Schema version.
+ * CertificateType, ; The type of certificate being requested.
+ * DeviceInfo, ; Defined in DeviceInfo.aidl
+ * KeysToSign, ; Provided by the method parameters
+ * ]
+ *
+ * ; A tstr identifying the type of certificate. The set of supported certificate types may
+ * ; be extended without requiring a version bump of the HAL. Custom certificate types may
+ * ; be used, but the provisioning server may reject the request for an unknown certificate
+ * ; type. The currently defined certificate types are:
+ * ; - "widevine"
+ * ; - "keymint"
+ * CertificateType = tstr
+ *
+ * KeysToSign = [ * PublicKey ] ; Please see MacedPublicKey.aidl for the PublicKey definition.
+ *
+ * AuthenticatedRequest<T> = [
+ * version: 1, ; The AuthenticatedRequest CDDL Schema version.
+ * UdsCerts,
+ * DiceCertChain,
+ * SignedData<[
+ * challenge: bstr .size (32..64), ; Provided by the method parameters
+ * bstr .cbor T,
+ * ]>,
+ * ]
+ *
+ * ; COSE_Sign1 (untagged)
+ * SignedData<Data> = [
+ * protected: bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 },
+ * unprotected: {},
+ * payload: bstr .cbor Data / nil,
+ * signature: bstr ; PureEd25519(CDI_Leaf_Priv, bstr .cbor SignedDataSigStruct<Data>) /
+ * ; ECDSA(CDI_Leaf_Priv, bstr .cbor SignedDataSigStruct<Data>)
+ * ]
+ *
+ * ; Sig_structure for SignedData
+ * SignedDataSigStruct<Data> = [
+ * context: "Signature1",
+ * protected: bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 },
+ * external_aad: bstr .size 0,
+ * payload: bstr .cbor Data / nil,
+ * ]
+ *
+ * ; UdsCerts allows the platform to provide additional certifications for the UDS_Pub. For
+ * ; example, this could be provided by the hardware vendor, who certifies all of their chips.
+ * ; The SignerName is a free-form string describing who generated the signature. The root
+ * ; certificate will need to be communicated to the verifier out of band, along with the
+ * ; SignerName that is expected for the given root certificate.
+ * UdsCerts = {
+ * * SignerName => UdsCertChain
+ * }
+ *
+ * ; SignerName is a string identifier that indicates both the signing authority as
+ * ; well as the format of the UdsCertChain
+ * SignerName = tstr
+ *
+ * UdsCertChain = [
+ * 2* X509Certificate ; Root -> ... -> Leaf. "Root" is the vendor self-signed
+ * ; cert, "Leaf" contains UDS_Public. There may also be
+ * ; intermediate certificates between Root and Leaf.
+ * ]
+ *
+ * ; A bstr containing a DER-encoded X.509 certificate (RSA, NIST P-curve, or EdDSA)
+ * X509Certificate = bstr
+ *
+ * ; The DICE Chain contains measurements about the device firmware.
+ * ; The first entry in the DICE Chain is the UDS_Pub, encoded as a COSE_key. All entries
+ * ; after the first describe a link in the boot chain (e.g. bootloaders: BL1, BL2, ... BLN)
+ * ; Note that there is no DiceChainEntry for UDS_pub, only a "bare" COSE_key.
+ * DiceCertChain = [
+ * PubKeyEd25519 / PubKeyECDSA256, ; UDS_Pub
+ * + DiceChainEntry, ; First CDI_Certificate -> Last CDI_Certificate
+ * ; Last certificate corresponds to KeyMint's DICE key.
+ * ]
+ *
+ * ; This is the signed payload for each entry in the DICE chain. Note that the "Configuration
+ * ; Input Values" described by the Open Profile are not used here. Instead, the DICE chain
+ * ; defines its own configuration values for the Configuration Descriptor field. See
+ * ; the Open Profile for DICE for more details on the fields. SHA256 and SHA512 are acceptable
+ * ; hash algorithms. The digest bstr values in the payload are the digest values without any
+ * ; padding. Note that for SHA256, this implies the digest bstr is 32 bytes. This is an
+ * ; intentional, minor deviation from Open Profile for DICE, which specifies all digests are
+ * ; 64 bytes.
+ * DiceChainEntryPayload = { ; CWT [RFC8392]
+ * 1 : tstr, ; Issuer
+ * 2 : tstr, ; Subject
+ * -4670552 : bstr .cbor PubKeyEd25519 /
+ * bstr .cbor PubKeyECDSA256, ; Subject Public Key
+ * -4670553 : bstr ; Key Usage
+ *
+ * ; NOTE: All of the following fields may be omitted for a "Degenerate DICE Chain", as
+ * ; described above.
+ * -4670545 : bstr, ; Code Hash
+ * ? -4670546 : bstr, ; Code Descriptor
+ * ? -4670547 : bstr, ; Configuration Hash
+ * -4670548 : bstr .cbor { ; Configuration Descriptor
+ * ? -70002 : tstr, ; Component name
+ * ? -70003 : int, ; Firmware version
+ * ? -70004 : null, ; Resettable
+ * },
+ * -4670549 : bstr, ; Authority Hash
+ * ? -4670550 : bstr, ; Authority Descriptor
+ * -4670551 : bstr, ; Mode
+ * }
+ *
+ * ; Each entry in the DICE chain is a DiceChainEntryPayload signed by the key from the previous
+ * ; entry in the DICE chain array.
+ * DiceChainEntry = [ ; COSE_Sign1 (untagged)
+ * protected : bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 },
+ * unprotected: {},
+ * payload: bstr .cbor DiceChainEntryPayload,
+ * signature: bstr ; PureEd25519(SigningKey, bstr .cbor DiceChainEntryInput) /
+ * ; ECDSA(SigningKey, bstr .cbor DiceChainEntryInput)
+ * ; See RFC 8032 for details of how to encode the signature value
+ * ; for Ed25519.
+ * ]
+ *
+ * DiceChainEntryInput = [
+ * context: "Signature1",
+ * protected: bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 },
+ * external_aad: bstr .size 0,
+ * payload: bstr .cbor DiceChainEntryPayload
+ * ]
+ *
+ * ; The following section defines some types that are reused throughout the above
+ * ; data structures.
+ * PubKeyX25519 = { ; COSE_Key
+ * 1 : 1, ; Key type : Octet Key Pair
+ * -1 : 4, ; Curve : X25519
+ * -2 : bstr ; Sender X25519 public key
+ * }
+ *
+ * PubKeyEd25519 = { ; COSE_Key
+ * 1 : 1, ; Key type : octet key pair
+ * 3 : AlgorithmEdDSA, ; Algorithm : EdDSA
+ * -1 : 6, ; Curve : Ed25519
+ * -2 : bstr ; X coordinate, little-endian
+ * }
+ *
+ * PubKeyEcdhP256 = { ; COSE_Key
+ * 1 : 2, ; Key type : EC2
+ * -1 : 1, ; Curve : P256
+ * -2 : bstr ; Sender X coordinate
+ * -3 : bstr ; Sender Y coordinate
+ * }
+ *
+ * PubKeyECDSA256 = { ; COSE_Key
+ * 1 : 2, ; Key type : EC2
+ * 3 : AlgorithmES256, ; Algorithm : ECDSA w/ SHA-256
+ * -1 : 1, ; Curve: P256
+ * -2 : bstr, ; X coordinate
+ * -3 : bstr ; Y coordinate
+ * }
+ *
+ * AlgorithmES256 = -7
+ * AlgorithmEdDSA = -8
+ */
+ byte[] generateCertificateRequestV2(in MacedPublicKey[] keysToSign, in byte[] challenge);
+}
diff --git a/security/rkp/aidl/android/hardware/security/keymint/MacedPublicKey.aidl b/security/rkp/aidl/android/hardware/security/keymint/MacedPublicKey.aidl
new file mode 100644
index 0000000..275e322
--- /dev/null
+++ b/security/rkp/aidl/android/hardware/security/keymint/MacedPublicKey.aidl
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.security.keymint;
+
+/**
+ * MacedPublicKey contains a CBOR-encoded public key, MACed by an IRemotelyProvisionedComponent, to
+ * prove that the key pair was generated by that component.
+ * @hide
+ */
+@VintfStability
+parcelable MacedPublicKey {
+ /**
+ * key is a COSE_Mac0 structure containing the new public key. It's MACed by a key available
+ * 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)
+ * ]
+ *
+ * ; NOTE: -70000 is deprecated for v3 HAL implementations.
+ * PublicKey = { ; COSE_Key
+ * 1 : 2, ; Key type : EC2
+ * 3 : -7, ; Algorithm : ES256
+ * -1 : 1, ; Curve : P256
+ * -2 : bstr, ; X coordinate, little-endian
+ * -3 : bstr, ; Y coordinate, little-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/ProtectedData.aidl b/security/rkp/aidl/android/hardware/security/keymint/ProtectedData.aidl
new file mode 100644
index 0000000..d59508b
--- /dev/null
+++ b/security/rkp/aidl/android/hardware/security/keymint/ProtectedData.aidl
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.security.keymint;
+
+/**
+ * NOTE: ProtectedData has been removed as of version 3, but is kept around for backwards
+ * compatibility reasons. For versions 1 and 2:
+ *
+ * ProtectedData contains the encrypted BCC and the ephemeral MAC key used to
+ * authenticate the keysToSign (see keysToSignMac output argument of
+ * IRemotelyProvisionedComponent.generateCertificateRequest).
+ *
+ * @hide
+ */
+@VintfStability
+parcelable ProtectedData {
+ /**
+ * ProtectedData is a COSE_Encrypt structure, encrypted with an AES key that is agreed upon
+ * using Elliptic-curve Diffie-Hellman. The contents of the structure are specified by the
+ * following CDDL [RFC8610].
+ *
+ * Notes:
+ * - None of the CBOR in ProtectedData uses CBOR tags. If an implementation includes
+ * tags, parsers may reject the data.
+ *
+ * ProtectedData = [ ; COSE_Encrypt
+ * protected: bstr .cbor {
+ * 1 : 3 ; Algorithm : AES-GCM 256
+ * },
+ * unprotected: {
+ * 5 : bstr .size 12 ; IV
+ * },
+ * ciphertext: bstr, ; AES-GCM-256(K, .cbor ProtectedDataPayload)
+ * ; Where the encryption key 'K' is derived as follows:
+ * ; ikm = ECDH(EEK_pub, Ephemeral_priv)
+ * ; salt = null
+ * ; info = .cbor Context (see below)
+ * ; K = HKDF-SHA-256(ikm, salt, info)
+ * recipients : [
+ * [ ; COSE_Recipient
+ * protected : bstr .cbor {
+ * 1 : -25 ; Algorithm : ECDH-ES + HKDF-256
+ * },
+ * unprotected : {
+ * -1 : PubKeyX25519 / PubKeyEcdhP256 ; Ephemeral_pub
+ * 4 : bstr, ; KID : EEK ID
+ * },
+ * ciphertext : nil
+ * ]
+ * ]
+ * ]
+ *
+ * ; The COSE_KDF_Context that is used to derive the ProtectedData encryption key with
+ * ; HKDF. See details on use in ProtectedData comments above.
+ * Context = [
+ * AlgorithmID : 3 ; AES-GCM 256
+ * PartyUInfo : [
+ * identity : bstr "client"
+ * nonce : bstr .size 0,
+ * other : bstr ; Ephemeral_pub
+ * ],
+ * PartyVInfo : [
+ * identity : bstr "server",
+ * nonce : bstr .size 0,
+ * other : bstr ; EEK pubkey
+ * ],
+ * SuppPubInfo : [
+ * 256, ; Output key length
+ * protected : bstr .size 0
+ * ]
+ * ]
+ *
+ * ; The data that is encrypted and included in ProtectedData ciphertext (see above).
+ * ProtectedDataPayload [
+ * SignedMac,
+ * Bcc,
+ * ? AdditionalDKSignatures,
+ * ]
+ *
+ * ; AdditionalDKSignatures allows the platform to provide additional certifications
+ * ; for the DK_pub. For example, this could be provided by the hardware vendor, who
+ * ; certifies all of their devices. The SignerName is a free-form string describing
+ * ; who generated the signature.
+ * AdditionalDKSignatures = {
+ * + SignerName => DKCertChain
+ * }
+ *
+ * ; SignerName is a string identifier that indicates both the signing authority as
+ * ; well as the format of the DKCertChain
+ * SignerName = tstr
+ *
+ * DKCertChain = [
+ * 2* X509Certificate ; Root -> ... -> Leaf. "Root" is the vendor self-signed
+ * ; cert, "Leaf" contains DK_pub. 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 SignedMac, which authenticates the MAC key that is used to authenticate the
+ * ; keysToSign.
+ * SignedMac = [ ; COSE_Sign1
+ * bstr .cbor { ; Protected params
+ * 1 : AlgorithmEdDSA / AlgorithmES256, ; Algorithm
+ * },
+ * {}, ; Unprotected params
+ * bstr .size 32, ; Payload: MAC key
+ * bstr ; PureEd25519(KM_priv, bstr .cbor SignedMac_structure) /
+ * ; ECDSA(KM_priv, bstr .cbor SignedMac_structure)
+ * ]
+ *
+ * SignedMac_structure = [ ; COSE Sig_structure
+ * "Signature1",
+ * bstr .cbor { ; Protected params
+ * 1 : AlgorithmEdDSA / AlgorithmES256, ; Algorithm
+ * },
+ * bstr .cbor SignedMacAad,
+ * bstr .size 32 ; MAC key
+ * ]
+ *
+ * SignedMacAad = [
+ * challenge : bstr .size (32..64), ; Size between 32 - 64
+ * ; bytes inclusive
+ * VerifiedDeviceInfo,
+ * tag: bstr ; This is the tag from COSE_Mac0 of
+ * ; KeysToCertify, to tie the key set to
+ * ; the signature.
+ * ]
+ *
+ * VerifiedDeviceInfo = DeviceInfo ; See DeviceInfo.aidl
+ *
+ * ; The BCC is the boot certificate chain, containing measurements about the device
+ * ; boot chain. The BCC generally follows the Open Profile for DICE specification at
+ * ; https:;pigweed.googlesource.com/open-dice/+/HEAD/docs/specification.md.
+ * ;
+ * ; The first entry in the Bcc is the DK_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 BccEntry for DK_pub, only a "bare" COSE_key.
+ * Bcc = [
+ * PubKeyEd25519 / PubKeyECDSA256, ; DK_pub
+ * + BccEntry, ; Root -> leaf (KM_pub)
+ * ]
+ *
+ * ; This is the signed payload for each entry in the Bcc. Note that the "Configuration
+ * ; Input Values" described by the Open Profile are not used here. Instead, the Bcc
+ * ; defines its own configuration values for the Configuration Descriptor field. See
+ * ; the Open Profile for DICE for more details on the fields. All hashes are SHA256.
+ * BccPayload = { ; CWT [RFC8392]
+ * 1 : tstr, ; Issuer
+ * 2 : tstr, ; Subject
+ * -4670552 : bstr .cbor PubKeyEd25519 /
+ * bstr .cbor PubKeyECDSA256, ; Subject Public Key
+ * -4670553 : bstr ; Key Usage
+ *
+ * ; NOTE: All of the following fields may be omitted for a "Degenerate BCC", as
+ * ; described by IRemotelyProvisionedComponent.aidl.
+ * -4670545 : bstr, ; Code Hash
+ * ? -4670546 : bstr, ; Code Descriptor
+ * ? -4670547 : bstr, ; Configuration Hash
+ * -4670548 : bstr .cbor { ; Configuration Descriptor
+ * ? -70002 : tstr, ; Component name
+ * ? -70003 : int, ; Firmware version
+ * ? -70004 : null, ; Resettable
+ * },
+ * -4670549 : bstr, ; Authority Hash
+ * ? -4670550 : bstr, ; Authority Descriptor
+ * -4670551 : bstr, ; Mode
+ * }
+ *
+ * ; Each entry in the Bcc is a BccPayload signed by the key from the previous entry
+ * ; in the Bcc array.
+ * BccEntry = [ ; COSE_Sign1 (untagged)
+ * protected : bstr .cbor {
+ * 1 : AlgorithmEdDSA / AlgorithmES256, ; Algorithm
+ * },
+ * unprotected: {},
+ * payload: bstr .cbor BccPayload,
+ * signature: bstr ; PureEd25519(SigningKey, bstr .cbor BccEntryInput) /
+ * ; ECDSA(SigningKey, bstr .cbor BccEntryInput)
+ * ; See RFC 8032 for details of how to encode the signature value for Ed25519.
+ * ]
+ *
+ * BccEntryInput = [
+ * context: "Signature1",
+ * protected: bstr .cbor {
+ * 1 : AlgorithmEdDSA / AlgorithmES256, ; Algorithm
+ * },
+ * external_aad: bstr .size 0,
+ * payload: bstr .cbor BccPayload
+ * ]
+ *
+ * ; The following section defines some types that are reused throughout the above
+ * ; data structures.
+ * PubKeyX25519 = { ; COSE_Key
+ * 1 : 1, ; Key type : Octet Key Pair
+ * -1 : 4, ; Curve : X25519
+ * -2 : bstr ; Sender X25519 public key
+ * }
+ *
+ * PubKeyEd25519 = { ; COSE_Key
+ * 1 : 1, ; Key type : octet key pair
+ * 3 : AlgorithmEdDSA, ; Algorithm : EdDSA
+ * -1 : 6, ; Curve : Ed25519
+ * -2 : bstr ; X coordinate, little-endian
+ * }
+ *
+ * PubKeyEcdhP256 = { ; COSE_Key
+ * 1 : 2, ; Key type : EC2
+ * -1 : 1, ; Curve : P256
+ * -2 : bstr ; Sender X coordinate
+ * -3 : bstr ; Sender Y coordinate
+ * }
+ *
+ * PubKeyECDSA256 = { ; COSE_Key
+ * 1 : 2, ; Key type : EC2
+ * 3 : AlgorithmES256, ; Algorithm : ECDSA w/ SHA-256
+ * -1 : 1, ; Curve: P256
+ * -2 : bstr, ; X coordinate
+ * -3 : bstr ; Y coordinate
+ * }
+ *
+ * AlgorithmES256 = -7
+ * AlgorithmEdDSA = -8
+ */
+ byte[] protectedData;
+}
diff --git a/security/rkp/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl b/security/rkp/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl
new file mode 100644
index 0000000..d0b059d
--- /dev/null
+++ b/security/rkp/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.security.keymint;
+
+/**
+ * RpcHardwareInfo is the hardware information returned by calling RemotelyProvisionedComponent
+ * getHardwareInfo()
+ * @hide
+ */
+@VintfStability
+@RustDerive(Clone=true, Eq=true, PartialEq=true, Ord=true, PartialOrd=true, Hash=true)
+parcelable RpcHardwareInfo {
+ const int CURVE_NONE = 0;
+ const int CURVE_P256 = 1;
+ const int CURVE_25519 = 2;
+
+ /**
+ * Implementation version of the remotely provisioned component hardware. The version provided
+ * here must match the version reported in the CsrPayload produced by the HAL interface. This
+ * field primarily acts as a convenience for the system components interacting with the HALs.
+ */
+ int versionNumber;
+
+ /**
+ * rpcAuthorName is the name of the author of the IRemotelyProvisionedComponent implementation
+ * (organization name, not individual). This name is implementation defined, so it can be used
+ * to distinguish between different implementations from the same author.
+ */
+ @utf8InCpp String rpcAuthorName;
+
+ /**
+ * NOTE: This field is no longer used as of version 3 of the HAL interface. This is because the
+ * Endpoint Encryption Key is no longer used in the provisioning scheme.
+ *
+ * supportedEekCurve returns an int representing which curve is supported for validating
+ * signatures over the Endpoint Encryption Key certificate chain and for using the corresponding
+ * signed encryption key in ECDH. Only one curve should be supported, with preference for 25519
+ * if it's available. These values are defined as constants above.
+ *
+ * CURVE_NONE is made the default to help ensure that an implementor doesn't accidentally forget
+ * to provide the correct information here, as the VTS tests will check to make certain that
+ * a passing implementation does not provide CURVE_NONE.
+ */
+ int supportedEekCurve = CURVE_NONE;
+
+ /**
+ * uniqueId is an opaque identifier for this IRemotelyProvisionedComponent implementation. The
+ * client should NOT interpret the content of the identifier in any way. The client can only
+ * compare identifiers to determine if two IRemotelyProvisionedComponents share the same
+ * implementation. Each IRemotelyProvisionedComponent implementation must have a distinct
+ * identifier from all other implementations, and it must be consistent across all devices.
+ * It's critical that this identifier not be usable to uniquely identify a specific device.
+ *
+ * This identifier must be consistent across reboots, as it is used to store and track
+ * provisioned keys in a persistent, on-device database.
+ *
+ * uniqueId may not be empty, and must not be any longer than 32 characters.
+ *
+ * A recommended construction for this value is "[Vendor] [Component Name] [Major Version]",
+ * e.g. "Google Trusty KeyMint 1".
+ *
+ * This field was added in API version 2.
+ *
+ */
+ @nullable @utf8InCpp String uniqueId;
+
+ /**
+ * supportedNumKeysInCsr is the maximum number of keys in a CSR that this implementation can
+ * support. This value is implementation defined.
+ *
+ * From version 3 onwards, supportedNumKeysInCsr must be larger or equal to
+ * MIN_SUPPORTED_NUM_KEYS_IN_CSR.
+ *
+ * The default value was chosen as the value enforced by the VTS test in versions 1 and 2 of
+ * this interface.
+ */
+ const int MIN_SUPPORTED_NUM_KEYS_IN_CSR = 20;
+ int supportedNumKeysInCsr = 4;
+}
diff --git a/security/secureclock/aidl/Android.bp b/security/secureclock/aidl/Android.bp
index 00a6ba3..853ad89 100644
--- a/security/secureclock/aidl/Android.bp
+++ b/security/secureclock/aidl/Android.bp
@@ -18,11 +18,6 @@
java: {
platform_apis: true,
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
rust: {
enabled: true,
apex_available: [
diff --git a/security/sharedsecret/aidl/Android.bp b/security/sharedsecret/aidl/Android.bp
index f1fce74..fe77c10 100644
--- a/security/sharedsecret/aidl/Android.bp
+++ b/security/sharedsecret/aidl/Android.bp
@@ -18,11 +18,6 @@
java: {
sdk_version: "module_current",
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
rust: {
enabled: true,
},
diff --git a/security/sharedsecret/aidl/android/hardware/security/sharedsecret/SharedSecretParameters.aidl b/security/sharedsecret/aidl/android/hardware/security/sharedsecret/SharedSecretParameters.aidl
index 8144699..b72f0de 100644
--- a/security/sharedsecret/aidl/android/hardware/security/sharedsecret/SharedSecretParameters.aidl
+++ b/security/sharedsecret/aidl/android/hardware/security/sharedsecret/SharedSecretParameters.aidl
@@ -33,9 +33,9 @@
byte[] seed;
/**
- * A 32-byte value which is guaranteed to be different each time
- * getSharedSecretParameters() is called. Probabilistic uniqueness (i.e. random) is acceptable,
- * though a stronger uniqueness guarantee (e.g. counter) is recommended where possible.
+ * A 32-byte value which is guaranteed to be different each time getSharedSecretParameters() is
+ * called after a restart. Probabilistic uniqueness (i.e. random) is acceptable, though a
+ * stronger uniqueness guarantee (e.g. counter) is recommended where possible.
*/
byte[] nonce;
}
diff --git a/sensors/1.0/default/Android.bp b/sensors/1.0/default/Android.bp
index 2e4e1b0..bb31050 100644
--- a/sensors/1.0/default/Android.bp
+++ b/sensors/1.0/default/Android.bp
@@ -44,6 +44,12 @@
"libhidlbase",
"android.hardware.sensors@1.0",
],
+ whole_static_libs: [
+ "sensors_common_convert",
+ ],
+ export_static_lib_headers: [
+ "sensors_common_convert",
+ ],
local_include_dirs: ["include/sensors"],
export_shared_lib_headers: [
"libhardware",
diff --git a/sensors/1.0/default/convert.cpp b/sensors/1.0/default/convert.cpp
index 43ee327..ae71a97 100644
--- a/sensors/1.0/default/convert.cpp
+++ b/sensors/1.0/default/convert.cpp
@@ -196,6 +196,11 @@
}
}
+void convertFromASensorEvent(const ASensorEvent& src, Event* dst) {
+ convertFromSensorEvent(
+ android::hardware::sensors::implementation::common::convertASensorEvent(src), dst);
+}
+
void convertToSensorEvent(const Event &src, sensors_event_t *dst) {
*dst = {.version = sizeof(sensors_event_t),
.sensor = src.sensorHandle,
diff --git a/sensors/1.0/default/include/sensors/convert.h b/sensors/1.0/default/include/sensors/convert.h
index c3a0125..ae773df 100644
--- a/sensors/1.0/default/include/sensors/convert.h
+++ b/sensors/1.0/default/include/sensors/convert.h
@@ -20,6 +20,7 @@
#include <android/hardware/sensors/1.0/ISensors.h>
#include <hardware/sensors.h>
+#include <sensors/common_convert.h>
namespace android {
namespace hardware {
@@ -31,6 +32,7 @@
void convertToSensor(const SensorInfo &src, sensor_t *dst);
void convertFromSensorEvent(const sensors_event_t &src, Event *dst);
+void convertFromASensorEvent(const ASensorEvent& src, Event* dst);
void convertToSensorEvent(const Event &src, sensors_event_t *dst);
bool convertFromSharedMemInfo(const SharedMemInfo& memIn, sensors_direct_mem_t *memOut);
diff --git a/sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc b/sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc
index 8867a1a..c874604 100644
--- a/sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc
+++ b/sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc
@@ -1,7 +1,7 @@
service vendor.sensors-hal-2-0-multihal /vendor/bin/hw/android.hardware.sensors@2.0-service.multihal
class hal
user system
- group system wakelock context_hub
+ group system wakelock context_hub input
task_profiles ServiceCapacityLow
capabilities BLOCK_SUSPEND
rlimit rtprio 10 10
diff --git a/sensors/2.1/multihal/android.hardware.sensors@2.1-service-multihal.rc b/sensors/2.1/multihal/android.hardware.sensors@2.1-service-multihal.rc
index f47e060..deea16e 100644
--- a/sensors/2.1/multihal/android.hardware.sensors@2.1-service-multihal.rc
+++ b/sensors/2.1/multihal/android.hardware.sensors@2.1-service-multihal.rc
@@ -1,7 +1,7 @@
service vendor.sensors-hal-2-1-multihal /vendor/bin/hw/android.hardware.sensors@2.1-service.multihal
class hal
user system
- group system wakelock context_hub
+ group system wakelock context_hub input
task_profiles ServiceCapacityLow
capabilities BLOCK_SUSPEND
rlimit rtprio 10 10
diff --git a/sensors/aidl/Android.bp b/sensors/aidl/Android.bp
index 1c2d83f..9673190 100644
--- a/sensors/aidl/Android.bp
+++ b/sensors/aidl/Android.bp
@@ -11,6 +11,7 @@
name: "android.hardware.sensors",
vendor_available: true,
srcs: ["android/hardware/sensors/*.aidl"],
+ host_supported: true,
imports: [
"android.hardware.common-V2",
"android.hardware.common.fmq-V1",
@@ -23,11 +24,6 @@
java: {
enabled: false,
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
versions_with_info: [
{
diff --git a/sensors/aidl/convert/Android.bp b/sensors/aidl/convert/Android.bp
new file mode 100644
index 0000000..0b31597
--- /dev/null
+++ b/sensors/aidl/convert/Android.bp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_static {
+ name: "android.hardware.sensors-V1-convert",
+ vendor_available: true,
+ host_supported: true,
+ srcs: ["convert.cpp"],
+ export_include_dirs: ["include"],
+ shared_libs: [
+ "liblog",
+ "libcutils",
+ "libhardware",
+ "libbase",
+ "libutils",
+ "android.hardware.sensors-V1-ndk",
+ ],
+ whole_static_libs: [
+ "sensors_common_convert",
+ ],
+ export_static_lib_headers: [
+ "sensors_common_convert",
+ ],
+ local_include_dirs: ["include/aidl/sensors"],
+ export_shared_lib_headers: [
+ "libhardware",
+ ],
+}
diff --git a/sensors/aidl/convert/convert.cpp b/sensors/aidl/convert/convert.cpp
new file mode 100644
index 0000000..abd4d55
--- /dev/null
+++ b/sensors/aidl/convert/convert.cpp
@@ -0,0 +1,500 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "aidl/sensors/convert.h"
+#include "android-base/logging.h"
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace implementation {
+
+using aidl::android::hardware::sensors::AdditionalInfo;
+using aidl::android::hardware::sensors::DynamicSensorInfo;
+using aidl::android::hardware::sensors::Event;
+using aidl::android::hardware::sensors::ISensors;
+using aidl::android::hardware::sensors::SensorInfo;
+using aidl::android::hardware::sensors::SensorStatus;
+using aidl::android::hardware::sensors::SensorType;
+
+status_t convertToStatus(ndk::ScopedAStatus status) {
+ if (status.isOk()) {
+ return OK;
+ } else {
+ switch (status.getExceptionCode()) {
+ case EX_ILLEGAL_ARGUMENT: {
+ return BAD_VALUE;
+ }
+ case EX_SECURITY: {
+ return PERMISSION_DENIED;
+ }
+ case EX_UNSUPPORTED_OPERATION: {
+ return INVALID_OPERATION;
+ }
+ case EX_SERVICE_SPECIFIC: {
+ switch (status.getServiceSpecificError()) {
+ case ISensors::ERROR_BAD_VALUE: {
+ return BAD_VALUE;
+ }
+ case ISensors::ERROR_NO_MEMORY: {
+ return NO_MEMORY;
+ }
+ default: {
+ return UNKNOWN_ERROR;
+ }
+ }
+ }
+ default: {
+ return UNKNOWN_ERROR;
+ }
+ }
+ }
+}
+
+void convertToSensor(const SensorInfo& src, sensor_t* dst) {
+ dst->name = strdup(src.name.c_str());
+ dst->vendor = strdup(src.vendor.c_str());
+ dst->version = src.version;
+ dst->handle = src.sensorHandle;
+ dst->type = (int)src.type;
+ dst->maxRange = src.maxRange;
+ dst->resolution = src.resolution;
+ dst->power = src.power;
+ dst->minDelay = src.minDelayUs;
+ dst->fifoReservedEventCount = src.fifoReservedEventCount;
+ dst->fifoMaxEventCount = src.fifoMaxEventCount;
+ dst->stringType = strdup(src.typeAsString.c_str());
+ dst->requiredPermission = strdup(src.requiredPermission.c_str());
+ dst->maxDelay = src.maxDelayUs;
+ dst->flags = src.flags;
+ dst->reserved[0] = dst->reserved[1] = 0;
+}
+
+void convertToSensorEvent(const Event& src, sensors_event_t* dst) {
+ *dst = {.version = sizeof(sensors_event_t),
+ .sensor = src.sensorHandle,
+ .type = (int32_t)src.sensorType,
+ .reserved0 = 0,
+ .timestamp = src.timestamp};
+
+ switch (src.sensorType) {
+ case SensorType::META_DATA: {
+ // Legacy HALs expect the handle reference in the meta data field.
+ // Copy it over from the handle of the event.
+ dst->meta_data.what = (int32_t)src.payload.get<Event::EventPayload::meta>().what;
+ dst->meta_data.sensor = src.sensorHandle;
+ // Set the sensor handle to 0 to maintain compatibility.
+ dst->sensor = 0;
+ break;
+ }
+
+ case SensorType::ACCELEROMETER:
+ case SensorType::MAGNETIC_FIELD:
+ case SensorType::ORIENTATION:
+ case SensorType::GYROSCOPE:
+ case SensorType::GRAVITY:
+ case SensorType::LINEAR_ACCELERATION: {
+ dst->acceleration.x = src.payload.get<Event::EventPayload::vec3>().x;
+ dst->acceleration.y = src.payload.get<Event::EventPayload::vec3>().y;
+ dst->acceleration.z = src.payload.get<Event::EventPayload::vec3>().z;
+ dst->acceleration.status = (int32_t)src.payload.get<Event::EventPayload::vec3>().status;
+ break;
+ }
+
+ case SensorType::GAME_ROTATION_VECTOR: {
+ dst->data[0] = src.payload.get<Event::EventPayload::vec4>().x;
+ dst->data[1] = src.payload.get<Event::EventPayload::vec4>().y;
+ dst->data[2] = src.payload.get<Event::EventPayload::vec4>().z;
+ dst->data[3] = src.payload.get<Event::EventPayload::vec4>().w;
+ break;
+ }
+
+ case SensorType::ROTATION_VECTOR:
+ case SensorType::GEOMAGNETIC_ROTATION_VECTOR: {
+ dst->data[0] = src.payload.get<Event::EventPayload::data>().values[0];
+ dst->data[1] = src.payload.get<Event::EventPayload::data>().values[1];
+ dst->data[2] = src.payload.get<Event::EventPayload::data>().values[2];
+ dst->data[3] = src.payload.get<Event::EventPayload::data>().values[3];
+ dst->data[4] = src.payload.get<Event::EventPayload::data>().values[4];
+ break;
+ }
+
+ case SensorType::MAGNETIC_FIELD_UNCALIBRATED:
+ case SensorType::GYROSCOPE_UNCALIBRATED:
+ case SensorType::ACCELEROMETER_UNCALIBRATED: {
+ dst->uncalibrated_gyro.x_uncalib = src.payload.get<Event::EventPayload::uncal>().x;
+ dst->uncalibrated_gyro.y_uncalib = src.payload.get<Event::EventPayload::uncal>().y;
+ dst->uncalibrated_gyro.z_uncalib = src.payload.get<Event::EventPayload::uncal>().z;
+ dst->uncalibrated_gyro.x_bias = src.payload.get<Event::EventPayload::uncal>().xBias;
+ dst->uncalibrated_gyro.y_bias = src.payload.get<Event::EventPayload::uncal>().yBias;
+ dst->uncalibrated_gyro.z_bias = src.payload.get<Event::EventPayload::uncal>().zBias;
+ break;
+ }
+
+ case SensorType::HINGE_ANGLE:
+ case SensorType::DEVICE_ORIENTATION:
+ case SensorType::LIGHT:
+ case SensorType::PRESSURE:
+ case SensorType::PROXIMITY:
+ case SensorType::RELATIVE_HUMIDITY:
+ case SensorType::AMBIENT_TEMPERATURE:
+ case SensorType::SIGNIFICANT_MOTION:
+ case SensorType::STEP_DETECTOR:
+ case SensorType::TILT_DETECTOR:
+ case SensorType::WAKE_GESTURE:
+ case SensorType::GLANCE_GESTURE:
+ case SensorType::PICK_UP_GESTURE:
+ case SensorType::WRIST_TILT_GESTURE:
+ case SensorType::STATIONARY_DETECT:
+ case SensorType::MOTION_DETECT:
+ case SensorType::HEART_BEAT:
+ case SensorType::LOW_LATENCY_OFFBODY_DETECT: {
+ dst->data[0] = src.payload.get<Event::EventPayload::scalar>();
+ break;
+ }
+
+ case SensorType::STEP_COUNTER: {
+ dst->u64.step_counter = src.payload.get<Event::EventPayload::stepCount>();
+ break;
+ }
+
+ case SensorType::HEART_RATE: {
+ dst->heart_rate.bpm = src.payload.get<Event::EventPayload::heartRate>().bpm;
+ dst->heart_rate.status =
+ (int8_t)src.payload.get<Event::EventPayload::heartRate>().status;
+ break;
+ }
+
+ case SensorType::POSE_6DOF: { // 15 floats
+ for (size_t i = 0; i < 15; ++i) {
+ dst->data[i] = src.payload.get<Event::EventPayload::pose6DOF>().values[i];
+ }
+ break;
+ }
+
+ case SensorType::DYNAMIC_SENSOR_META: {
+ dst->dynamic_sensor_meta.connected =
+ src.payload.get<Event::EventPayload::dynamic>().connected;
+ dst->dynamic_sensor_meta.handle =
+ src.payload.get<Event::EventPayload::dynamic>().sensorHandle;
+ dst->dynamic_sensor_meta.sensor = NULL; // to be filled in later
+
+ memcpy(dst->dynamic_sensor_meta.uuid,
+ src.payload.get<Event::EventPayload::dynamic>().uuid.values.data(), 16);
+
+ break;
+ }
+
+ case SensorType::ADDITIONAL_INFO: {
+ const AdditionalInfo& srcInfo = src.payload.get<Event::EventPayload::additional>();
+
+ additional_info_event_t* dstInfo = &dst->additional_info;
+ dstInfo->type = (int32_t)srcInfo.type;
+ dstInfo->serial = srcInfo.serial;
+
+ switch (srcInfo.payload.getTag()) {
+ case AdditionalInfo::AdditionalInfoPayload::Tag::dataInt32: {
+ const auto& values =
+ srcInfo.payload.get<AdditionalInfo::AdditionalInfoPayload::dataInt32>()
+ .values;
+ CHECK_EQ(values.size() * sizeof(int32_t), sizeof(dstInfo->data_int32));
+ memcpy(dstInfo->data_int32, values.data(), sizeof(dstInfo->data_int32));
+ break;
+ }
+ case AdditionalInfo::AdditionalInfoPayload::Tag::dataFloat: {
+ const auto& values =
+ srcInfo.payload.get<AdditionalInfo::AdditionalInfoPayload::dataFloat>()
+ .values;
+ CHECK_EQ(values.size() * sizeof(float), sizeof(dstInfo->data_float));
+ memcpy(dstInfo->data_float, values.data(), sizeof(dstInfo->data_float));
+ break;
+ }
+ default: {
+ LOG(ERROR) << "Invalid sensor additional info tag: ",
+ (int)srcInfo.payload.getTag();
+ }
+ }
+ break;
+ }
+
+ case SensorType::HEAD_TRACKER: {
+ const auto& ht = src.payload.get<Event::EventPayload::headTracker>();
+ dst->head_tracker.rx = ht.rx;
+ dst->head_tracker.ry = ht.ry;
+ dst->head_tracker.rz = ht.rz;
+ dst->head_tracker.vx = ht.vx;
+ dst->head_tracker.vy = ht.vy;
+ dst->head_tracker.vz = ht.vz;
+ dst->head_tracker.discontinuity_count = ht.discontinuityCount;
+ break;
+ }
+
+ case SensorType::ACCELEROMETER_LIMITED_AXES:
+ case SensorType::GYROSCOPE_LIMITED_AXES:
+ dst->limited_axes_imu.x = src.payload.get<Event::EventPayload::limitedAxesImu>().x;
+ dst->limited_axes_imu.y = src.payload.get<Event::EventPayload::limitedAxesImu>().y;
+ dst->limited_axes_imu.z = src.payload.get<Event::EventPayload::limitedAxesImu>().z;
+ dst->limited_axes_imu.x_supported =
+ src.payload.get<Event::EventPayload::limitedAxesImu>().xSupported;
+ dst->limited_axes_imu.y_supported =
+ src.payload.get<Event::EventPayload::limitedAxesImu>().ySupported;
+ dst->limited_axes_imu.z_supported =
+ src.payload.get<Event::EventPayload::limitedAxesImu>().zSupported;
+ break;
+
+ case SensorType::ACCELEROMETER_LIMITED_AXES_UNCALIBRATED:
+ case SensorType::GYROSCOPE_LIMITED_AXES_UNCALIBRATED:
+ dst->limited_axes_imu_uncalibrated.x_uncalib =
+ src.payload.get<Event::EventPayload::limitedAxesImuUncal>().x;
+ dst->limited_axes_imu_uncalibrated.y_uncalib =
+ src.payload.get<Event::EventPayload::limitedAxesImuUncal>().y;
+ dst->limited_axes_imu_uncalibrated.z_uncalib =
+ src.payload.get<Event::EventPayload::limitedAxesImuUncal>().z;
+ dst->limited_axes_imu_uncalibrated.x_bias =
+ src.payload.get<Event::EventPayload::limitedAxesImuUncal>().xBias;
+ dst->limited_axes_imu_uncalibrated.y_bias =
+ src.payload.get<Event::EventPayload::limitedAxesImuUncal>().yBias;
+ dst->limited_axes_imu_uncalibrated.z_bias =
+ src.payload.get<Event::EventPayload::limitedAxesImuUncal>().zBias;
+ dst->limited_axes_imu_uncalibrated.x_supported =
+ src.payload.get<Event::EventPayload::limitedAxesImuUncal>().xSupported;
+ dst->limited_axes_imu_uncalibrated.y_supported =
+ src.payload.get<Event::EventPayload::limitedAxesImuUncal>().ySupported;
+ dst->limited_axes_imu_uncalibrated.z_supported =
+ src.payload.get<Event::EventPayload::limitedAxesImuUncal>().zSupported;
+ break;
+
+ case SensorType::HEADING:
+ dst->heading.heading = src.payload.get<Event::EventPayload::heading>().heading;
+ dst->heading.accuracy = src.payload.get<Event::EventPayload::heading>().accuracy;
+ break;
+
+ default: {
+ CHECK_GE((int32_t)src.sensorType, (int32_t)SensorType::DEVICE_PRIVATE_BASE);
+
+ memcpy(dst->data, src.payload.get<Event::EventPayload::data>().values.data(),
+ 16 * sizeof(float));
+ break;
+ }
+ }
+}
+
+void convertFromSensorEvent(const sensors_event_t& src, Event* dst) {
+ *dst = {
+ .timestamp = src.timestamp,
+ .sensorHandle = src.sensor,
+ .sensorType = (SensorType)src.type,
+ };
+
+ switch (dst->sensorType) {
+ case SensorType::META_DATA: {
+ Event::EventPayload::MetaData meta;
+ meta.what = (Event::EventPayload::MetaData::MetaDataEventType)src.meta_data.what;
+ // Legacy HALs contain the handle reference in the meta data field.
+ // Copy that over to the handle of the event. In legacy HALs this
+ // field was expected to be 0.
+ dst->sensorHandle = src.meta_data.sensor;
+ dst->payload.set<Event::EventPayload::Tag::meta>(meta);
+ break;
+ }
+
+ case SensorType::ACCELEROMETER:
+ case SensorType::MAGNETIC_FIELD:
+ case SensorType::ORIENTATION:
+ case SensorType::GYROSCOPE:
+ case SensorType::GRAVITY:
+ case SensorType::LINEAR_ACCELERATION: {
+ Event::EventPayload::Vec3 vec3;
+ vec3.x = src.acceleration.x;
+ vec3.y = src.acceleration.y;
+ vec3.z = src.acceleration.z;
+ vec3.status = (SensorStatus)src.acceleration.status;
+ dst->payload.set<Event::EventPayload::Tag::vec3>(vec3);
+ break;
+ }
+
+ case SensorType::GAME_ROTATION_VECTOR: {
+ Event::EventPayload::Vec4 vec4;
+ vec4.x = src.data[0];
+ vec4.y = src.data[1];
+ vec4.z = src.data[2];
+ vec4.w = src.data[3];
+ dst->payload.set<Event::EventPayload::Tag::vec4>(vec4);
+ break;
+ }
+
+ case SensorType::ROTATION_VECTOR:
+ case SensorType::GEOMAGNETIC_ROTATION_VECTOR: {
+ Event::EventPayload::Data data;
+ memcpy(data.values.data(), src.data, 5 * sizeof(float));
+ dst->payload.set<Event::EventPayload::Tag::data>(data);
+ break;
+ }
+
+ case SensorType::MAGNETIC_FIELD_UNCALIBRATED:
+ case SensorType::GYROSCOPE_UNCALIBRATED:
+ case SensorType::ACCELEROMETER_UNCALIBRATED: {
+ Event::EventPayload::Uncal uncal;
+ uncal.x = src.uncalibrated_gyro.x_uncalib;
+ uncal.y = src.uncalibrated_gyro.y_uncalib;
+ uncal.z = src.uncalibrated_gyro.z_uncalib;
+ uncal.xBias = src.uncalibrated_gyro.x_bias;
+ uncal.yBias = src.uncalibrated_gyro.y_bias;
+ uncal.zBias = src.uncalibrated_gyro.z_bias;
+ dst->payload.set<Event::EventPayload::Tag::uncal>(uncal);
+ break;
+ }
+
+ case SensorType::DEVICE_ORIENTATION:
+ case SensorType::LIGHT:
+ case SensorType::PRESSURE:
+ case SensorType::PROXIMITY:
+ case SensorType::RELATIVE_HUMIDITY:
+ case SensorType::AMBIENT_TEMPERATURE:
+ case SensorType::SIGNIFICANT_MOTION:
+ case SensorType::STEP_DETECTOR:
+ case SensorType::TILT_DETECTOR:
+ case SensorType::WAKE_GESTURE:
+ case SensorType::GLANCE_GESTURE:
+ case SensorType::PICK_UP_GESTURE:
+ case SensorType::WRIST_TILT_GESTURE:
+ case SensorType::STATIONARY_DETECT:
+ case SensorType::MOTION_DETECT:
+ case SensorType::HEART_BEAT:
+ case SensorType::LOW_LATENCY_OFFBODY_DETECT:
+ case SensorType::HINGE_ANGLE: {
+ dst->payload.set<Event::EventPayload::Tag::scalar>((float)src.data[0]);
+ break;
+ }
+
+ case SensorType::STEP_COUNTER: {
+ dst->payload.set<Event::EventPayload::Tag::stepCount>(src.u64.step_counter);
+ break;
+ }
+
+ case SensorType::HEART_RATE: {
+ Event::EventPayload::HeartRate heartRate;
+ heartRate.bpm = src.heart_rate.bpm;
+ heartRate.status = (SensorStatus)src.heart_rate.status;
+ dst->payload.set<Event::EventPayload::Tag::heartRate>(heartRate);
+ break;
+ }
+
+ case SensorType::POSE_6DOF: { // 15 floats
+ Event::EventPayload::Pose6Dof pose6DOF;
+ for (size_t i = 0; i < 15; ++i) {
+ pose6DOF.values[i] = src.data[i];
+ }
+ dst->payload.set<Event::EventPayload::Tag::pose6DOF>(pose6DOF);
+ break;
+ }
+
+ case SensorType::DYNAMIC_SENSOR_META: {
+ DynamicSensorInfo dynamic;
+ dynamic.connected = src.dynamic_sensor_meta.connected;
+ dynamic.sensorHandle = src.dynamic_sensor_meta.handle;
+
+ memcpy(dynamic.uuid.values.data(), src.dynamic_sensor_meta.uuid, 16);
+ dst->payload.set<Event::EventPayload::Tag::dynamic>(dynamic);
+ break;
+ }
+
+ case SensorType::ADDITIONAL_INFO: {
+ AdditionalInfo info;
+ const additional_info_event_t& srcInfo = src.additional_info;
+ info.type = (AdditionalInfo::AdditionalInfoType)srcInfo.type;
+ info.serial = srcInfo.serial;
+
+ AdditionalInfo::AdditionalInfoPayload::Int32Values data;
+ CHECK_EQ(data.values.size() * sizeof(int32_t), sizeof(srcInfo.data_int32));
+ memcpy(data.values.data(), srcInfo.data_int32, sizeof(srcInfo.data_int32));
+ info.payload.set<AdditionalInfo::AdditionalInfoPayload::Tag::dataInt32>(data);
+
+ dst->payload.set<Event::EventPayload::Tag::additional>(info);
+ break;
+ }
+
+ case SensorType::HEAD_TRACKER: {
+ Event::EventPayload::HeadTracker headTracker;
+ headTracker.rx = src.head_tracker.rx;
+ headTracker.ry = src.head_tracker.ry;
+ headTracker.rz = src.head_tracker.rz;
+ headTracker.vx = src.head_tracker.vx;
+ headTracker.vy = src.head_tracker.vy;
+ headTracker.vz = src.head_tracker.vz;
+ headTracker.discontinuityCount = src.head_tracker.discontinuity_count;
+
+ dst->payload.set<Event::EventPayload::Tag::headTracker>(headTracker);
+ break;
+ }
+
+ case SensorType::ACCELEROMETER_LIMITED_AXES:
+ case SensorType::GYROSCOPE_LIMITED_AXES: {
+ Event::EventPayload::LimitedAxesImu limitedAxesImu;
+ limitedAxesImu.x = src.limited_axes_imu.x;
+ limitedAxesImu.y = src.limited_axes_imu.y;
+ limitedAxesImu.z = src.limited_axes_imu.z;
+ limitedAxesImu.xSupported = src.limited_axes_imu.x_supported;
+ limitedAxesImu.ySupported = src.limited_axes_imu.y_supported;
+ limitedAxesImu.zSupported = src.limited_axes_imu.z_supported;
+ dst->payload.set<Event::EventPayload::Tag::limitedAxesImu>(limitedAxesImu);
+ break;
+ }
+
+ case SensorType::ACCELEROMETER_LIMITED_AXES_UNCALIBRATED:
+ case SensorType::GYROSCOPE_LIMITED_AXES_UNCALIBRATED: {
+ Event::EventPayload::LimitedAxesImuUncal limitedAxesImuUncal;
+ limitedAxesImuUncal.x = src.limited_axes_imu_uncalibrated.x_uncalib;
+ limitedAxesImuUncal.y = src.limited_axes_imu_uncalibrated.y_uncalib;
+ limitedAxesImuUncal.z = src.limited_axes_imu_uncalibrated.z_uncalib;
+ limitedAxesImuUncal.xBias = src.limited_axes_imu_uncalibrated.x_bias;
+ limitedAxesImuUncal.yBias = src.limited_axes_imu_uncalibrated.y_bias;
+ limitedAxesImuUncal.yBias = src.limited_axes_imu_uncalibrated.y_bias;
+ limitedAxesImuUncal.zBias = src.limited_axes_imu_uncalibrated.z_bias;
+ limitedAxesImuUncal.xSupported = src.limited_axes_imu_uncalibrated.x_supported;
+ limitedAxesImuUncal.ySupported = src.limited_axes_imu_uncalibrated.y_supported;
+ limitedAxesImuUncal.zSupported = src.limited_axes_imu_uncalibrated.z_supported;
+ dst->payload.set<Event::EventPayload::Tag::limitedAxesImuUncal>(limitedAxesImuUncal);
+ break;
+ }
+
+ case SensorType::HEADING: {
+ Event::EventPayload::Heading heading;
+ heading.heading = src.heading.heading;
+ heading.accuracy = src.heading.accuracy;
+ dst->payload.set<Event::EventPayload::heading>(heading);
+ break;
+ }
+
+ default: {
+ CHECK_GE((int32_t)dst->sensorType, (int32_t)SensorType::DEVICE_PRIVATE_BASE);
+
+ Event::EventPayload::Data data;
+ memcpy(data.values.data(), src.data, 16 * sizeof(float));
+ dst->payload.set<Event::EventPayload::Tag::data>(data);
+ break;
+ }
+ }
+}
+
+void convertFromASensorEvent(const ASensorEvent& src, Event* dst) {
+ convertFromSensorEvent(common::convertASensorEvent(src), dst);
+}
+
+} // namespace implementation
+} // namespace sensors
+} // namespace hardware
+} // namespace android
diff --git a/sensors/aidl/convert/include/aidl/sensors/convert.h b/sensors/aidl/convert/include/aidl/sensors/convert.h
new file mode 100644
index 0000000..44504fe
--- /dev/null
+++ b/sensors/aidl/convert/include/aidl/sensors/convert.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/sensors/ISensors.h>
+#include <hardware/sensors.h>
+#include <sensors/common_convert.h>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace implementation {
+
+status_t convertToStatus(ndk::ScopedAStatus status);
+void convertToSensor(const aidl::android::hardware::sensors::SensorInfo& src, sensor_t* dst);
+void convertToSensorEvent(const aidl::android::hardware::sensors::Event& src, sensors_event_t* dst);
+void convertFromSensorEvent(const sensors_event_t& src,
+ aidl::android::hardware::sensors::Event* dst);
+void convertFromASensorEvent(const ASensorEvent& src, aidl::android::hardware::sensors::Event* dst);
+
+} // namespace implementation
+} // namespace sensors
+} // namespace hardware
+} // namespace android
diff --git a/sensors/aidl/default/Sensor.cpp b/sensors/aidl/default/Sensor.cpp
index 62193d6..3bdd8b6 100644
--- a/sensors/aidl/default/Sensor.cpp
+++ b/sensors/aidl/default/Sensor.cpp
@@ -223,7 +223,7 @@
EventPayload::Vec3 vec3 = {
.x = 0,
.y = 0,
- .z = -9.8,
+ .z = 9.8,
.status = SensorStatus::ACCURACY_HIGH,
};
payload.set<EventPayload::Tag::vec3>(vec3);
diff --git a/sensors/common/convert/Android.bp b/sensors/common/convert/Android.bp
new file mode 100644
index 0000000..230665e
--- /dev/null
+++ b/sensors/common/convert/Android.bp
@@ -0,0 +1,42 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_library {
+ name: "sensors_common_convert",
+ srcs: [
+ "convert.cpp",
+ ],
+ vendor_available: true,
+ host_supported: true,
+ local_include_dirs: ["include"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ shared_libs: [
+ "libhardware",
+ ],
+ header_libs: [
+ "libandroid_sensor_headers",
+ ],
+
+ export_include_dirs: ["include"],
+ export_header_lib_headers: [
+ "libandroid_sensor_headers",
+ ],
+}
diff --git a/sensors/common/convert/convert.cpp b/sensors/common/convert/convert.cpp
new file mode 100644
index 0000000..27de32c
--- /dev/null
+++ b/sensors/common/convert/convert.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sensors/common_convert.h>
+#include <cstring>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace implementation {
+namespace common {
+
+sensors_event_t convertASensorEvent(const ASensorEvent& src) {
+ // Attempt to ensure these types are compatible.
+ static_assert(sizeof(sensors_event_t) == sizeof(ASensorEvent));
+ static_assert(offsetof(sensors_event_t, timestamp) == offsetof(ASensorEvent, timestamp));
+ static_assert(offsetof(sensors_event_t, flags) == offsetof(ASensorEvent, flags));
+
+ // TODO(b/259711109) Follow up work to handle this in a safer way.
+ return *reinterpret_cast<const sensors_event_t*>(&src);
+}
+
+} // namespace common
+} // namespace implementation
+} // namespace sensors
+} // namespace hardware
+} // namespace android
diff --git a/sensors/common/convert/include/sensors/common_convert.h b/sensors/common/convert/include/sensors/common_convert.h
new file mode 100644
index 0000000..a281369
--- /dev/null
+++ b/sensors/common/convert/include/sensors/common_convert.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/sensor.h>
+#include <hardware/sensors.h>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace implementation {
+namespace common {
+
+sensors_event_t convertASensorEvent(const ASensorEvent& aEvent);
+
+} // namespace common
+} // namespace implementation
+} // namespace sensors
+} // namespace hardware
+} // namespace android
diff --git a/sensors/common/default/2.X/Sensor.cpp b/sensors/common/default/2.X/Sensor.cpp
index fd701fd..2c1cdfb 100644
--- a/sensors/common/default/2.X/Sensor.cpp
+++ b/sensors/common/default/2.X/Sensor.cpp
@@ -218,7 +218,7 @@
void AccelSensor::readEventPayload(EventPayload& payload) {
payload.vec3.x = 0;
payload.vec3.y = 0;
- payload.vec3.z = -9.8;
+ payload.vec3.z = 9.8;
payload.vec3.status = SensorStatus::ACCURACY_HIGH;
}
diff --git a/sensors/common/default/2.X/multihal/HalProxy.cpp b/sensors/common/default/2.X/multihal/HalProxy.cpp
index f44f5c4..31a17db 100644
--- a/sensors/common/default/2.X/multihal/HalProxy.cpp
+++ b/sensors/common/default/2.X/multihal/HalProxy.cpp
@@ -82,8 +82,11 @@
}
HalProxy::HalProxy() {
- const char* kMultiHalConfigFile = "/vendor/etc/sensors/hals.conf";
- initializeSubHalListFromConfigFile(kMultiHalConfigFile);
+ static const std::string kMultiHalConfigFiles[] = {"/vendor/etc/sensors/hals.conf",
+ "/odm/etc/sensors/hals.conf"};
+ for (const std::string& configFile : kMultiHalConfigFiles) {
+ initializeSubHalListFromConfigFile(configFile.c_str());
+ }
init();
}
diff --git a/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.cpp b/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.cpp
index f5745c5..a0bb67a 100644
--- a/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.cpp
+++ b/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.cpp
@@ -237,7 +237,7 @@
event.timestamp = ::android::elapsedRealtimeNano();
event.u.vec3.x = 0;
event.u.vec3.y = 0;
- event.u.vec3.z = -9.815;
+ event.u.vec3.z = 9.815;
event.u.vec3.status = SensorStatus::ACCURACY_HIGH;
events.push_back(event);
return events;
diff --git a/sensors/common/vts/utils/Android.bp b/sensors/common/vts/utils/Android.bp
index 08b6afa..b35280a 100644
--- a/sensors/common/vts/utils/Android.bp
+++ b/sensors/common/vts/utils/Android.bp
@@ -27,9 +27,11 @@
// dependencies
cc_defaults {
name: "VtsHalSensorsDefaults",
+ defaults: [
+ "android.hardware.graphics.allocator-ndk_shared",
+ "android.hardware.graphics.common-ndk_shared",
+ ],
shared_libs: [
- "android.hardware.graphics.allocator-V1-ndk",
- "android.hardware.graphics.common-V3-ndk",
"libbinder_ndk",
"libutils",
"libvndksupport",
@@ -42,7 +44,11 @@
cc_library_static {
name: "VtsHalSensorsTargetTestUtils",
- defaults: ["VtsHalTargetTestDefaults"],
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "android.hardware.graphics.allocator-ndk_shared",
+ "android.hardware.graphics.common-ndk_shared",
+ ],
cflags: ["-DLOG_TAG=\"sensors_hidl_hal_test\""],
srcs: [
"GrallocWrapper.cpp",
@@ -55,8 +61,6 @@
],
// Targets that depend on us need to also include these
shared_libs: [
- "android.hardware.graphics.allocator-V1-ndk",
- "android.hardware.graphics.common-V3-ndk",
"libbinder_ndk",
"libutils",
"libvndksupport",
diff --git a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlTestBase.h b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlTestBase.h
index f3cbd78..f2c92ae 100644
--- a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlTestBase.h
+++ b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlTestBase.h
@@ -351,11 +351,11 @@
minDelayAverageInterval / 10);
// fastest rate sampling time is close to spec
- EXPECT_LT(std::abs(minDelayAverageInterval - minSamplingPeriodInNs),
+ EXPECT_LE(std::abs(minDelayAverageInterval - minSamplingPeriodInNs),
minSamplingPeriodInNs / 10);
// slowest rate sampling time is close to spec
- EXPECT_LT(std::abs(maxDelayAverageInterval - maxSamplingPeriodInNs),
+ EXPECT_LE(std::abs(maxDelayAverageInterval - maxSamplingPeriodInNs),
maxSamplingPeriodInNs / 10);
}
diff --git a/soundtrigger/2.3/cli/Android.bp b/soundtrigger/2.3/cli/Android.bp
index 27d7b30..883bf2b 100644
--- a/soundtrigger/2.3/cli/Android.bp
+++ b/soundtrigger/2.3/cli/Android.bp
@@ -9,7 +9,7 @@
java_binary {
name: "sthal_cli_2.3",
- wrapper: "sthal_cli_2.3",
+ wrapper: "sthal_cli_2.3.sh",
srcs: ["java/**/*.java"],
static_libs: [
"android.hardware.soundtrigger-V2.3-java",
diff --git a/soundtrigger/2.3/cli/sthal_cli_2.3 b/soundtrigger/2.3/cli/sthal_cli_2.3.sh
similarity index 100%
rename from soundtrigger/2.3/cli/sthal_cli_2.3
rename to soundtrigger/2.3/cli/sthal_cli_2.3.sh
diff --git a/soundtrigger/aidl/Android.bp b/soundtrigger/aidl/Android.bp
index 448895c..27d43d3 100644
--- a/soundtrigger/aidl/Android.bp
+++ b/soundtrigger/aidl/Android.bp
@@ -33,17 +33,26 @@
java: {
sdk_version: "module_current",
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
versions_with_info: [
{
version: "1",
imports: ["android.media.soundtrigger.types-V1"],
},
+ // IMPORTANT: Update latest_android_hardware_soundtrigger3 every time
+ // you add the latest frozen version to versions_with_info
],
+}
+// Note: This should always be one version ahead of the last frozen version
+latest_android_hardware_soundtrigger3 = "android.hardware.soundtrigger3-V1"
+
+// Modules that depend on android.hardware.soundtrigger3 directly can include
+// the following java_defaults to avoid explicitly managing dependency versions
+// across many scattered files.
+java_defaults {
+ name: "latest_android_hardware_soundtrigger3_java_static",
+ static_libs: [
+ latest_android_hardware_soundtrigger3 + "-java",
+ ],
}
diff --git a/soundtrigger/aidl/cli/Android.bp b/soundtrigger/aidl/cli/Android.bp
index e8999ff..935e438 100644
--- a/soundtrigger/aidl/cli/Android.bp
+++ b/soundtrigger/aidl/cli/Android.bp
@@ -9,7 +9,7 @@
java_binary {
name: "sthal_cli_3",
- wrapper: "sthal_cli_3",
+ wrapper: "sthal_cli_3.sh",
srcs: ["java/**/*.java"],
static_libs: [
"android.hardware.soundtrigger3-V1-java",
diff --git a/soundtrigger/aidl/cli/sthal_cli_3 b/soundtrigger/aidl/cli/sthal_cli_3.sh
similarity index 100%
rename from soundtrigger/aidl/cli/sthal_cli_3
rename to soundtrigger/aidl/cli/sthal_cli_3.sh
diff --git a/tests/extension/vibrator/aidl/default/CustomVibrator.cpp b/tests/extension/vibrator/aidl/default/CustomVibrator.cpp
index 2f3dfcb..7a7c58b 100644
--- a/tests/extension/vibrator/aidl/default/CustomVibrator.cpp
+++ b/tests/extension/vibrator/aidl/default/CustomVibrator.cpp
@@ -57,4 +57,12 @@
return ndk::ScopedAStatus::ok();
}
+ndk::SpAIBinder CustomVibrator::createBinder() {
+ auto binder = BnCustomVibrator::createBinder();
+ // e.g. AIBinder_setInheritRt(binder.get(), true);
+ // e.g. AIBinder_setMinSchedulerPolicy(binder.get(), SCHED_NORMAL, 20);
+ // e.g. AIBinder_setRequestingSid(binder.get(), true);
+ return binder;
+}
+
} // namespace aidl::android::hardware::tests::extension::vibrator
diff --git a/tests/extension/vibrator/aidl/default/CustomVibrator.h b/tests/extension/vibrator/aidl/default/CustomVibrator.h
index 6dc5743..084a557 100644
--- a/tests/extension/vibrator/aidl/default/CustomVibrator.h
+++ b/tests/extension/vibrator/aidl/default/CustomVibrator.h
@@ -29,6 +29,12 @@
ndk::ScopedAStatus perform(VendorEffect effect,
const std::shared_ptr<IVibratorCallback>& callback,
int32_t* _aidl_return) override;
+
+ private:
+ // override for AIBinder_setInheritRt, AIBinder_setMinSchedulerPolicy, or
+ // AIBinder_setRequestingSid calling this in the constructor or elsewhere, the binder would
+ // immediately be destroyed.
+ ndk::SpAIBinder createBinder() override;
};
} // namespace aidl::android::hardware::tests::extension::vibrator
diff --git a/thermal/OWNERS b/thermal/OWNERS
new file mode 100644
index 0000000..7229b22
--- /dev/null
+++ b/thermal/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 826709
+
+# ADPF virtual team
+lpy@google.com
+wvw@google.com
diff --git a/thermal/aidl/Android.bp b/thermal/aidl/Android.bp
new file mode 100644
index 0000000..b132746
--- /dev/null
+++ b/thermal/aidl/Android.bp
@@ -0,0 +1,39 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+aidl_interface {
+ name: "android.hardware.thermal",
+ vendor_available: true,
+ srcs: [
+ "android/hardware/thermal/*.aidl",
+ ],
+ stability: "vintf",
+ backend: {
+ cpp: {
+ enabled: true,
+ },
+ java: {
+ platform_apis: true,
+ },
+ },
+}
diff --git a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/CoolingDevice.aidl b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/CoolingDevice.aidl
new file mode 100644
index 0000000..dfd8686
--- /dev/null
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/CoolingDevice.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+1 * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.thermal;
+/* @hide */
+@VintfStability
+parcelable CoolingDevice {
+ android.hardware.thermal.CoolingType type;
+ String name;
+ long value;
+}
diff --git a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/CoolingType.aidl b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/CoolingType.aidl
new file mode 100644
index 0000000..d2eb389
--- /dev/null
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/CoolingType.aidl
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.thermal;
+/* @hide */
+@Backing(type="int") @VintfStability
+enum CoolingType {
+ FAN = 0,
+ BATTERY = 1,
+ CPU = 2,
+ GPU = 3,
+ MODEM = 4,
+ NPU = 5,
+ COMPONENT = 6,
+ TPU = 7,
+ POWER_AMPLIFIER = 8,
+ DISPLAY = 9,
+ SPEAKER = 10,
+}
diff --git a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/IThermal.aidl b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/IThermal.aidl
new file mode 100644
index 0000000..c9b6cab
--- /dev/null
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/IThermal.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.thermal;
+/* @hide */
+@VintfStability
+interface IThermal {
+ android.hardware.thermal.CoolingDevice[] getCoolingDevices();
+ android.hardware.thermal.CoolingDevice[] getCoolingDevicesWithType(in android.hardware.thermal.CoolingType type);
+ android.hardware.thermal.Temperature[] getTemperatures();
+ android.hardware.thermal.Temperature[] getTemperaturesWithType(in android.hardware.thermal.TemperatureType type);
+ android.hardware.thermal.TemperatureThreshold[] getTemperatureThresholds();
+ android.hardware.thermal.TemperatureThreshold[] getTemperatureThresholdsWithType(in android.hardware.thermal.TemperatureType type);
+ void registerThermalChangedCallback(in android.hardware.thermal.IThermalChangedCallback callback);
+ void registerThermalChangedCallbackWithType(in android.hardware.thermal.IThermalChangedCallback callback, in android.hardware.thermal.TemperatureType type);
+ void unregisterThermalChangedCallback(in android.hardware.thermal.IThermalChangedCallback callback);
+}
diff --git a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/IThermalChangedCallback.aidl b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/IThermalChangedCallback.aidl
new file mode 100644
index 0000000..5e1d753
--- /dev/null
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/IThermalChangedCallback.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.thermal;
+/* @hide */
+@VintfStability
+interface IThermalChangedCallback {
+ oneway void notifyThrottling(in android.hardware.thermal.Temperature temperature);
+}
diff --git a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/Temperature.aidl b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/Temperature.aidl
new file mode 100644
index 0000000..3bf08bf
--- /dev/null
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/Temperature.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.thermal;
+/* @hide */
+@VintfStability
+parcelable Temperature {
+ android.hardware.thermal.TemperatureType type;
+ String name;
+ float value;
+ android.hardware.thermal.ThrottlingSeverity throttlingStatus;
+}
diff --git a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/TemperatureThreshold.aidl b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/TemperatureThreshold.aidl
new file mode 100644
index 0000000..c5ca4b9
--- /dev/null
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/TemperatureThreshold.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.thermal;
+/* @hide */
+@VintfStability
+parcelable TemperatureThreshold {
+ android.hardware.thermal.TemperatureType type;
+ String name;
+ float[] hotThrottlingThresholds;
+ float[] coldThrottlingThresholds;
+}
diff --git a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/TemperatureType.aidl b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/TemperatureType.aidl
new file mode 100644
index 0000000..0a9efdd
--- /dev/null
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/TemperatureType.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.thermal;
+/* @hide */
+@Backing(type="int") @VintfStability
+enum TemperatureType {
+ UNKNOWN = -1,
+ CPU = 0,
+ GPU = 1,
+ BATTERY = 2,
+ SKIN = 3,
+ USB_PORT = 4,
+ POWER_AMPLIFIER = 5,
+ BCL_VOLTAGE = 6,
+ BCL_CURRENT = 7,
+ BCL_PERCENTAGE = 8,
+ NPU = 9,
+ TPU = 10,
+ DISPLAY = 11,
+ MODEM = 12,
+ SOC = 13,
+}
diff --git a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/ThrottlingSeverity.aidl b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/ThrottlingSeverity.aidl
new file mode 100644
index 0000000..8fe3df6
--- /dev/null
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/ThrottlingSeverity.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.thermal;
+/* @hide */
+@Backing(type="int") @VintfStability
+enum ThrottlingSeverity {
+ NONE = 0,
+ LIGHT = 1,
+ MODERATE = 2,
+ SEVERE = 3,
+ CRITICAL = 4,
+ EMERGENCY = 5,
+ SHUTDOWN = 6,
+}
diff --git a/thermal/aidl/android/hardware/thermal/CoolingDevice.aidl b/thermal/aidl/android/hardware/thermal/CoolingDevice.aidl
new file mode 100644
index 0000000..1f2360d
--- /dev/null
+++ b/thermal/aidl/android/hardware/thermal/CoolingDevice.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
+ *
+1 * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.thermal;
+
+import android.hardware.thermal.CoolingType;
+
+/* @hide */
+@VintfStability
+parcelable CoolingDevice {
+ /**
+ * This cooling device type, CPU, GPU, BATTERY, and etc.
+ */
+ CoolingType type;
+ /**
+ * Name of this cooling device.
+ * All cooling devices of the same "type" must have a different "name".
+ * The name is usually defined in kernel device tree, and this is for client
+ * logging purpose.
+ */
+ String name;
+ /**
+ * Current throttle state of the cooling device. The value can any unsigned integer
+ * numbers between 0 and max_state defined in its driver, usually representing the
+ * associated device's power state. 0 means device is not in throttling, higher value
+ * means deeper throttling.
+ */
+ long value;
+}
diff --git a/thermal/aidl/android/hardware/thermal/CoolingType.aidl b/thermal/aidl/android/hardware/thermal/CoolingType.aidl
new file mode 100644
index 0000000..08beb55
--- /dev/null
+++ b/thermal/aidl/android/hardware/thermal/CoolingType.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.thermal;
+
+/**
+ * Device cooling device types
+ * @hide
+ */
+@VintfStability
+@Backing(type="int")
+enum CoolingType {
+ FAN,
+ BATTERY,
+ CPU,
+ GPU,
+ MODEM,
+ NPU,
+ COMPONENT,
+ TPU,
+ POWER_AMPLIFIER,
+ DISPLAY,
+ SPEAKER,
+}
diff --git a/thermal/aidl/android/hardware/thermal/IThermal.aidl b/thermal/aidl/android/hardware/thermal/IThermal.aidl
new file mode 100644
index 0000000..dd87b3a
--- /dev/null
+++ b/thermal/aidl/android/hardware/thermal/IThermal.aidl
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.thermal;
+
+import android.hardware.thermal.CoolingDevice;
+import android.hardware.thermal.CoolingType;
+import android.hardware.thermal.IThermalChangedCallback;
+import android.hardware.thermal.Temperature;
+import android.hardware.thermal.TemperatureThreshold;
+import android.hardware.thermal.TemperatureType;
+
+/* @hide */
+@VintfStability
+interface IThermal {
+ /**
+ * Retrieves the cooling devices information.
+ *
+ * @return devices If succeed, it's filled with the
+ * current cooling device information. The order of built-in cooling
+ * devices in the list must be kept the same regardless the number
+ * of calls to this method even if they go offline, if these devices
+ * exist on boot. The method always returns and never removes from
+ * the list such cooling devices.
+ *
+ * @throws ScopedAStatus Status of the operation. If status code is not
+ * STATUS_OK, getMessage() must be populated with the human-readable
+ * error message.
+ */
+ CoolingDevice[] getCoolingDevices();
+
+ /**
+ * Retrieves the cooling devices information of a given CoolingType.
+ *
+ * @param type the CoolingDevice such as CPU/GPU.
+ *
+ * @return devices If succeed, it's filled with the current
+ * cooling device information. The order of built-in cooling
+ * devices in the list must be kept the same regardless of the number
+ * of calls to this method even if they go offline, if these devices
+ * exist on boot. The method always returns and never removes from
+ * the list such cooling devices.
+ *
+ * @throws ScopedAStatus Status of the operation. If status code is not
+ * STATUS_OK, the getMessage() must be populated with the human-readable
+ * error message.
+ */
+ CoolingDevice[] getCoolingDevicesWithType(in CoolingType type);
+
+ /**
+ * Retrieves temperatures in Celsius.
+ *
+ * @return temperatures If succeed, it's filled with the
+ * current temperatures. The order of temperatures of built-in
+ * devices (such as CPUs, GPUs and etc.) in the list must be kept
+ * the same regardless the number of calls to this method even if
+ * they go offline, if these devices exist on boot. The method
+ * always returns and never removes such temperatures.
+ *
+ * @throws ScopedAStatus Status of the operation. If status code is not
+ * STATUS_OK, the getMessage() must be populated with the human-readable
+ * error message.
+ */
+ Temperature[] getTemperatures();
+
+ /**
+ * Retrieves temperatures in Celsius with a given TemperatureType.
+ *
+ * @param type the TemperatureType such as battery or skin.
+ *
+ * @return temperatures If succeed, it's filled with the
+ * current temperatures. The order of temperatures of built-in
+ * devices (such as CPUs, GPUs and etc.) in the list must be kept
+ * the same regardless of the number of calls to this method even if
+ * they go offline, if these devices exist on boot. The method
+ * always returns and never removes such temperatures.
+ *
+ * @throws ScopedAStatus Status of the operation. If status code is not
+ * STATUS_OK, the getMessage() must be populated with the human-readable
+ * error message.
+ */
+ Temperature[] getTemperaturesWithType(in TemperatureType type);
+
+ /**
+ * Retrieves static temperature thresholds in Celsius.
+ *
+ * @return temperatureThresholds If succeed, it's filled with the
+ * temperatures thresholds. The order of temperatures of built-in
+ * devices (such as CPUs, GPUs and etc.) in the list must be kept
+ * the same regardless of the number of calls to this method even if
+ * they go offline, if these devices exist on boot. The method
+ * always returns and never removes such temperatures. The thresholds
+ * are returned as static values and must not change across calls. The actual
+ * throttling state is determined in device thermal mitigation policy/agorithm
+ * which might not be simple thresholds so these values Thermal HAL provided
+ * may not be accurate to detemin the throttling status. To get accurate
+ * throttling status, use getTemperatures or registerThermalChangedCallback
+ * and listen to the callback.
+ *
+ * @throws ScopedAStatus Status of the operation. If status code is not
+ * STATUS_OK, the getMessage() must be populated with the human-readable
+ * error message.
+ */
+ TemperatureThreshold[] getTemperatureThresholds();
+
+ /**
+ * Retrieves static temperature thresholds in Celsius of a given temperature
+ * type.
+ *
+ * @param type the TemperatureType such as battery or skin.
+ *
+ * @return temperatureThresholds If succeed, it's filled with the
+ * temperatures thresholds. The order of temperatures of built-in
+ * devices (such as CPUs, GPUs and etc.) in the list must be kept
+ * the same regardless of the number of calls to this method even if
+ * they go offline, if these devices exist on boot. The method
+ * always returns and never removes such temperatures. The thresholds
+ * are returned as static values and must not change across calls. The actual
+ * throttling state is determined in device thermal mitigation policy/agorithm
+ * which might not be simple thresholds so these values Thermal HAL provided
+ * may not be accurate to detemin the throttling status. To get accurate
+ * throttling status, use getTemperatures or registerThermalChangedCallback
+ * and listen to the callback.
+ *
+ * @throws ScopedAStatus Status of the operation. If status code is not
+ * STATUS_OK, the getMessage() must be populated with the human-readable
+ * error message.
+ */
+ TemperatureThreshold[] getTemperatureThresholdsWithType(in TemperatureType type);
+
+ /**
+ * Register an IThermalChangedCallback, used by the Thermal HAL to receive
+ * thermal events when thermal mitigation status changed.
+ * Multiple registrations with different IThermalChangedCallback must be allowed.
+ * Multiple registrations with same IThermalChangedCallback is not allowed, client
+ * should unregister the given IThermalChangedCallback first.
+ *
+ * @param callback the IThermalChangedCallback to use for receiving
+ * thermal events. if nullptr callback is given, the status code will be
+ * STATUS_BAD_VALUE and the operation will fail.
+ *
+ * @throws ScopedAStatus Status of the operation. If status code is not
+ * STATUS_OK, the getMessage() must be populated with the human-readable
+ * error message. If callback is given nullptr, the returned status code
+ * will be STATUS_BAD_VALUE and the exception will be EX_ILLEGAL_ARGUMENT.
+ * if callback is already registered, the returned status code will be
+ * STATUS_INVALID_OPERATION, the exception will be EX_ILLEGAL_ARGUMENT.
+ */
+ void registerThermalChangedCallback(in IThermalChangedCallback callback);
+
+ /**
+ * Register an IThermalChangedCallback for a given TemperatureType, used by
+ * the Thermal HAL to receive thermal events when thermal mitigation status
+ * changed.
+ * Multiple registrations with different IThermalChangedCallback must be allowed.
+ * Multiple registrations with same IThermalChangedCallback is not allowed, client
+ * should unregister the given IThermalChangedCallback first.
+ *
+ * @param callback the IThermalChangedCallback to use for receiving
+ * thermal events. if nullptr callback is given, the status code will be
+ * STATUS_BAD_VALUE and the operation will fail.
+ * @param type the type to be filtered.
+ *
+ * @throws ScopedAStatus Status of the operation. If status code is not
+ * STATUS_OK, the getMessage() must be populated with the human-readable
+ * error message. If callback is given nullptr, the returned status code
+ * will be STATUS_BAD_VALUE and the exception will be EX_ILLEGAL_ARGUMENT.
+ * if callback is already registered, the returned status code will be
+ * STATUS_INVALID_OPERATION, the exception will be EX_ILLEGAL_ARGUMENT.
+ */
+ void registerThermalChangedCallbackWithType(
+ in IThermalChangedCallback callback, in TemperatureType type);
+
+ /**
+ * Unregister an IThermalChangedCallback, used by the Thermal HAL
+ * to receive thermal events when thermal mitigation status changed.
+ *
+ * @param callback the IThermalChangedCallback to use for receiving
+ * thermal events. if nullptr callback is given, the status code will be
+ * STATUS_BAD_VALUE and the operation will fail.
+ *
+ * @throws ScopedAStatus Status of the operation. If status code is not
+ * STATUS_OK, the getMessage() must be populated with the human-readable
+ * error message. If callback is given nullptr, the returned status code
+ * will be STATUS_BAD_VALUE and the exception will be EX_ILLEGAL_ARGUMENT.
+ * if callback is not registered, the returned status code will be
+ * STATUS_INVALID_OPERATION, the exception will be EX_ILLEGAL_ARGUMENT.
+ */
+ void unregisterThermalChangedCallback(in IThermalChangedCallback callback);
+}
diff --git a/thermal/aidl/android/hardware/thermal/IThermalChangedCallback.aidl b/thermal/aidl/android/hardware/thermal/IThermalChangedCallback.aidl
new file mode 100644
index 0000000..105f085
--- /dev/null
+++ b/thermal/aidl/android/hardware/thermal/IThermalChangedCallback.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.thermal;
+
+import android.hardware.thermal.Temperature;
+
+/**
+ * IThermalChangedCallback send throttling notification to clients.
+ * @hide
+ */
+@VintfStability
+interface IThermalChangedCallback {
+ /**
+ * Send a thermal throttling event to all ThermalHAL
+ * thermal event listeners.
+ *
+ * @param temperature The temperature associated with the
+ * throttling event.
+ */
+ oneway void notifyThrottling(in Temperature temperature);
+}
diff --git a/thermal/aidl/android/hardware/thermal/Temperature.aidl b/thermal/aidl/android/hardware/thermal/Temperature.aidl
new file mode 100644
index 0000000..281d68d
--- /dev/null
+++ b/thermal/aidl/android/hardware/thermal/Temperature.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.thermal;
+
+import android.hardware.thermal.TemperatureType;
+import android.hardware.thermal.ThrottlingSeverity;
+
+/* @hide */
+@VintfStability
+parcelable Temperature {
+ /**
+ * This temperature's type.
+ */
+ TemperatureType type;
+ /**
+ * Name of this temperature matching the TemperatureThreshold.
+ * All temperatures of the same "type" must have a different "name",
+ * e.g., cpu0, battery. Clients use it to match with TemperatureThreshold
+ * struct.
+ */
+ String name;
+ /**
+ * For BCL, this is the current reading of the virtual sensor and the unit is
+ * millivolt, milliamp, percentage for BCL_VOLTAGE, BCL_CURRENT and BCL_PERCENTAGE
+ * respectively. For everything else, this is the current temperature in Celsius.
+ * If not available set by HAL to NAN.
+ */
+ float value;
+ /**
+ * The current throttling level of the sensor.
+ */
+ ThrottlingSeverity throttlingStatus;
+}
diff --git a/thermal/aidl/android/hardware/thermal/TemperatureThreshold.aidl b/thermal/aidl/android/hardware/thermal/TemperatureThreshold.aidl
new file mode 100644
index 0000000..8065f76
--- /dev/null
+++ b/thermal/aidl/android/hardware/thermal/TemperatureThreshold.aidl
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.thermal;
+
+import android.hardware.thermal.TemperatureType;
+
+/* @hide */
+@VintfStability
+parcelable TemperatureThreshold {
+ /**
+ * This temperature's type.
+ */
+ TemperatureType type;
+ /**
+ * Name of this temperature matching the Temperature struct.
+ * All temperatures of the same "type" must have a different "name",
+ * e.g., cpu0, battery. Clients use it to match Temperature struct.
+ */
+ String name;
+ /**
+ * Hot throttling temperature constant for this temperature sensor in
+ * level defined in ThrottlingSeverity including shutdown. Throttling
+ * happens when temperature >= threshold. If not available, set to NAN.
+ * Unit is same as Temperature's value.
+ * The number of thresholds must be the same as ThrottlingSeverity#len.
+ */
+ float[] hotThrottlingThresholds;
+ /**
+ * Cold throttling temperature constant for this temperature sensor in
+ * level defined in ThrottlingSeverity including shutdown. Throttling
+ * happens when temperature <= threshold. If not available, set to NAN.
+ * Unit is same as Temperature's value.
+ * The number of theresholds must be the same as ThrottlingSeverity#len.
+ */
+ float[] coldThrottlingThresholds;
+}
diff --git a/thermal/aidl/android/hardware/thermal/TemperatureType.aidl b/thermal/aidl/android/hardware/thermal/TemperatureType.aidl
new file mode 100644
index 0000000..467d096
--- /dev/null
+++ b/thermal/aidl/android/hardware/thermal/TemperatureType.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.thermal;
+
+/**
+ * Device temperature types
+ * @hide
+ */
+@VintfStability
+@Backing(type="int")
+enum TemperatureType {
+ UNKNOWN = -1,
+ CPU = 0,
+ GPU = 1,
+ BATTERY = 2,
+ SKIN = 3,
+ USB_PORT = 4,
+ POWER_AMPLIFIER = 5,
+ /**
+ * Battery Current Limit - virtual sensors
+ */
+ BCL_VOLTAGE = 6,
+ BCL_CURRENT = 7,
+ BCL_PERCENTAGE = 8,
+ /**
+ * Neural Processing Unit
+ */
+ NPU = 9,
+ TPU = 10,
+ DISPLAY = 11,
+ MODEM = 12,
+ SOC = 13,
+}
diff --git a/thermal/aidl/android/hardware/thermal/ThrottlingSeverity.aidl b/thermal/aidl/android/hardware/thermal/ThrottlingSeverity.aidl
new file mode 100644
index 0000000..c66e6c2
--- /dev/null
+++ b/thermal/aidl/android/hardware/thermal/ThrottlingSeverity.aidl
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.thermal;
+
+/**
+ * Device throttling severity
+ * @hide
+ */
+@VintfStability
+@Backing(type="int")
+enum ThrottlingSeverity {
+ /**
+ * Not under throttling.
+ */
+ NONE = 0,
+ /**
+ * Light throttling where UX is not impacted.
+ */
+ LIGHT,
+ /**
+ * Moderate throttling where UX is not largely impacted.
+ */
+ MODERATE,
+ /**
+ * Severe throttling where UX is largely impacted.
+ * Similar to 1.0 throttlingThreshold.
+ */
+ SEVERE,
+ /**
+ * Platform has done everything to reduce power.
+ */
+ CRITICAL,
+ /**
+ * Key components in platform are shutting down due to thermal condition.
+ * Device functionalities will be limited.
+ */
+ EMERGENCY,
+ /**
+ * Need shutdown immediately.
+ */
+ SHUTDOWN,
+}
diff --git a/thermal/aidl/default/Android.bp b/thermal/aidl/default/Android.bp
new file mode 100644
index 0000000..49a578b
--- /dev/null
+++ b/thermal/aidl/default/Android.bp
@@ -0,0 +1,49 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_binary {
+ name: "android.hardware.thermal-service.example",
+ relative_install_path: "hw",
+ init_rc: [":android.hardware.thermal.example.rc"],
+ vintf_fragments: [":android.hardware.thermal.example.xml"],
+ vendor: true,
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "android.hardware.thermal-V1-ndk",
+ ],
+ srcs: [
+ "main.cpp",
+ "Thermal.cpp",
+ ],
+}
+
+filegroup {
+ name: "android.hardware.thermal.example.xml",
+ srcs: ["thermal-example.xml"],
+}
+
+filegroup {
+ name: "android.hardware.thermal.example.rc",
+ srcs: ["thermal-example.rc"],
+}
diff --git a/thermal/aidl/default/Thermal.cpp b/thermal/aidl/default/Thermal.cpp
new file mode 100644
index 0000000..5771e0e
--- /dev/null
+++ b/thermal/aidl/default/Thermal.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Thermal.h"
+
+#include <android-base/logging.h>
+
+namespace aidl::android::hardware::thermal::impl::example {
+
+using ndk::ScopedAStatus;
+
+ScopedAStatus Thermal::getCoolingDevices(std::vector<CoolingDevice>* /* out_devices */) {
+ LOG(VERBOSE) << __func__;
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus Thermal::getCoolingDevicesWithType(CoolingType in_type,
+ std::vector<CoolingDevice>* /* out_devices */) {
+ LOG(VERBOSE) << __func__ << " CoolingType: " << static_cast<int32_t>(in_type);
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus Thermal::getTemperatures(std::vector<Temperature>* /* out_temperatures */) {
+ LOG(VERBOSE) << __func__;
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus Thermal::getTemperaturesWithType(TemperatureType in_type,
+ std::vector<Temperature>* /* out_temperatures */) {
+ LOG(VERBOSE) << __func__ << " TemperatureType: " << static_cast<int32_t>(in_type);
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus Thermal::getTemperatureThresholds(
+ std::vector<TemperatureThreshold>* /* out_temperatureThresholds */) {
+ LOG(VERBOSE) << __func__;
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus Thermal::getTemperatureThresholdsWithType(
+ TemperatureType in_type,
+ std::vector<TemperatureThreshold>* /* out_temperatureThresholds */) {
+ LOG(VERBOSE) << __func__ << " TemperatureType: " << static_cast<int32_t>(in_type);
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus Thermal::registerThermalChangedCallback(
+ const std::shared_ptr<IThermalChangedCallback>& in_callback) {
+ LOG(VERBOSE) << __func__ << " IThermalChangedCallback: " << in_callback;
+ if (in_callback == nullptr) {
+ return ScopedAStatus::fromStatus(STATUS_BAD_VALUE);
+ }
+ if (mCallbacks.find(in_callback) != mCallbacks.end()) {
+ return ScopedAStatus::fromStatus(STATUS_INVALID_OPERATION);
+ }
+ mCallbacks.insert(in_callback);
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus Thermal::registerThermalChangedCallbackWithType(
+ const std::shared_ptr<IThermalChangedCallback>& in_callback, TemperatureType in_type) {
+ LOG(VERBOSE) << __func__ << " IThermalChangedCallback: " << in_callback
+ << ", TemperatureType: " << static_cast<int32_t>(in_type);
+ if (in_callback == nullptr) {
+ return ScopedAStatus::fromStatus(STATUS_BAD_VALUE);
+ }
+ if (mCallbacks.find(in_callback) != mCallbacks.end()) {
+ return ScopedAStatus::fromStatus(STATUS_INVALID_OPERATION);
+ }
+ mCallbacks.insert(in_callback);
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus Thermal::unregisterThermalChangedCallback(
+ const std::shared_ptr<IThermalChangedCallback>& in_callback) {
+ LOG(VERBOSE) << __func__ << " IThermalChangedCallback: " << in_callback;
+ bool found = false;
+ if (in_callback == nullptr) {
+ return ScopedAStatus::fromStatus(STATUS_BAD_VALUE);
+ }
+ if (mCallbacks.find(in_callback) == mCallbacks.end()) {
+ return ScopedAStatus::fromStatus(STATUS_INVALID_OPERATION);
+ }
+ mCallbacks.erase(in_callback);
+ return ScopedAStatus::ok();
+}
+
+} // namespace aidl::android::hardware::thermal::impl::example
diff --git a/thermal/aidl/default/Thermal.h b/thermal/aidl/default/Thermal.h
new file mode 100644
index 0000000..788af4a
--- /dev/null
+++ b/thermal/aidl/default/Thermal.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <set>
+
+#include <aidl/android/hardware/thermal/BnThermal.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace thermal {
+namespace impl {
+namespace example {
+
+class Thermal : public BnThermal {
+ public:
+ ndk::ScopedAStatus getCoolingDevices(std::vector<CoolingDevice>* out_devices) override;
+ ndk::ScopedAStatus getCoolingDevicesWithType(CoolingType in_type,
+ std::vector<CoolingDevice>* out_devices) override;
+
+ ndk::ScopedAStatus getTemperatures(std::vector<Temperature>* out_temperatures) override;
+ ndk::ScopedAStatus getTemperaturesWithType(TemperatureType in_type,
+ std::vector<Temperature>* out_temperatures) override;
+
+ ndk::ScopedAStatus getTemperatureThresholds(
+ std::vector<TemperatureThreshold>* out_temperatureThresholds) override;
+
+ ndk::ScopedAStatus getTemperatureThresholdsWithType(
+ TemperatureType in_type,
+ std::vector<TemperatureThreshold>* out_temperatureThresholds) override;
+
+ ndk::ScopedAStatus registerThermalChangedCallback(
+ const std::shared_ptr<IThermalChangedCallback>& in_callback) override;
+ ndk::ScopedAStatus registerThermalChangedCallbackWithType(
+ const std::shared_ptr<IThermalChangedCallback>& in_callback,
+ TemperatureType in_type) override;
+
+ ndk::ScopedAStatus unregisterThermalChangedCallback(
+ const std::shared_ptr<IThermalChangedCallback>& in_callback) override;
+
+ private:
+ std::set<std::shared_ptr<IThermalChangedCallback>> mCallbacks;
+};
+
+} // namespace example
+} // namespace impl
+} // namespace thermal
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/thermal/aidl/default/main.cpp b/thermal/aidl/default/main.cpp
new file mode 100644
index 0000000..61d8ad0
--- /dev/null
+++ b/thermal/aidl/default/main.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Thermal.h"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+using aidl::android::hardware::thermal::impl::example::Thermal;
+
+int main() {
+ ABinderProcess_setThreadPoolMaxThreadCount(0);
+ std::shared_ptr<Thermal> thermal = ndk::SharedRefBase::make<Thermal>();
+
+ const std::string instance = std::string() + Thermal::descriptor + "/default";
+ binder_status_t status =
+ AServiceManager_addService(thermal->asBinder().get(), instance.c_str());
+ CHECK(status == STATUS_OK);
+
+ ABinderProcess_joinThreadPool();
+ return EXIT_FAILURE; // should not reach
+}
diff --git a/thermal/aidl/default/thermal-example.rc b/thermal/aidl/default/thermal-example.rc
new file mode 100644
index 0000000..591ca03
--- /dev/null
+++ b/thermal/aidl/default/thermal-example.rc
@@ -0,0 +1,4 @@
+service vendor.thermal-example /vendor/bin/hw/android.hardware.thermal-service.example
+ class hal
+ user nobody
+ group system
diff --git a/thermal/aidl/default/thermal-example.xml b/thermal/aidl/default/thermal-example.xml
new file mode 100644
index 0000000..bdee744
--- /dev/null
+++ b/thermal/aidl/default/thermal-example.xml
@@ -0,0 +1,7 @@
+<manifest version="1.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.thermal</name>
+ <version>1</version>
+ <fqname>IThermal/default</fqname>
+ </hal>
+</manifest>
diff --git a/thermal/aidl/vts/Android.bp b/thermal/aidl/vts/Android.bp
new file mode 100644
index 0000000..b00eb33
--- /dev/null
+++ b/thermal/aidl/vts/Android.bp
@@ -0,0 +1,40 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_test {
+ name: "VtsHalThermalTargetTest",
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "use_libaidlvintf_gtest_helper_static",
+ ],
+ srcs: ["VtsHalThermalTargetTest.cpp"],
+ shared_libs: [
+ "libbinder_ndk",
+ ],
+ static_libs: [
+ "android.hardware.thermal-V1-ndk",
+ ],
+ test_suites: [
+ "vts",
+ ],
+}
diff --git a/thermal/aidl/vts/VtsHalThermalTargetTest.cpp b/thermal/aidl/vts/VtsHalThermalTargetTest.cpp
new file mode 100644
index 0000000..b93250e
--- /dev/null
+++ b/thermal/aidl/vts/VtsHalThermalTargetTest.cpp
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <algorithm>
+#include <chrono>
+#include <cmath>
+#include <memory>
+#include <string>
+#include <thread>
+#include <vector>
+
+#define LOG_TAG "thermal_aidl_hal_test"
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/thermal/BnThermal.h>
+#include <aidl/android/hardware/thermal/BnThermalChangedCallback.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android/binder_ibinder.h>
+#include <android/binder_interface_utils.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <android/binder_status.h>
+#include <gtest/gtest.h>
+
+#include <unistd.h>
+
+namespace aidl::android::hardware::thermal {
+
+namespace {
+
+using ::android::sp;
+using android::hardware::thermal::CoolingDevice;
+using android::hardware::thermal::IThermal;
+using android::hardware::thermal::Temperature;
+using android::hardware::thermal::TemperatureType;
+
+using namespace std::string_literals;
+using namespace std::chrono_literals;
+
+static const Temperature kThrottleTemp = {
+ .type = TemperatureType::SKIN,
+ .name = "test temperature sensor",
+ .value = 98.6,
+ .throttlingStatus = ThrottlingSeverity::CRITICAL,
+};
+
+// Callback class for receiving thermal event notifications from main class
+class ThermalCallback : public BnThermalChangedCallback {
+ public:
+ ndk::ScopedAStatus notifyThrottling(const Temperature&) override {
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mInvoke = true;
+ }
+ mNotifyThrottling.notify_all();
+ return ndk::ScopedAStatus::ok();
+ }
+
+ template <typename R, typename P>
+ [[nodiscard]] bool waitForCallback(std::chrono::duration<R, P> duration) {
+ std::unique_lock<std::mutex> lock(mMutex);
+ bool r = mNotifyThrottling.wait_for(lock, duration, [this] { return this->mInvoke; });
+ mInvoke = false;
+ return r;
+ }
+
+ private:
+ std::mutex mMutex;
+ std::condition_variable mNotifyThrottling;
+ bool mInvoke = false;
+};
+
+// The main test class for THERMAL HIDL HAL.
+class ThermalAidlTest : public testing::TestWithParam<std::string> {
+ public:
+ void SetUp() override {
+ AIBinder* binder = AServiceManager_waitForService(GetParam().c_str());
+ ASSERT_NE(binder, nullptr);
+ mThermal = IThermal::fromBinder(ndk::SpAIBinder(binder));
+
+ mThermalCallback = ndk::SharedRefBase::make<ThermalCallback>();
+ ASSERT_NE(mThermalCallback, nullptr);
+ auto ret = mThermal->registerThermalChangedCallback(mThermalCallback);
+ ASSERT_TRUE(ret.isOk());
+ // Expect to fail if register again
+ ret = mThermal->registerThermalChangedCallback(mThermalCallback);
+ ASSERT_FALSE(ret.isOk());
+ ASSERT_TRUE(ret.getStatus() == STATUS_INVALID_OPERATION);
+ }
+
+ void TearDown() override {
+ auto ret = mThermal->unregisterThermalChangedCallback(mThermalCallback);
+ ASSERT_TRUE(ret.isOk());
+ // Expect to fail if unregister again
+ ret = mThermal->unregisterThermalChangedCallback(mThermalCallback);
+ ASSERT_FALSE(ret.isOk());
+ ASSERT_TRUE(ret.getStatus() == STATUS_INVALID_OPERATION);
+ }
+
+ protected:
+ std::shared_ptr<IThermal> mThermal;
+ std::shared_ptr<ThermalCallback> mThermalCallback;
+};
+
+// Test ThermalChangedCallback::notifyThrottling().
+// This just calls into and back from our local ThermalChangedCallback impl.
+TEST_P(ThermalAidlTest, NotifyThrottlingTest) {
+ std::shared_ptr<ThermalCallback> thermalCallback = ndk::SharedRefBase::make<ThermalCallback>();
+ auto ret = thermalCallback->notifyThrottling(kThrottleTemp);
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_TRUE(thermalCallback->waitForCallback(200ms));
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ThermalAidlTest);
+INSTANTIATE_TEST_SUITE_P(
+ Thermal, ThermalAidlTest,
+ testing::ValuesIn(::android::getAidlHalInstanceNames(IThermal::descriptor)),
+ ::android::PrintInstanceNameToString);
+
+} // namespace
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ ABinderProcess_setThreadPoolMaxThreadCount(1);
+ ABinderProcess_startThreadPool();
+ return RUN_ALL_TESTS();
+}
+
+} // namespace aidl::android::hardware::thermal
diff --git a/tv/cec/aidl/Android.bp b/tv/cec/aidl/Android.bp
new file mode 100644
index 0000000..0b0e7cf
--- /dev/null
+++ b/tv/cec/aidl/Android.bp
@@ -0,0 +1,29 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+aidl_interface {
+ name: "android.hardware.tv.cec",
+ vendor_available: true,
+ srcs: ["android/hardware/tv/cec/*.aidl"],
+ stability: "vintf",
+ backend: {
+ java: {
+ sdk_version: "module_current",
+ },
+ },
+}
diff --git a/tv/cec/aidl/OWNERS b/tv/cec/aidl/OWNERS
new file mode 100644
index 0000000..d9c6783
--- /dev/null
+++ b/tv/cec/aidl/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 826094
+include platform/frameworks/base:/core/java/android/hardware/hdmi/OWNERS
\ No newline at end of file
diff --git a/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/AbortReason.aidl b/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/AbortReason.aidl
new file mode 100644
index 0000000..7377d81
--- /dev/null
+++ b/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/AbortReason.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.tv.cec;
+@Backing(type="int") @VintfStability
+enum AbortReason {
+ UNRECOGNIZED_MODE = 0,
+ NOT_IN_CORRECT_MODE = 1,
+ CANNOT_PROVIDE_SOURCE = 2,
+ INVALID_OPERAND = 3,
+ REFUSED = 4,
+ UNABLE_TO_DETERMINE = 5,
+}
diff --git a/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/CecDeviceType.aidl b/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/CecDeviceType.aidl
new file mode 100644
index 0000000..4d991cd
--- /dev/null
+++ b/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/CecDeviceType.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.tv.cec;
+@Backing(type="byte") @VintfStability
+enum CecDeviceType {
+ INACTIVE = -1,
+ TV = 0,
+ RECORDER = 1,
+ TUNER = 3,
+ PLAYBACK = 4,
+ AUDIO_SYSTEM = 5,
+}
diff --git a/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/CecLogicalAddress.aidl b/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/CecLogicalAddress.aidl
new file mode 100644
index 0000000..a36935b
--- /dev/null
+++ b/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/CecLogicalAddress.aidl
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.tv.cec;
+@Backing(type="byte") @VintfStability
+enum CecLogicalAddress {
+ TV = 0,
+ RECORDER_1 = 1,
+ RECORDER_2 = 2,
+ TUNER_1 = 3,
+ PLAYBACK_1 = 4,
+ AUDIO_SYSTEM = 5,
+ TUNER_2 = 6,
+ TUNER_3 = 7,
+ PLAYBACK_2 = 8,
+ RECORDER_3 = 9,
+ TUNER_4 = 10,
+ PLAYBACK_3 = 11,
+ BACKUP_1 = 12,
+ BACKUP_2 = 13,
+ FREE_USE = 14,
+ BROADCAST = 15,
+ UNREGISTERED = 15,
+}
diff --git a/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/CecMessage.aidl b/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/CecMessage.aidl
new file mode 100644
index 0000000..5ce5ce8
--- /dev/null
+++ b/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/CecMessage.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.tv.cec;
+@VintfStability
+parcelable CecMessage {
+ android.hardware.tv.cec.CecLogicalAddress initiator;
+ android.hardware.tv.cec.CecLogicalAddress destination;
+ byte[] body;
+ const int MAX_MESSAGE_BODY_LENGTH = 15;
+}
diff --git a/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/CecMessageType.aidl b/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/CecMessageType.aidl
new file mode 100644
index 0000000..61ebb94
--- /dev/null
+++ b/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/CecMessageType.aidl
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.tv.cec;
+@Backing(type="int") @VintfStability
+enum CecMessageType {
+ FEATURE_ABORT = 0,
+ IMAGE_VIEW_ON = 4,
+ TUNER_STEP_INCREMENT = 5,
+ TUNER_STEP_DECREMENT = 6,
+ TUNER_DEVICE_STATUS = 7,
+ GIVE_TUNER_DEVICE_STATUS = 8,
+ RECORD_ON = 9,
+ RECORD_STATUS = 10,
+ RECORD_OFF = 11,
+ TEXT_VIEW_ON = 13,
+ RECORD_TV_SCREEN = 15,
+ GIVE_DECK_STATUS = 26,
+ DECK_STATUS = 27,
+ SET_MENU_LANGUAGE = 50,
+ CLEAR_ANALOG_TIMER = 51,
+ SET_ANALOG_TIMER = 52,
+ TIMER_STATUS = 53,
+ STANDBY = 54,
+ PLAY = 65,
+ DECK_CONTROL = 66,
+ TIMER_CLEARED_STATUS = 67,
+ USER_CONTROL_PRESSED = 68,
+ USER_CONTROL_RELEASED = 69,
+ GIVE_OSD_NAME = 70,
+ SET_OSD_NAME = 71,
+ SET_OSD_STRING = 100,
+ SET_TIMER_PROGRAM_TITLE = 103,
+ SYSTEM_AUDIO_MODE_REQUEST = 112,
+ GIVE_AUDIO_STATUS = 113,
+ SET_SYSTEM_AUDIO_MODE = 114,
+ REPORT_AUDIO_STATUS = 122,
+ GIVE_SYSTEM_AUDIO_MODE_STATUS = 125,
+ SYSTEM_AUDIO_MODE_STATUS = 126,
+ ROUTING_CHANGE = 128,
+ ROUTING_INFORMATION = 129,
+ ACTIVE_SOURCE = 130,
+ GIVE_PHYSICAL_ADDRESS = 131,
+ REPORT_PHYSICAL_ADDRESS = 132,
+ REQUEST_ACTIVE_SOURCE = 133,
+ SET_STREAM_PATH = 134,
+ DEVICE_VENDOR_ID = 135,
+ VENDOR_COMMAND = 137,
+ VENDOR_REMOTE_BUTTON_DOWN = 138,
+ VENDOR_REMOTE_BUTTON_UP = 139,
+ GIVE_DEVICE_VENDOR_ID = 140,
+ MENU_REQUEST = 141,
+ MENU_STATUS = 142,
+ GIVE_DEVICE_POWER_STATUS = 143,
+ REPORT_POWER_STATUS = 144,
+ GET_MENU_LANGUAGE = 145,
+ SELECT_ANALOG_SERVICE = 146,
+ SELECT_DIGITAL_SERVICE = 147,
+ SET_DIGITAL_TIMER = 151,
+ CLEAR_DIGITAL_TIMER = 153,
+ SET_AUDIO_RATE = 154,
+ INACTIVE_SOURCE = 157,
+ CEC_VERSION = 158,
+ GET_CEC_VERSION = 159,
+ VENDOR_COMMAND_WITH_ID = 160,
+ CLEAR_EXTERNAL_TIMER = 161,
+ SET_EXTERNAL_TIMER = 162,
+ REPORT_SHORT_AUDIO_DESCRIPTOR = 163,
+ REQUEST_SHORT_AUDIO_DESCRIPTOR = 164,
+ INITIATE_ARC = 192,
+ REPORT_ARC_INITIATED = 193,
+ REPORT_ARC_TERMINATED = 194,
+ REQUEST_ARC_INITIATION = 195,
+ REQUEST_ARC_TERMINATION = 196,
+ TERMINATE_ARC = 197,
+ ABORT = 255,
+ GIVE_FEATURES = 165,
+ REPORT_FEATURES = 166,
+ REQUEST_CURRENT_LATENCY = 167,
+ REPORT_CURRENT_LATENCY = 168,
+}
diff --git a/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/IHdmiCec.aidl b/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/IHdmiCec.aidl
new file mode 100644
index 0000000..cf8425e
--- /dev/null
+++ b/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/IHdmiCec.aidl
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.tv.cec;
+@VintfStability
+interface IHdmiCec {
+ android.hardware.tv.cec.Result addLogicalAddress(in android.hardware.tv.cec.CecLogicalAddress addr);
+ void clearLogicalAddress();
+ void enableAudioReturnChannel(in int portId, in boolean enable);
+ int getCecVersion();
+ int getPhysicalAddress();
+ int getVendorId();
+ android.hardware.tv.cec.SendMessageResult sendMessage(in android.hardware.tv.cec.CecMessage message);
+ void setCallback(in android.hardware.tv.cec.IHdmiCecCallback callback);
+ void setLanguage(in String language);
+ void enableWakeupByOtp(in boolean value);
+ void enableCec(in boolean value);
+ void enableSystemCecControl(in boolean value);
+}
diff --git a/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/IHdmiCecCallback.aidl b/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/IHdmiCecCallback.aidl
new file mode 100644
index 0000000..1918765
--- /dev/null
+++ b/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/IHdmiCecCallback.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.tv.cec;
+@VintfStability
+interface IHdmiCecCallback {
+ oneway void onCecMessage(in android.hardware.tv.cec.CecMessage message);
+}
diff --git a/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/Result.aidl b/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/Result.aidl
new file mode 100644
index 0000000..a5ba276
--- /dev/null
+++ b/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/Result.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.tv.cec;
+@Backing(type="byte") @VintfStability
+enum Result {
+ SUCCESS = 0,
+ FAILURE_UNKNOWN = 1,
+ FAILURE_INVALID_ARGS = 2,
+ FAILURE_INVALID_STATE = 3,
+ FAILURE_NOT_SUPPORTED = 4,
+ FAILURE_BUSY = 5,
+}
diff --git a/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/SendMessageResult.aidl b/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/SendMessageResult.aidl
new file mode 100644
index 0000000..58206c8
--- /dev/null
+++ b/tv/cec/aidl/aidl_api/android.hardware.tv.cec/current/android/hardware/tv/cec/SendMessageResult.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.tv.cec;
+@Backing(type="byte") @VintfStability
+enum SendMessageResult {
+ SUCCESS = 0,
+ NACK = 1,
+ BUSY = 2,
+ FAIL = 3,
+}
diff --git a/tv/cec/aidl/android/hardware/tv/cec/AbortReason.aidl b/tv/cec/aidl/android/hardware/tv/cec/AbortReason.aidl
new file mode 100644
index 0000000..3ae23ec
--- /dev/null
+++ b/tv/cec/aidl/android/hardware/tv/cec/AbortReason.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tv.cec;
+
+/**
+ * Operand description [Abort Reason]
+ */
+@VintfStability
+@Backing(type="int")
+enum AbortReason {
+ UNRECOGNIZED_MODE = 0,
+ NOT_IN_CORRECT_MODE = 1,
+ CANNOT_PROVIDE_SOURCE = 2,
+ INVALID_OPERAND = 3,
+ REFUSED = 4,
+ UNABLE_TO_DETERMINE = 5,
+}
diff --git a/tv/cec/aidl/android/hardware/tv/cec/CecDeviceType.aidl b/tv/cec/aidl/android/hardware/tv/cec/CecDeviceType.aidl
new file mode 100644
index 0000000..16dfbec
--- /dev/null
+++ b/tv/cec/aidl/android/hardware/tv/cec/CecDeviceType.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tv.cec;
+
+@VintfStability
+@Backing(type="byte")
+enum CecDeviceType {
+ INACTIVE = -1,
+ TV = 0,
+ RECORDER = 1,
+ TUNER = 3,
+ PLAYBACK = 4,
+ AUDIO_SYSTEM = 5,
+}
diff --git a/tv/cec/aidl/android/hardware/tv/cec/CecLogicalAddress.aidl b/tv/cec/aidl/android/hardware/tv/cec/CecLogicalAddress.aidl
new file mode 100644
index 0000000..fbf5328
--- /dev/null
+++ b/tv/cec/aidl/android/hardware/tv/cec/CecLogicalAddress.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tv.cec;
+
+@VintfStability
+@Backing(type="byte")
+enum CecLogicalAddress {
+ TV = 0,
+ RECORDER_1 = 1,
+ RECORDER_2 = 2,
+ TUNER_1 = 3,
+ PLAYBACK_1 = 4,
+ AUDIO_SYSTEM = 5,
+ TUNER_2 = 6,
+ TUNER_3 = 7,
+ PLAYBACK_2 = 8,
+ RECORDER_3 = 9,
+ TUNER_4 = 10,
+ PLAYBACK_3 = 11,
+ BACKUP_1 = 12,
+ BACKUP_2 = 13,
+ FREE_USE = 14,
+ BROADCAST = 15,
+ UNREGISTERED = 15,
+}
diff --git a/tv/cec/aidl/android/hardware/tv/cec/CecMessage.aidl b/tv/cec/aidl/android/hardware/tv/cec/CecMessage.aidl
new file mode 100644
index 0000000..b126045
--- /dev/null
+++ b/tv/cec/aidl/android/hardware/tv/cec/CecMessage.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tv.cec;
+
+import android.hardware.tv.cec.CecLogicalAddress;
+
+@VintfStability
+parcelable CecMessage {
+ /**
+ * Maximum length of the message body
+ */
+ const int MAX_MESSAGE_BODY_LENGTH = 15;
+ /**
+ * logical address of the initiator
+ */
+ CecLogicalAddress initiator;
+ /**
+ * logical address of destination
+ */
+ CecLogicalAddress destination;
+ /**
+ * The maximum size of body is 15 (MAX_MESSAGE_BODY_LENGTH) as specified in
+ * the section 6 of the CEC Spec 1.4b. Overflowed data must be ignored.
+ */
+ byte[] body;
+}
diff --git a/tv/cec/aidl/android/hardware/tv/cec/CecMessageType.aidl b/tv/cec/aidl/android/hardware/tv/cec/CecMessageType.aidl
new file mode 100644
index 0000000..b544a91
--- /dev/null
+++ b/tv/cec/aidl/android/hardware/tv/cec/CecMessageType.aidl
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tv.cec;
+
+@VintfStability
+@Backing(type="int")
+enum CecMessageType {
+ FEATURE_ABORT = 0x00,
+ IMAGE_VIEW_ON = 0x04,
+ TUNER_STEP_INCREMENT = 0x05,
+ TUNER_STEP_DECREMENT = 0x06,
+ TUNER_DEVICE_STATUS = 0x07,
+ GIVE_TUNER_DEVICE_STATUS = 0x08,
+ RECORD_ON = 0x09,
+ RECORD_STATUS = 0x0A,
+ RECORD_OFF = 0x0B,
+ TEXT_VIEW_ON = 0x0D,
+ RECORD_TV_SCREEN = 0x0F,
+ GIVE_DECK_STATUS = 0x1A,
+ DECK_STATUS = 0x1B,
+ SET_MENU_LANGUAGE = 0x32,
+ CLEAR_ANALOG_TIMER = 0x33,
+ SET_ANALOG_TIMER = 0x34,
+ TIMER_STATUS = 0x35,
+ STANDBY = 0x36,
+ PLAY = 0x41,
+ DECK_CONTROL = 0x42,
+ TIMER_CLEARED_STATUS = 0x43,
+ USER_CONTROL_PRESSED = 0x44,
+ USER_CONTROL_RELEASED = 0x45,
+ GIVE_OSD_NAME = 0x46,
+ SET_OSD_NAME = 0x47,
+ SET_OSD_STRING = 0x64,
+ SET_TIMER_PROGRAM_TITLE = 0x67,
+ SYSTEM_AUDIO_MODE_REQUEST = 0x70,
+ GIVE_AUDIO_STATUS = 0x71,
+ SET_SYSTEM_AUDIO_MODE = 0x72,
+ REPORT_AUDIO_STATUS = 0x7A,
+ GIVE_SYSTEM_AUDIO_MODE_STATUS = 0x7D,
+ SYSTEM_AUDIO_MODE_STATUS = 0x7E,
+ ROUTING_CHANGE = 0x80,
+ ROUTING_INFORMATION = 0x81,
+ ACTIVE_SOURCE = 0x82,
+ GIVE_PHYSICAL_ADDRESS = 0x83,
+ REPORT_PHYSICAL_ADDRESS = 0x84,
+ REQUEST_ACTIVE_SOURCE = 0x85,
+ SET_STREAM_PATH = 0x86,
+ DEVICE_VENDOR_ID = 0x87,
+ VENDOR_COMMAND = 0x89,
+ VENDOR_REMOTE_BUTTON_DOWN = 0x8A,
+ VENDOR_REMOTE_BUTTON_UP = 0x8B,
+ GIVE_DEVICE_VENDOR_ID = 0x8C,
+ MENU_REQUEST = 0x8D,
+ MENU_STATUS = 0x8E,
+ GIVE_DEVICE_POWER_STATUS = 0x8F,
+ REPORT_POWER_STATUS = 0x90,
+ GET_MENU_LANGUAGE = 0x91,
+ SELECT_ANALOG_SERVICE = 0x92,
+ SELECT_DIGITAL_SERVICE = 0x93,
+ SET_DIGITAL_TIMER = 0x97,
+ CLEAR_DIGITAL_TIMER = 0x99,
+ SET_AUDIO_RATE = 0x9A,
+ INACTIVE_SOURCE = 0x9D,
+ CEC_VERSION = 0x9E,
+ GET_CEC_VERSION = 0x9F,
+ VENDOR_COMMAND_WITH_ID = 0xA0,
+ CLEAR_EXTERNAL_TIMER = 0xA1,
+ SET_EXTERNAL_TIMER = 0xA2,
+ REPORT_SHORT_AUDIO_DESCRIPTOR = 0xA3,
+ REQUEST_SHORT_AUDIO_DESCRIPTOR = 0xA4,
+ INITIATE_ARC = 0xC0,
+ REPORT_ARC_INITIATED = 0xC1,
+ REPORT_ARC_TERMINATED = 0xC2,
+ REQUEST_ARC_INITIATION = 0xC3,
+ REQUEST_ARC_TERMINATION = 0xC4,
+ TERMINATE_ARC = 0xC5,
+ ABORT = 0xFF,
+ GIVE_FEATURES = 0xA5,
+ REPORT_FEATURES = 0xA6,
+ REQUEST_CURRENT_LATENCY = 0xA7,
+ REPORT_CURRENT_LATENCY = 0xA8,
+}
diff --git a/tv/cec/aidl/android/hardware/tv/cec/IHdmiCec.aidl b/tv/cec/aidl/android/hardware/tv/cec/IHdmiCec.aidl
new file mode 100644
index 0000000..dbf7139
--- /dev/null
+++ b/tv/cec/aidl/android/hardware/tv/cec/IHdmiCec.aidl
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tv.cec;
+
+import android.hardware.tv.cec.CecLogicalAddress;
+import android.hardware.tv.cec.CecMessage;
+import android.hardware.tv.cec.IHdmiCecCallback;
+import android.hardware.tv.cec.Result;
+import android.hardware.tv.cec.SendMessageResult;
+
+/**
+ * HDMI-CEC HAL interface definition.
+ */
+@VintfStability
+interface IHdmiCec {
+ /**
+ * Passes the logical address that must be used in this system.
+ *
+ * HAL must use it to configure the hardware so that the CEC commands
+ * addressed the given logical address can be filtered in. This method must
+ * be able to be called as many times as necessary in order to support
+ * multiple logical devices.
+ *
+ * @param addr Logical address that must be used in this system. It must be
+ * in the range of valid logical addresses for the call to succeed.
+ * @return Result status of the operation. SUCCESS if successful,
+ * FAILURE_INVALID_ARGS if the given logical address is invalid,
+ * FAILURE_BUSY if device or resource is busy
+ */
+ Result addLogicalAddress(in CecLogicalAddress addr);
+
+ /**
+ * Clears all the logical addresses.
+ *
+ * It is used when the system doesn't need to process CEC command any more,
+ * hence to tell HAL to stop receiving commands from the CEC bus, and change
+ * the state back to the beginning.
+ */
+ void clearLogicalAddress();
+
+ /**
+ * Configures ARC circuit in the hardware logic to start or stop the
+ * feature.
+ *
+ * @param portId Port id to be configured.
+ * @param enable Flag must be either true to start the feature or false to
+ * stop it.
+ */
+ void enableAudioReturnChannel(in int portId, in boolean enable);
+
+ /**
+ * Returns the CEC version supported by underlying hardware.
+ *
+ * @return the CEC version supported by underlying hardware.
+ */
+ int getCecVersion();
+
+ /**
+ * Gets the CEC physical address.
+ *
+ * The physical address depends on the topology of the network formed by
+ * connected HDMI devices. It is therefore likely to change if the cable is
+ * plugged off and on again. It is advised to call getPhysicalAddress to get
+ * the updated address when hot plug event takes place.
+ *
+ * @param out addr Physical address of this device.
+ */
+ int getPhysicalAddress();
+
+ /**
+ * Gets the identifier of the vendor.
+ *
+ * @return Identifier of the vendor that is the 24-bit unique
+ * company ID obtained from the IEEE Registration Authority
+ * Committee (RAC). The upper 8 bits must be 0.
+ */
+ int getVendorId();
+
+ /**
+ * Transmits HDMI-CEC message to other HDMI device.
+ *
+ * The method must be designed to return in a certain amount of time and not
+ * hanging forever which may happen if CEC signal line is pulled low for
+ * some reason.
+ *
+ * It must try retransmission at least once as specified in the section '7.1
+ * Frame Re-transmissions' of the CEC Spec 1.4b.
+ *
+ * @param message CEC message to be sent to other HDMI device.
+ * @return Result status of the operation. SUCCESS if successful,
+ * NACK if the sent message is not acknowledged,
+ * BUSY if the CEC bus is busy,
+ * FAIL if the message could not be sent.
+ */
+ SendMessageResult sendMessage(in CecMessage message);
+
+ /**
+ * Sets a callback that HDMI-CEC HAL must later use for incoming CEC
+ * messages.
+ *
+ * @param callback Callback object to pass hdmi events to the system. The
+ * previously registered callback must be replaced with this one.
+ * setCallback(null) should deregister the callback.
+ */
+ void setCallback(in IHdmiCecCallback callback);
+
+ /**
+ * Passes the updated language information of Android system. Contains
+ * three-letter code as defined in ISO/FDIS 639-2. Must be used for HAL to
+ * respond to <Get Menu Language> while in standby mode.
+ *
+ * @param language Three-letter code defined in ISO/FDIS 639-2. Must be
+ * lowercase letters. (e.g., eng for English)
+ */
+ void setLanguage(in String language);
+
+ /**
+ * Determines whether a TV panel device in standby mode should wake up when
+ * it receives an OTP (One Touch Play) from a source device.
+ *
+ * @param value If true, the TV device will wake up when OTP is received
+ * and if false, the TV device will not wake up for an OTP.
+ */
+ void enableWakeupByOtp(in boolean value);
+
+ /**
+ * Switch to enable or disable CEC on the device.
+ *
+ * @param value If true, the device will have all CEC functionalities
+ * and if false, the device will not perform any CEC functions.
+ */
+ void enableCec(in boolean value);
+
+ /**
+ * Determines which module processes CEC messages - the Android framework or
+ * the HAL.
+ *
+ * @param value If true, the Android framework will actively process CEC
+ * messages and if false, only the HAL will process the CEC messages.
+ */
+ void enableSystemCecControl(in boolean value);
+}
diff --git a/tv/cec/aidl/android/hardware/tv/cec/IHdmiCecCallback.aidl b/tv/cec/aidl/android/hardware/tv/cec/IHdmiCecCallback.aidl
new file mode 100644
index 0000000..4934a64
--- /dev/null
+++ b/tv/cec/aidl/android/hardware/tv/cec/IHdmiCecCallback.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tv.cec;
+
+import android.hardware.tv.cec.CecMessage;
+
+/**
+ * Callbacks from the HAL implementation to notify the system of new events.
+ */
+@VintfStability
+oneway interface IHdmiCecCallback {
+ /**
+ * The callback function that must be called by HAL implementation to notify
+ * the system of new CEC message arrival.
+ */
+ void onCecMessage(in CecMessage message);
+}
diff --git a/tv/cec/aidl/android/hardware/tv/cec/Result.aidl b/tv/cec/aidl/android/hardware/tv/cec/Result.aidl
new file mode 100644
index 0000000..3184c46
--- /dev/null
+++ b/tv/cec/aidl/android/hardware/tv/cec/Result.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tv.cec;
+
+@VintfStability
+@Backing(type="byte")
+enum Result {
+ SUCCESS = 0,
+ FAILURE_UNKNOWN = 1,
+ FAILURE_INVALID_ARGS = 2,
+ FAILURE_INVALID_STATE = 3,
+ FAILURE_NOT_SUPPORTED = 4,
+ FAILURE_BUSY = 5,
+}
diff --git a/tv/cec/aidl/android/hardware/tv/cec/SendMessageResult.aidl b/tv/cec/aidl/android/hardware/tv/cec/SendMessageResult.aidl
new file mode 100644
index 0000000..8cb98bc
--- /dev/null
+++ b/tv/cec/aidl/android/hardware/tv/cec/SendMessageResult.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tv.cec;
+
+/**
+ * error code used for send_message.
+ */
+@VintfStability
+@Backing(type="byte")
+enum SendMessageResult {
+ SUCCESS = 0,
+ NACK = 1,
+ BUSY = 2,
+ FAIL = 3,
+}
diff --git a/tv/cec/aidl/default/Android.bp b/tv/cec/aidl/default/Android.bp
new file mode 100644
index 0000000..5479601
--- /dev/null
+++ b/tv/cec/aidl/default/Android.bp
@@ -0,0 +1,58 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_binary {
+ name: "android.hardware.tv.cec-service",
+ vintf_fragments: ["android.hardware.tv.cec-service.xml"],
+ relative_install_path: "hw",
+ vendor: true,
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ ],
+ init_rc: ["android.hardware.tv.cec-service.rc"],
+ srcs: [
+ "serviceMock.cpp",
+ "HdmiCecMock.cpp",
+ ],
+ shared_libs: [
+ "libbinder_ndk",
+ "liblog",
+ "libbase",
+ "libutils",
+ "libhardware",
+ "libhidlbase",
+ "android.hardware.tv.cec-V1-ndk",
+ ],
+}
+
+cc_fuzz {
+ name: "android.hardware.tv.cec-service_fuzzer",
+ defaults: ["service_fuzzer_defaults"],
+ static_libs: [
+ "android.hardware.tv.cec-V1-ndk",
+ "liblog",
+ ],
+ srcs: [
+ "fuzzer.cpp",
+ "HdmiCecMock.cpp",
+ ],
+ fuzz_config: {
+ componentid: 826094,
+ },
+}
diff --git a/tv/cec/aidl/default/HdmiCecMock.cpp b/tv/cec/aidl/default/HdmiCecMock.cpp
new file mode 100644
index 0000000..d8d655b
--- /dev/null
+++ b/tv/cec/aidl/default/HdmiCecMock.cpp
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.tv.cec"
+#include <android-base/logging.h>
+#include <fcntl.h>
+#include <utils/Log.h>
+
+#include <hardware/hardware.h>
+#include <hardware/hdmi_cec.h>
+#include "HdmiCecMock.h"
+
+using ndk::ScopedAStatus;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace cec {
+namespace implementation {
+
+void HdmiCecMock::serviceDied(void* cookie) {
+ ALOGE("HdmiCecMock died");
+ auto hdmiCecMock = static_cast<HdmiCecMock*>(cookie);
+ hdmiCecMock->mCecThreadRun = false;
+}
+
+ScopedAStatus HdmiCecMock::addLogicalAddress(CecLogicalAddress addr, Result* _aidl_return) {
+ // Have a list to maintain logical addresses
+ mLogicalAddresses.push_back(addr);
+ *_aidl_return = Result::SUCCESS;
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus HdmiCecMock::clearLogicalAddress() {
+ // Remove logical address from the list
+ mLogicalAddresses = {};
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus HdmiCecMock::enableAudioReturnChannel(int32_t portId __unused, bool enable __unused) {
+ // Maintain ARC status
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus HdmiCecMock::getCecVersion(int32_t* _aidl_return) {
+ // Maintain a cec version and return it
+ *_aidl_return = mCecVersion;
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus HdmiCecMock::getPhysicalAddress(int32_t* _aidl_return) {
+ // Maintain a physical address and return it
+ // Default 0xFFFF, update on hotplug event
+ *_aidl_return = mPhysicalAddress;
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus HdmiCecMock::getVendorId(int32_t* _aidl_return) {
+ *_aidl_return = mCecVendorId;
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus HdmiCecMock::sendMessage(const CecMessage& message, SendMessageResult* _aidl_return) {
+ if (message.body.size() == 0) {
+ *_aidl_return = SendMessageResult::NACK;
+ } else {
+ sendMessageToFifo(message);
+ *_aidl_return = SendMessageResult::SUCCESS;
+ }
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus HdmiCecMock::setCallback(const std::shared_ptr<IHdmiCecCallback>& callback) {
+ // If callback is null, mCallback is also set to null so we do not call the old callback.
+ mCallback = callback;
+
+ if (callback != nullptr) {
+ AIBinder_linkToDeath(this->asBinder().get(), mDeathRecipient.get(), 0 /* cookie */);
+
+ mInputFile = open(CEC_MSG_IN_FIFO, O_RDWR | O_CLOEXEC);
+ mOutputFile = open(CEC_MSG_OUT_FIFO, O_RDWR | O_CLOEXEC);
+ pthread_create(&mThreadId, NULL, __threadLoop, this);
+ pthread_setname_np(mThreadId, "hdmi_cec_loop");
+ }
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus HdmiCecMock::setLanguage(const std::string& language) {
+ if (language.size() != 3) {
+ LOG(ERROR) << "Wrong language code: expected 3 letters, but it was " << language.size()
+ << ".";
+ return ScopedAStatus::ok();
+ }
+ // TODO Validate if language is a valid language code
+ const char* languageStr = language.c_str();
+ int convertedLanguage = ((languageStr[0] & 0xFF) << 16) | ((languageStr[1] & 0xFF) << 8) |
+ (languageStr[2] & 0xFF);
+ mOptionLanguage = convertedLanguage;
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus HdmiCecMock::enableWakeupByOtp(bool value) {
+ mOptionWakeUp = value;
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus HdmiCecMock::enableCec(bool value) {
+ mOptionEnableCec = value;
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus HdmiCecMock::enableSystemCecControl(bool value) {
+ mOptionSystemCecControl = value;
+ return ScopedAStatus::ok();
+}
+
+void* HdmiCecMock::__threadLoop(void* user) {
+ HdmiCecMock* const self = static_cast<HdmiCecMock*>(user);
+ self->threadLoop();
+ return 0;
+}
+
+int HdmiCecMock::readMessageFromFifo(unsigned char* buf, int msgCount) {
+ if (msgCount <= 0 || !buf) {
+ return 0;
+ }
+
+ int ret = -1;
+ // Maybe blocked at driver
+ ret = read(mInputFile, buf, msgCount);
+ if (ret < 0) {
+ ALOGE("[halimp_aidl] read :%s failed, ret:%d\n", CEC_MSG_IN_FIFO, ret);
+ return -1;
+ }
+
+ return ret;
+}
+
+int HdmiCecMock::sendMessageToFifo(const CecMessage& message) {
+ unsigned char msgBuf[CEC_MESSAGE_BODY_MAX_LENGTH + 1] = {0};
+ int ret = -1;
+
+ msgBuf[0] = ((static_cast<uint8_t>(message.initiator) & 0xf) << 4) |
+ (static_cast<uint8_t>(message.destination) & 0xf);
+
+ size_t length = std::min(static_cast<size_t>(message.body.size()),
+ static_cast<size_t>(CEC_MESSAGE_BODY_MAX_LENGTH));
+ for (size_t i = 0; i < length; ++i) {
+ msgBuf[i + 1] = static_cast<unsigned char>(message.body[i]);
+ }
+
+ // Open the output pipe for writing outgoing cec message
+ mOutputFile = open(CEC_MSG_OUT_FIFO, O_WRONLY | O_CLOEXEC);
+ if (mOutputFile < 0) {
+ ALOGD("[halimp_aidl] file open failed for writing");
+ return -1;
+ }
+
+ // Write message into the output pipe
+ ret = write(mOutputFile, msgBuf, length + 1);
+ close(mOutputFile);
+ if (ret < 0) {
+ ALOGE("[halimp_aidl] write :%s failed, ret:%d\n", CEC_MSG_OUT_FIFO, ret);
+ return -1;
+ }
+ return ret;
+}
+
+void HdmiCecMock::printCecMsgBuf(const char* msg_buf, int len) {
+ int i, size = 0;
+ const int bufSize = CEC_MESSAGE_BODY_MAX_LENGTH * 3;
+ // Use 2 characters for each byte in the message plus 1 space
+ char buf[bufSize] = {0};
+
+ // Messages longer than max length will be truncated.
+ for (i = 0; i < len && size < bufSize; i++) {
+ size += sprintf(buf + size, " %02x", msg_buf[i]);
+ }
+ ALOGD("[halimp_aidl] %s, msg:%.*s", __FUNCTION__, size, buf);
+}
+
+void HdmiCecMock::handleCecMessage(unsigned char* msgBuf, int msgSize) {
+ CecMessage message;
+ size_t length = std::min(static_cast<size_t>(msgSize - 1),
+ static_cast<size_t>(CEC_MESSAGE_BODY_MAX_LENGTH));
+ message.body.resize(length);
+
+ for (size_t i = 0; i < length; ++i) {
+ message.body[i] = static_cast<uint8_t>(msgBuf[i + 1]);
+ ALOGD("[halimp_aidl] msg body %x", message.body[i]);
+ }
+
+ message.initiator = static_cast<CecLogicalAddress>((msgBuf[0] >> 4) & 0xf);
+ ALOGD("[halimp_aidl] msg init %hhd", message.initiator);
+ message.destination = static_cast<CecLogicalAddress>((msgBuf[0] >> 0) & 0xf);
+ ALOGD("[halimp_aidl] msg dest %hhd", message.destination);
+
+ if (mCallback != nullptr) {
+ mCallback->onCecMessage(message);
+ }
+}
+
+void HdmiCecMock::threadLoop() {
+ ALOGD("[halimp_aidl] threadLoop start.");
+ unsigned char msgBuf[CEC_MESSAGE_BODY_MAX_LENGTH];
+ int r = -1;
+
+ // Open the input pipe
+ while (mInputFile < 0) {
+ usleep(1000 * 1000);
+ mInputFile = open(CEC_MSG_IN_FIFO, O_RDONLY | O_CLOEXEC);
+ }
+ ALOGD("[halimp_aidl] file open ok, fd = %d.", mInputFile);
+
+ while (mCecThreadRun) {
+ if (!mOptionSystemCecControl) {
+ usleep(1000 * 1000);
+ continue;
+ }
+
+ memset(msgBuf, 0, sizeof(msgBuf));
+ // Try to get a message from dev.
+ // echo -n -e '\x04\x83' >> /dev/cec
+ r = readMessageFromFifo(msgBuf, CEC_MESSAGE_BODY_MAX_LENGTH);
+ if (r <= 1) {
+ // Ignore received ping messages
+ continue;
+ }
+
+ printCecMsgBuf((const char*)msgBuf, r);
+
+ if (((msgBuf[0] >> 4) & 0xf) == 0xf) {
+ // The message is a hotplug event, handled by HDMI HAL.
+ continue;
+ }
+
+ handleCecMessage(msgBuf, r);
+ }
+
+ ALOGD("[halimp_aidl] thread end.");
+}
+
+HdmiCecMock::HdmiCecMock() {
+ ALOGE("[halimp_aidl] Opening a virtual CEC HAL for testing and virtual machine.");
+ mCallback = nullptr;
+ mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient_new(serviceDied));
+}
+
+} // namespace implementation
+} // namespace cec
+} // namespace tv
+} // namespace hardware
+} // namespace android
diff --git a/tv/cec/aidl/default/HdmiCecMock.h b/tv/cec/aidl/default/HdmiCecMock.h
new file mode 100644
index 0000000..08f4d6f
--- /dev/null
+++ b/tv/cec/aidl/default/HdmiCecMock.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/android/hardware/tv/cec/BnHdmiCec.h>
+#include <algorithm>
+#include <vector>
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace cec {
+namespace implementation {
+
+using ::aidl::android::hardware::tv::cec::BnHdmiCec;
+using ::aidl::android::hardware::tv::cec::CecLogicalAddress;
+using ::aidl::android::hardware::tv::cec::CecMessage;
+using ::aidl::android::hardware::tv::cec::IHdmiCec;
+using ::aidl::android::hardware::tv::cec::IHdmiCecCallback;
+using ::aidl::android::hardware::tv::cec::Result;
+using ::aidl::android::hardware::tv::cec::SendMessageResult;
+
+#define CEC_MSG_IN_FIFO "/dev/cec_aidl_in_pipe"
+#define CEC_MSG_OUT_FIFO "/dev/cec_aidl_out_pipe"
+
+struct HdmiCecMock : public BnHdmiCec {
+ HdmiCecMock();
+ ::ndk::ScopedAStatus addLogicalAddress(CecLogicalAddress addr, Result* _aidl_return) override;
+ ::ndk::ScopedAStatus clearLogicalAddress() override;
+ ::ndk::ScopedAStatus enableAudioReturnChannel(int32_t portId, bool enable) override;
+ ::ndk::ScopedAStatus getCecVersion(int32_t* _aidl_return) override;
+ ::ndk::ScopedAStatus getPhysicalAddress(int32_t* _aidl_return) override;
+ ::ndk::ScopedAStatus getVendorId(int32_t* _aidl_return) override;
+ ::ndk::ScopedAStatus sendMessage(const CecMessage& message,
+ SendMessageResult* _aidl_return) override;
+ ::ndk::ScopedAStatus setCallback(const std::shared_ptr<IHdmiCecCallback>& callback) override;
+ ::ndk::ScopedAStatus setLanguage(const std::string& language) override;
+ ::ndk::ScopedAStatus enableWakeupByOtp(bool value) override;
+ ::ndk::ScopedAStatus enableCec(bool value) override;
+ ::ndk::ScopedAStatus enableSystemCecControl(bool value) override;
+ void printCecMsgBuf(const char* msg_buf, int len);
+
+ private:
+ static void* __threadLoop(void* data);
+ void threadLoop();
+ int readMessageFromFifo(unsigned char* buf, int msgCount);
+ int sendMessageToFifo(const CecMessage& message);
+ void handleCecMessage(unsigned char* msgBuf, int length);
+
+ private:
+ static void serviceDied(void* cookie);
+ std::shared_ptr<IHdmiCecCallback> mCallback;
+
+ // Variables for the virtual cec hal impl
+ uint16_t mPhysicalAddress = 0xFFFF;
+ vector<CecLogicalAddress> mLogicalAddresses;
+ int32_t mCecVersion = 0x06;
+ uint32_t mCecVendorId = 0x01;
+
+ // CEC Option value
+ bool mOptionWakeUp = 0;
+ bool mOptionEnableCec = 0;
+ bool mOptionSystemCecControl = 0;
+ int mOptionLanguage;
+
+ // Testing variables
+ // Input file descriptor
+ int mInputFile;
+ // Output file descriptor
+ int mOutputFile;
+ bool mCecThreadRun = true;
+ pthread_t mThreadId = 0;
+
+ ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
+};
+} // namespace implementation
+} // namespace cec
+} // namespace tv
+} // namespace hardware
+} // namespace android
diff --git a/tv/cec/aidl/default/android.hardware.tv.cec-service.rc b/tv/cec/aidl/default/android.hardware.tv.cec-service.rc
new file mode 100644
index 0000000..c79520c
--- /dev/null
+++ b/tv/cec/aidl/default/android.hardware.tv.cec-service.rc
@@ -0,0 +1,5 @@
+service vendor.cec-default /vendor/bin/hw/android.hardware.tv.cec-service
+ interface aidl android.hardware.tv.cec.IHdmiCec/default
+ class hal
+ user system
+ group system
diff --git a/tv/cec/aidl/default/android.hardware.tv.cec-service.xml b/tv/cec/aidl/default/android.hardware.tv.cec-service.xml
new file mode 100644
index 0000000..e68450d
--- /dev/null
+++ b/tv/cec/aidl/default/android.hardware.tv.cec-service.xml
@@ -0,0 +1,10 @@
+<manifest version="1.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.tv.cec</name>
+ <version>1</version>
+ <interface>
+ <name>IHdmiCec</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/tv/cec/aidl/default/fuzzer.cpp b/tv/cec/aidl/default/fuzzer.cpp
new file mode 100644
index 0000000..9f6a9ac
--- /dev/null
+++ b/tv/cec/aidl/default/fuzzer.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <HdmiCecMock.h>
+#include <fuzzbinder/libbinder_ndk_driver.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+using android::fuzzService;
+using android::hardware::tv::cec::implementation::HdmiCecMock;
+using ndk::SharedRefBase;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ auto hdmiCecAidl = SharedRefBase::make<HdmiCecMock>();
+
+ fuzzService(hdmiCecAidl->asBinder().get(), FuzzedDataProvider(data, size));
+
+ return 0;
+}
diff --git a/tv/cec/aidl/default/serviceMock.cpp b/tv/cec/aidl/default/serviceMock.cpp
new file mode 100644
index 0000000..ab86c3f
--- /dev/null
+++ b/tv/cec/aidl/default/serviceMock.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.tv.cec-service-shim"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <hidl/HidlTransportSupport.h>
+#include <utils/Log.h>
+#include "HdmiCecMock.h"
+
+using android::hardware::tv::cec::implementation::HdmiCecMock;
+
+int main() {
+ ABinderProcess_setThreadPoolMaxThreadCount(1);
+ ABinderProcess_startThreadPool();
+
+ std::shared_ptr<HdmiCecMock> hdmiCecAidl = ndk::SharedRefBase::make<HdmiCecMock>();
+ const std::string instance = std::string() + HdmiCecMock::descriptor + "/default";
+ binder_status_t status =
+ AServiceManager_addService(hdmiCecAidl->asBinder().get(), instance.c_str());
+ CHECK_EQ(status, STATUS_OK);
+
+ ABinderProcess_joinThreadPool();
+ return 0;
+}
diff --git a/tv/cec/aidl/vts/functional/Android.bp b/tv/cec/aidl/vts/functional/Android.bp
new file mode 100644
index 0000000..37fbaf0
--- /dev/null
+++ b/tv/cec/aidl/vts/functional/Android.bp
@@ -0,0 +1,38 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_test {
+ name: "VtsHalTvCecAidlTargetTest",
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "use_libaidlvintf_gtest_helper_static",
+ ],
+ srcs: ["VtsHalTvCecAidlTargetTest.cpp"],
+ static_libs: [
+ "android.hardware.tv.cec-V1-ndk",
+ "android.hardware.tv.hdmi-V1-ndk",
+ ],
+ shared_libs: [
+ "libbinder_ndk",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+ disable_framework: true,
+}
diff --git a/tv/cec/aidl/vts/functional/VtsHalTvCecAidlTargetTest.cpp b/tv/cec/aidl/vts/functional/VtsHalTvCecAidlTargetTest.cpp
new file mode 100644
index 0000000..69c209f
--- /dev/null
+++ b/tv/cec/aidl/vts/functional/VtsHalTvCecAidlTargetTest.cpp
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "HdmiCec_hal_test"
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/tv/cec/BnHdmiCec.h>
+#include <aidl/android/hardware/tv/cec/BnHdmiCecCallback.h>
+#include <aidl/android/hardware/tv/cec/CecDeviceType.h>
+#include <aidl/android/hardware/tv/hdmi/BnHdmi.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <gtest/gtest.h>
+#include <log/log.h>
+#include <sstream>
+#include <vector>
+
+using ::aidl::android::hardware::tv::cec::BnHdmiCecCallback;
+using ::aidl::android::hardware::tv::cec::CecDeviceType;
+using ::aidl::android::hardware::tv::cec::CecLogicalAddress;
+using ::aidl::android::hardware::tv::cec::CecMessage;
+using ::aidl::android::hardware::tv::cec::IHdmiCec;
+using ::aidl::android::hardware::tv::cec::IHdmiCecCallback;
+using ::aidl::android::hardware::tv::cec::Result;
+using ::aidl::android::hardware::tv::cec::SendMessageResult;
+using ::aidl::android::hardware::tv::hdmi::HdmiPortInfo;
+using ::ndk::SpAIBinder;
+
+#define CEC_VERSION 0x05
+#define INCORRECT_VENDOR_ID 0x00
+#define TV_PHYSICAL_ADDRESS 0x0000
+
+// The main test class for TV CEC HAL.
+class HdmiCecTest : public ::testing::TestWithParam<std::string> {
+ static void serviceDied(void* /* cookie */) { ALOGE("VtsHalTvCecAidlTargetTest died"); }
+
+ public:
+ void SetUp() override {
+ hdmiCec = IHdmiCec::fromBinder(
+ SpAIBinder(AServiceManager_waitForService(GetParam().c_str())));
+ ASSERT_NE(hdmiCec, nullptr);
+ ALOGI("%s: getService() for hdmiCec is %s", __func__,
+ hdmiCec->isRemote() ? "remote" : "local");
+
+ hdmiCecCallback = ::ndk::SharedRefBase::make<CecCallback>();
+ ASSERT_NE(hdmiCecCallback, nullptr);
+ hdmiCecDeathRecipient =
+ ndk::ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient_new(&serviceDied));
+ ASSERT_EQ(AIBinder_linkToDeath(hdmiCec->asBinder().get(), hdmiCecDeathRecipient.get(), 0),
+ STATUS_OK);
+ }
+
+ std::vector<int> getDeviceTypes() {
+ std::vector<int> deviceTypes;
+ FILE* p = popen("getprop ro.hdmi.device_type", "re");
+ if (p) {
+ char* line = NULL;
+ size_t len = 0;
+ if (getline(&line, &len, p) > 0) {
+ std::istringstream stream(line);
+ std::string number{};
+ while (std::getline(stream, number, ',')) {
+ deviceTypes.push_back(stoi(number));
+ }
+ }
+ pclose(p);
+ }
+ return deviceTypes;
+ }
+
+ bool hasDeviceType(CecDeviceType type) {
+ std::vector<int> deviceTypes = getDeviceTypes();
+ return std::find(deviceTypes.begin(), deviceTypes.end(), (int)type) != deviceTypes.end();
+ }
+
+ class CecCallback : public BnHdmiCecCallback {
+ public:
+ ::ndk::ScopedAStatus onCecMessage(const CecMessage& message __unused) {
+ return ::ndk::ScopedAStatus::ok();
+ };
+ };
+
+ std::shared_ptr<IHdmiCec> hdmiCec;
+ std::shared_ptr<IHdmiCecCallback> hdmiCecCallback;
+ ::ndk::ScopedAIBinder_DeathRecipient hdmiCecDeathRecipient;
+};
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(HdmiCecTest);
+INSTANTIATE_TEST_SUITE_P(PerInstance, HdmiCecTest,
+ testing::ValuesIn(android::getAidlHalInstanceNames(IHdmiCec::descriptor)),
+ android::PrintInstanceNameToString);
+
+TEST_P(HdmiCecTest, ClearAddLogicalAddress) {
+ Result addLaResult;
+ ASSERT_TRUE(hdmiCec->clearLogicalAddress().isOk());
+ ASSERT_TRUE(hdmiCec->addLogicalAddress(CecLogicalAddress::PLAYBACK_3, &addLaResult).isOk());
+ EXPECT_EQ(addLaResult, Result::SUCCESS);
+}
+
+TEST_P(HdmiCecTest, PhysicalAddress) {
+ int32_t addr;
+ ASSERT_TRUE(hdmiCec->getPhysicalAddress(&addr).isOk());
+ if (!hasDeviceType(CecDeviceType::TV)) {
+ EXPECT_NE(addr, TV_PHYSICAL_ADDRESS);
+ }
+}
+
+TEST_P(HdmiCecTest, SendMessage) {
+ CecMessage message;
+ message.initiator = CecLogicalAddress::PLAYBACK_1;
+ message.destination = CecLogicalAddress::BROADCAST;
+ message.body.resize(1);
+ message.body[0] = 131;
+ SendMessageResult result;
+ ASSERT_TRUE(hdmiCec->sendMessage(message, &result).isOk());
+ EXPECT_EQ(result, SendMessageResult::SUCCESS);
+}
+
+TEST_P(HdmiCecTest, CecVersion) {
+ int32_t version;
+ ASSERT_TRUE(hdmiCec->getCecVersion(&version).isOk());
+ EXPECT_GE(version, CEC_VERSION);
+}
+
+TEST_P(HdmiCecTest, SetCallback) {
+ ASSERT_TRUE(hdmiCec->setCallback(::ndk::SharedRefBase::make<CecCallback>()).isOk());
+}
+
+TEST_P(HdmiCecTest, VendorId) {
+ int32_t vendorId;
+ ASSERT_TRUE(hdmiCec->getVendorId(&vendorId).isOk());
+ EXPECT_NE(vendorId, INCORRECT_VENDOR_ID);
+}
+
+TEST_P(HdmiCecTest, EnableWakeupByOtp) {
+ ASSERT_TRUE(hdmiCec->enableWakeupByOtp(false).isOk());
+ // Restore option to its default value
+ ASSERT_TRUE(hdmiCec->enableWakeupByOtp(true).isOk());
+}
+
+TEST_P(HdmiCecTest, EnableCec) {
+ ASSERT_TRUE(hdmiCec->enableCec(false).isOk());
+ // Restore option to its default value
+ ASSERT_TRUE(hdmiCec->enableCec(true).isOk());
+}
+
+TEST_P(HdmiCecTest, EnableSystemCecControl) {
+ ASSERT_TRUE(hdmiCec->enableSystemCecControl(true).isOk());
+ // Restore option to its default value
+ ASSERT_TRUE(hdmiCec->enableSystemCecControl(false).isOk());
+}
+
+TEST_P(HdmiCecTest, SetLanguage) {
+ ASSERT_TRUE(hdmiCec->setLanguage("eng").isOk());
+}
diff --git a/tv/hdmi/aidl/Android.bp b/tv/hdmi/aidl/Android.bp
new file mode 100644
index 0000000..d8c6e5f
--- /dev/null
+++ b/tv/hdmi/aidl/Android.bp
@@ -0,0 +1,29 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+aidl_interface {
+ name: "android.hardware.tv.hdmi",
+ vendor_available: true,
+ srcs: ["android/hardware/tv/hdmi/*.aidl"],
+ stability: "vintf",
+ backend: {
+ java: {
+ sdk_version: "module_current",
+ },
+ },
+}
diff --git a/tv/hdmi/aidl/OWNERS b/tv/hdmi/aidl/OWNERS
new file mode 100644
index 0000000..d9c6783
--- /dev/null
+++ b/tv/hdmi/aidl/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 826094
+include platform/frameworks/base:/core/java/android/hardware/hdmi/OWNERS
\ No newline at end of file
diff --git a/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/HdmiPortInfo.aidl b/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/HdmiPortInfo.aidl
new file mode 100644
index 0000000..25c3be1
--- /dev/null
+++ b/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/HdmiPortInfo.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.tv.hdmi;
+@VintfStability
+parcelable HdmiPortInfo {
+ android.hardware.tv.hdmi.HdmiPortType type;
+ int portId;
+ boolean cecSupported;
+ boolean arcSupported;
+ boolean eArcSupported;
+ int physicalAddress;
+}
diff --git a/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/HdmiPortType.aidl b/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/HdmiPortType.aidl
new file mode 100644
index 0000000..af5f0f7
--- /dev/null
+++ b/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/HdmiPortType.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.tv.hdmi;
+@Backing(type="byte") @VintfStability
+enum HdmiPortType {
+ INPUT = 0,
+ OUTPUT = 1,
+}
diff --git a/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/IHdmi.aidl b/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/IHdmi.aidl
new file mode 100644
index 0000000..3fc7f41
--- /dev/null
+++ b/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/IHdmi.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.tv.hdmi;
+@VintfStability
+interface IHdmi {
+ android.hardware.tv.hdmi.HdmiPortInfo[] getPortInfo();
+ boolean isConnected(in int portId);
+ void setCallback(in android.hardware.tv.hdmi.IHdmiCallback callback);
+}
diff --git a/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/IHdmiCallback.aidl b/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/IHdmiCallback.aidl
new file mode 100644
index 0000000..05fe623
--- /dev/null
+++ b/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/IHdmiCallback.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.tv.hdmi;
+@VintfStability
+interface IHdmiCallback {
+ oneway void onHotplugEvent(in boolean connected, in int portId);
+}
diff --git a/tv/hdmi/aidl/android/hardware/tv/hdmi/HdmiPortInfo.aidl b/tv/hdmi/aidl/android/hardware/tv/hdmi/HdmiPortInfo.aidl
new file mode 100644
index 0000000..2e2c858
--- /dev/null
+++ b/tv/hdmi/aidl/android/hardware/tv/hdmi/HdmiPortInfo.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tv.hdmi;
+
+import android.hardware.tv.hdmi.HdmiPortType;
+
+/**
+ * HDMI port descriptor
+ */
+@VintfStability
+parcelable HdmiPortInfo {
+ HdmiPortType type;
+ int portId; // Should start from 1 which corresponds to HDMI "port 1".
+ boolean cecSupported;
+ boolean arcSupported;
+ boolean eArcSupported;
+ // The physical address of the device connected to this port, valid range is 0x0000 to 0xFFFF
+ // (ref Sec 8.7.2 of HDMI 1.4b).
+ int physicalAddress;
+}
diff --git a/tv/hdmi/aidl/android/hardware/tv/hdmi/HdmiPortType.aidl b/tv/hdmi/aidl/android/hardware/tv/hdmi/HdmiPortType.aidl
new file mode 100644
index 0000000..59c0d42
--- /dev/null
+++ b/tv/hdmi/aidl/android/hardware/tv/hdmi/HdmiPortType.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tv.hdmi;
+
+/**
+ * HDMI port type.
+ */
+@VintfStability
+@Backing(type="byte")
+enum HdmiPortType {
+ INPUT = 0,
+ OUTPUT = 1,
+}
diff --git a/tv/hdmi/aidl/android/hardware/tv/hdmi/IHdmi.aidl b/tv/hdmi/aidl/android/hardware/tv/hdmi/IHdmi.aidl
new file mode 100644
index 0000000..5536846
--- /dev/null
+++ b/tv/hdmi/aidl/android/hardware/tv/hdmi/IHdmi.aidl
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tv.hdmi;
+
+import android.hardware.tv.hdmi.HdmiPortInfo;
+import android.hardware.tv.hdmi.IHdmiCallback;
+
+/**
+ * HDMI HAL interface definition.
+ */
+@VintfStability
+interface IHdmi {
+ /**
+ * Gets the hdmi port information of underlying hardware.
+ *
+ * @return The list of HDMI port information
+ */
+ HdmiPortInfo[] getPortInfo();
+
+ /**
+ * Gets the connection status of the specified port.
+ *
+ * @param portId Port id to be inspected for the connection status.
+ * @return True if a device is connected, otherwise false. The HAL
+ * must watch for +5V power signal to determine the status.
+ */
+ boolean isConnected(in int portId);
+
+ /**
+ * Sets a callback that HDMI HAL must later use for internal HDMI events
+ *
+ * @param callback Callback object to pass hdmi events to the system. The
+ * previously registered callback must be replaced with this one.
+ * setCallback(null) should deregister the callback.
+ */
+ void setCallback(in IHdmiCallback callback);
+}
diff --git a/tv/hdmi/aidl/android/hardware/tv/hdmi/IHdmiCallback.aidl b/tv/hdmi/aidl/android/hardware/tv/hdmi/IHdmiCallback.aidl
new file mode 100644
index 0000000..51275b0
--- /dev/null
+++ b/tv/hdmi/aidl/android/hardware/tv/hdmi/IHdmiCallback.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tv.hdmi;
+
+/**
+ * Callbacks from the HDMI HAL implementation to notify the system of new events.
+ */
+@VintfStability
+oneway interface IHdmiCallback {
+ /**
+ * The callback function that must be called by HAL implementation to notify
+ * the system of new hotplug event.
+ */
+ void onHotplugEvent(in boolean connected, in int portId);
+}
diff --git a/tv/hdmi/aidl/default/Android.bp b/tv/hdmi/aidl/default/Android.bp
new file mode 100644
index 0000000..3e466a0
--- /dev/null
+++ b/tv/hdmi/aidl/default/Android.bp
@@ -0,0 +1,58 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_binary {
+ name: "android.hardware.tv.hdmi-service",
+ vintf_fragments: ["android.hardware.tv.hdmi-service.xml"],
+ relative_install_path: "hw",
+ vendor: true,
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ ],
+ init_rc: ["android.hardware.tv.hdmi-service.rc"],
+ srcs: [
+ "serviceMock.cpp",
+ "HdmiMock.cpp",
+ ],
+ shared_libs: [
+ "libbinder_ndk",
+ "liblog",
+ "libbase",
+ "libutils",
+ "libhardware",
+ "libhidlbase",
+ "android.hardware.tv.hdmi-V1-ndk",
+ ],
+}
+
+cc_fuzz {
+ name: "android.hardware.tv.hdmi-service_fuzzer",
+ defaults: ["service_fuzzer_defaults"],
+ static_libs: [
+ "android.hardware.tv.hdmi-V1-ndk",
+ "liblog",
+ ],
+ srcs: [
+ "fuzzer.cpp",
+ "HdmiMock.cpp",
+ ],
+ fuzz_config: {
+ componentid: 826094,
+ },
+}
diff --git a/tv/hdmi/aidl/default/HdmiMock.cpp b/tv/hdmi/aidl/default/HdmiMock.cpp
new file mode 100644
index 0000000..bbc4705
--- /dev/null
+++ b/tv/hdmi/aidl/default/HdmiMock.cpp
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.tv.hdmi"
+#include <android-base/logging.h>
+#include <fcntl.h>
+#include <utils/Log.h>
+
+#include "HdmiMock.h"
+
+using ndk::ScopedAStatus;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace hdmi {
+namespace implementation {
+
+void HdmiMock::serviceDied(void* cookie) {
+ ALOGE("HdmiMock died");
+ auto hdmi = static_cast<HdmiMock*>(cookie);
+ hdmi->mHdmiThreadRun = false;
+}
+
+ScopedAStatus HdmiMock::getPortInfo(std::vector<HdmiPortInfo>* _aidl_return) {
+ *_aidl_return = mPortInfos;
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus HdmiMock::isConnected(int32_t portId, bool* _aidl_return) {
+ // Maintain port connection status and update on hotplug event
+ if (portId <= mTotalPorts && portId >= 1) {
+ *_aidl_return = mPortConnectionStatus[portId];
+ } else {
+ *_aidl_return = false;
+ }
+
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus HdmiMock::setCallback(const std::shared_ptr<IHdmiCallback>& callback) {
+ if (mCallback != nullptr) {
+ mCallback = nullptr;
+ }
+
+ if (callback != nullptr) {
+ mCallback = callback;
+ AIBinder_linkToDeath(this->asBinder().get(), mDeathRecipient.get(), 0 /* cookie */);
+
+ mInputFile = open(HDMI_MSG_IN_FIFO, O_RDWR | O_CLOEXEC);
+ pthread_create(&mThreadId, NULL, __threadLoop, this);
+ pthread_setname_np(mThreadId, "hdmi_loop");
+ }
+ return ScopedAStatus::ok();
+}
+
+void* HdmiMock::__threadLoop(void* user) {
+ HdmiMock* const self = static_cast<HdmiMock*>(user);
+ self->threadLoop();
+ return 0;
+}
+
+int HdmiMock::readMessageFromFifo(unsigned char* buf, int msgCount) {
+ if (msgCount <= 0 || !buf) {
+ return 0;
+ }
+
+ int ret = -1;
+ // Maybe blocked at driver
+ ret = read(mInputFile, buf, msgCount);
+ if (ret < 0) {
+ ALOGE("[halimp_aidl] read :%s failed, ret:%d\n", HDMI_MSG_IN_FIFO, ret);
+ return -1;
+ }
+
+ return ret;
+}
+
+void HdmiMock::printEventBuf(const char* msg_buf, int len) {
+ int i, size = 0;
+ const int bufSize = MESSAGE_BODY_MAX_LENGTH * 3;
+ // Use 2 characters for each byte in the message plus 1 space
+ char buf[bufSize] = {0};
+
+ // Messages longer than max length will be truncated.
+ for (i = 0; i < len && size < bufSize; i++) {
+ size += sprintf(buf + size, " %02x", msg_buf[i]);
+ }
+ ALOGD("[halimp_aidl] %s, msg:%.*s", __FUNCTION__, size, buf);
+}
+
+void HdmiMock::handleHotplugMessage(unsigned char* msgBuf) {
+ bool connected = ((msgBuf[3]) & 0xf) > 0;
+ int32_t portId = static_cast<uint32_t>(msgBuf[0] & 0xf);
+
+ if (portId > static_cast<int32_t>(mPortInfos.size())) {
+ ALOGD("[halimp_aidl] ignore hot plug message, id %x does not exist", portId);
+ return;
+ }
+
+ ALOGD("[halimp_aidl] hot plug port id %x, is connected %x", (msgBuf[0] & 0xf),
+ (msgBuf[3] & 0xf));
+ mPortConnectionStatus[portId] = connected;
+ if (mPortInfos[portId].type == HdmiPortType::OUTPUT) {
+ mPhysicalAddress = (connected ? 0xffff : ((msgBuf[1] << 8) | (msgBuf[2])));
+ mPortInfos[portId].physicalAddress = mPhysicalAddress;
+ ALOGD("[halimp_aidl] hot plug physical address %x", mPhysicalAddress);
+ }
+
+ if (mCallback != nullptr) {
+ mCallback->onHotplugEvent(connected, portId);
+ }
+}
+
+void HdmiMock::threadLoop() {
+ ALOGD("[halimp_aidl] threadLoop start.");
+ unsigned char msgBuf[MESSAGE_BODY_MAX_LENGTH];
+ int r = -1;
+
+ // Open the input pipe
+ while (mInputFile < 0) {
+ usleep(1000 * 1000);
+ mInputFile = open(HDMI_MSG_IN_FIFO, O_RDONLY | O_CLOEXEC);
+ }
+ ALOGD("[halimp_aidl] file open ok, fd = %d.", mInputFile);
+
+ while (mHdmiThreadRun) {
+ memset(msgBuf, 0, sizeof(msgBuf));
+ // Try to get a message from dev.
+ // echo -n -e '\x04\x83' >> /dev/cec
+ r = readMessageFromFifo(msgBuf, MESSAGE_BODY_MAX_LENGTH);
+ if (r <= 1) {
+ // Ignore received ping messages
+ continue;
+ }
+
+ printEventBuf((const char*)msgBuf, r);
+
+ if (((msgBuf[0] >> 4) & 0xf) == 0xf) {
+ handleHotplugMessage(msgBuf);
+ }
+ }
+
+ ALOGD("[halimp_aidl] thread end.");
+}
+
+HdmiMock::HdmiMock() {
+ ALOGE("[halimp_aidl] Opening a virtual HDMI HAL for testing and virtual machine.");
+ mCallback = nullptr;
+ mPortInfos.resize(mTotalPorts);
+ mPortConnectionStatus.resize(mTotalPorts);
+ mPortInfos[0] = {.type = HdmiPortType::OUTPUT,
+ .portId = static_cast<uint32_t>(1),
+ .cecSupported = true,
+ .arcSupported = false,
+ .eArcSupported = false,
+ .physicalAddress = mPhysicalAddress};
+ mPortConnectionStatus[0] = false;
+ mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient_new(serviceDied));
+}
+
+} // namespace implementation
+} // namespace hdmi
+} // namespace tv
+} // namespace hardware
+} // namespace android
diff --git a/tv/hdmi/aidl/default/HdmiMock.h b/tv/hdmi/aidl/default/HdmiMock.h
new file mode 100644
index 0000000..05795dd
--- /dev/null
+++ b/tv/hdmi/aidl/default/HdmiMock.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/android/hardware/tv/hdmi/BnHdmi.h>
+#include <algorithm>
+#include <vector>
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace hdmi {
+namespace implementation {
+
+using ::aidl::android::hardware::tv::hdmi::BnHdmi;
+using ::aidl::android::hardware::tv::hdmi::HdmiPortInfo;
+using ::aidl::android::hardware::tv::hdmi::HdmiPortType;
+using ::aidl::android::hardware::tv::hdmi::IHdmi;
+using ::aidl::android::hardware::tv::hdmi::IHdmiCallback;
+
+#define HDMI_MSG_IN_FIFO "/dev/hdmi_in_pipe"
+#define MESSAGE_BODY_MAX_LENGTH 4
+
+struct HdmiMock : public BnHdmi {
+ HdmiMock();
+
+ ::ndk::ScopedAStatus getPortInfo(std::vector<HdmiPortInfo>* _aidl_return) override;
+ ::ndk::ScopedAStatus isConnected(int32_t portId, bool* _aidl_return) override;
+ ::ndk::ScopedAStatus setCallback(const std::shared_ptr<IHdmiCallback>& callback) override;
+
+ void printEventBuf(const char* msg_buf, int len);
+
+ private:
+ static void* __threadLoop(void* data);
+ void threadLoop();
+ int readMessageFromFifo(unsigned char* buf, int msgCount);
+ void handleHotplugMessage(unsigned char* msgBuf);
+
+ private:
+ static void serviceDied(void* cookie);
+ std::shared_ptr<IHdmiCallback> mCallback;
+
+ // Variables for the virtual HDMI hal impl
+ std::vector<HdmiPortInfo> mPortInfos;
+ std::vector<bool> mPortConnectionStatus;
+
+ // Port configuration
+ uint16_t mPhysicalAddress = 0xFFFF;
+ int mTotalPorts = 1;
+
+ // Testing variables
+ // Input file descriptor
+ int mInputFile;
+ bool mHdmiThreadRun = true;
+ pthread_t mThreadId = 0;
+
+ ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
+};
+} // namespace implementation
+} // namespace hdmi
+} // Namespace tv
+} // namespace hardware
+} // namespace android
diff --git a/tv/hdmi/aidl/default/android.hardware.tv.hdmi-service.rc b/tv/hdmi/aidl/default/android.hardware.tv.hdmi-service.rc
new file mode 100644
index 0000000..c926221
--- /dev/null
+++ b/tv/hdmi/aidl/default/android.hardware.tv.hdmi-service.rc
@@ -0,0 +1,5 @@
+service vendor.hdmi-default /vendor/bin/hw/android.hardware.tv.hdmi-service
+ interface aidl android.hardware.tv.hdmi.IHdmi/default
+ class hal
+ user system
+ group system
diff --git a/tv/hdmi/aidl/default/android.hardware.tv.hdmi-service.xml b/tv/hdmi/aidl/default/android.hardware.tv.hdmi-service.xml
new file mode 100644
index 0000000..a03c199
--- /dev/null
+++ b/tv/hdmi/aidl/default/android.hardware.tv.hdmi-service.xml
@@ -0,0 +1,10 @@
+<manifest version="1.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.tv.hdmi</name>
+ <version>1</version>
+ <interface>
+ <name>IHdmi</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/tv/hdmi/aidl/default/fuzzer.cpp b/tv/hdmi/aidl/default/fuzzer.cpp
new file mode 100644
index 0000000..06a2bc0
--- /dev/null
+++ b/tv/hdmi/aidl/default/fuzzer.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <HdmiMock.h>
+#include <fuzzbinder/libbinder_ndk_driver.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+using android::fuzzService;
+using android::hardware::tv::hdmi::implementation::HdmiMock;
+using ndk::SharedRefBase;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ auto hdmiAidl = SharedRefBase::make<HdmiMock>();
+
+ fuzzService(hdmiAidl->asBinder().get(), FuzzedDataProvider(data, size));
+
+ return 0;
+}
diff --git a/tv/hdmi/aidl/default/serviceMock.cpp b/tv/hdmi/aidl/default/serviceMock.cpp
new file mode 100644
index 0000000..1d8bf51
--- /dev/null
+++ b/tv/hdmi/aidl/default/serviceMock.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.tv.hdmi-service-shim"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <hidl/HidlTransportSupport.h>
+#include <utils/Log.h>
+#include "HdmiMock.h"
+
+using android::hardware::tv::hdmi::implementation::HdmiMock;
+
+int main() {
+ ABinderProcess_setThreadPoolMaxThreadCount(1);
+ ABinderProcess_startThreadPool();
+
+ std::shared_ptr<HdmiMock> hdmiAidl = ndk::SharedRefBase::make<HdmiMock>();
+ const std::string instance = std::string() + HdmiMock::descriptor + "/default";
+ binder_status_t status =
+ AServiceManager_addService(hdmiAidl->asBinder().get(), instance.c_str());
+ CHECK_EQ(status, STATUS_OK);
+
+ ABinderProcess_joinThreadPool();
+ return 0;
+}
diff --git a/tv/hdmi/aidl/vts/functional/Android.bp b/tv/hdmi/aidl/vts/functional/Android.bp
new file mode 100644
index 0000000..f9af58d
--- /dev/null
+++ b/tv/hdmi/aidl/vts/functional/Android.bp
@@ -0,0 +1,37 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_test {
+ name: "VtsHalTvHdmiAidlTargetTest",
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "use_libaidlvintf_gtest_helper_static",
+ ],
+ srcs: ["VtsHalTvHdmiAidlTargetTest.cpp"],
+ static_libs: [
+ "android.hardware.tv.hdmi-V1-ndk",
+ ],
+ shared_libs: [
+ "libbinder_ndk",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+ disable_framework: true,
+}
diff --git a/tv/hdmi/aidl/vts/functional/VtsHalTvHdmiAidlTargetTest.cpp b/tv/hdmi/aidl/vts/functional/VtsHalTvHdmiAidlTargetTest.cpp
new file mode 100644
index 0000000..78c2590
--- /dev/null
+++ b/tv/hdmi/aidl/vts/functional/VtsHalTvHdmiAidlTargetTest.cpp
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Hdmi_hal_test"
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/tv/hdmi/BnHdmi.h>
+#include <aidl/android/hardware/tv/hdmi/BnHdmiCallback.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <gtest/gtest.h>
+#include <log/log.h>
+#include <sstream>
+#include <vector>
+
+using ::aidl::android::hardware::tv::hdmi::BnHdmiCallback;
+using ::aidl::android::hardware::tv::hdmi::HdmiPortInfo;
+using ::aidl::android::hardware::tv::hdmi::HdmiPortType;
+using ::aidl::android::hardware::tv::hdmi::IHdmi;
+using ::aidl::android::hardware::tv::hdmi::IHdmiCallback;
+using ::ndk::SpAIBinder;
+
+#define INCORRECT_VENDOR_ID 0x00
+#define TV_PHYSICAL_ADDRESS 0x0000
+
+// The main test class for TV HDMI HAL.
+class HdmiTest : public ::testing::TestWithParam<std::string> {
+ static void serviceDied(void* /* cookie */) { ALOGE("VtsHalTvCecAidlTargetTest died"); }
+
+ public:
+ void SetUp() override {
+ hdmi = IHdmi::fromBinder(SpAIBinder(AServiceManager_waitForService(GetParam().c_str())));
+ ASSERT_NE(hdmi, nullptr);
+ ALOGI("%s: getService() for hdmi is %s", __func__, hdmi->isRemote() ? "remote" : "local");
+
+ hdmiCallback = ::ndk::SharedRefBase::make<HdmiCallback>();
+ ASSERT_NE(hdmiCallback, nullptr);
+ hdmiDeathRecipient =
+ ndk::ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient_new(&serviceDied));
+ ASSERT_EQ(AIBinder_linkToDeath(hdmi->asBinder().get(), hdmiDeathRecipient.get(), 0),
+ STATUS_OK);
+ }
+
+ class HdmiCallback : public BnHdmiCallback {
+ public:
+ ::ndk::ScopedAStatus onHotplugEvent(bool connected __unused, int32_t portId __unused) {
+ return ::ndk::ScopedAStatus::ok();
+ };
+ };
+
+ std::shared_ptr<IHdmi> hdmi;
+ std::shared_ptr<IHdmiCallback> hdmiCallback;
+ ::ndk::ScopedAIBinder_DeathRecipient hdmiDeathRecipient;
+};
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(HdmiTest);
+INSTANTIATE_TEST_SUITE_P(PerInstance, HdmiTest,
+ testing::ValuesIn(android::getAidlHalInstanceNames(IHdmi::descriptor)),
+ android::PrintInstanceNameToString);
+
+TEST_P(HdmiTest, SetCallback) {
+ ASSERT_TRUE(hdmi->setCallback(::ndk::SharedRefBase::make<HdmiCallback>()).isOk());
+}
+
+TEST_P(HdmiTest, GetPortInfo) {
+ std::vector<HdmiPortInfo> ports;
+ ASSERT_TRUE(hdmi->getPortInfo(&ports).isOk());
+
+ bool cecSupportedOnDevice = false;
+ for (size_t i = 0; i < ports.size(); ++i) {
+ EXPECT_TRUE((ports[i].type == HdmiPortType::OUTPUT) ||
+ (ports[i].type == HdmiPortType::INPUT));
+ if (ports[i].portId == 0) {
+ ALOGW("%s: Port id should start from 1", __func__);
+ }
+ cecSupportedOnDevice = cecSupportedOnDevice | ports[i].cecSupported;
+ }
+ EXPECT_NE(cecSupportedOnDevice, false) << "At least one port should support CEC";
+}
+
+TEST_P(HdmiTest, IsConnected) {
+ std::vector<HdmiPortInfo> ports;
+ ASSERT_TRUE(hdmi->getPortInfo(&ports).isOk());
+ for (size_t i = 0; i < ports.size(); ++i) {
+ bool connected;
+ ASSERT_TRUE(hdmi->isConnected(ports[i].portId, &connected).isOk());
+ }
+}
diff --git a/tv/input/OWNERS b/tv/input/OWNERS
new file mode 100644
index 0000000..a02291a
--- /dev/null
+++ b/tv/input/OWNERS
@@ -0,0 +1,4 @@
+hgchen@google.com
+shubang@google.com
+quxiangfang@google.com
+yixiaoluo@google.com
diff --git a/usb/1.0/default/Android.bp b/usb/1.0/default/Android.bp
index 4bed2c7..5f56fe0 100644
--- a/usb/1.0/default/Android.bp
+++ b/usb/1.0/default/Android.bp
@@ -21,21 +21,11 @@
default_applicable_licenses: ["hardware_interfaces_license"],
}
-filegroup {
- name: "android.hardware.usb@1.0-service.xml",
- srcs: ["android.hardware.usb@1.0-service.xml"],
-}
-
-filegroup {
- name: "android.hardware.usb@1.0-service.rc",
- srcs: ["android.hardware.usb@1.0-service.rc"],
-}
-
cc_binary {
name: "android.hardware.usb@1.0-service",
defaults: ["hidl_defaults"],
- init_rc: [":android.hardware.usb@1.0-service.rc"],
- vintf_fragments: [":android.hardware.usb@1.0-service.xml"],
+ init_rc: ["android.hardware.usb@1.0-service.rc"],
+ vintf_fragments: ["android.hardware.usb@1.0-service.xml"],
relative_install_path: "hw",
vendor: true,
srcs: [
diff --git a/usb/1.0/default/Usb.cpp b/usb/1.0/default/Usb.cpp
index 6eb8842..573e0e3 100644
--- a/usb/1.0/default/Usb.cpp
+++ b/usb/1.0/default/Usb.cpp
@@ -234,7 +234,7 @@
else
return Status::UNRECOGNIZED_ROLE;
- return Status::SUCCESS;
+ return Status::SUCCESS;
}
Status getPortStatusHelper (hidl_vec<PortStatus>& currentPortStatus) {
diff --git a/usb/1.0/default/apex/Android.bp b/usb/1.0/default/apex/Android.bp
deleted file mode 100644
index ee50fdf..0000000
--- a/usb/1.0/default/apex/Android.bp
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright (C) 2021 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package {
- default_applicable_licenses: ["hardware_interfaces_license"],
-}
-
-apex_key {
- name: "com.android.hardware.usb.key",
- public_key: "com.android.hardware.usb.avbpubkey",
- private_key: "com.android.hardware.usb.pem",
-}
-
-android_app_certificate {
- name: "com.android.hardware.usb.certificate",
- certificate: "com.android.hardware.usb",
-}
-
-genrule {
- name: "com.android.hardware.usb.rc-gen",
- srcs: [":android.hardware.usb@1.0-service.rc"],
- out: ["com.android.hardware.usb.rc"],
- cmd: "sed -E 's/\\/vendor/\\/apex\\/com.android.hardware.usb/' $(in) > $(out)",
-}
-
-prebuilt_etc {
- name: "com.android.hardware.usb.rc",
- src: ":com.android.hardware.usb.rc-gen",
- installable: false,
-}
-
-apex {
- name: "com.android.hardware.usb",
- manifest: "manifest.json",
- file_contexts: "file_contexts",
- key: "com.android.hardware.usb.key",
- certificate: ":com.android.hardware.usb.certificate",
- updatable: false,
- soc_specific: true,
- use_vndk_as_stable: true,
- binaries: ["android.hardware.usb@1.0-service"],
- prebuilts: [
- "com.android.hardware.usb.rc",
- "android.hardware.usb.accessory.prebuilt.xml",
- "android.hardware.usb.host.prebuilt.xml",
- ],
- vintf_fragments: [":android.hardware.usb@1.0-service.xml"],
-}
diff --git a/usb/1.0/default/apex/file_contexts b/usb/1.0/default/apex/file_contexts
deleted file mode 100644
index bc84ac4..0000000
--- a/usb/1.0/default/apex/file_contexts
+++ /dev/null
@@ -1,5 +0,0 @@
-(/.*)? u:object_r:vendor_file:s0
-# Permission XMLs
-/etc/permissions(/.*)? u:object_r:vendor_configs_file:s0
-# binary
-/bin/hw/android\.hardware\.usb@1\.0-service u:object_r:hal_usb_default_exec:s0
\ No newline at end of file
diff --git a/usb/1.0/default/apex/manifest.json b/usb/1.0/default/apex/manifest.json
deleted file mode 100644
index 6a1095f..0000000
--- a/usb/1.0/default/apex/manifest.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "name": "com.android.hardware.usb",
- "version": 1
-}
diff --git a/usb/aidl/Android.bp b/usb/aidl/Android.bp
index 7eb6020..4f59f02 100644
--- a/usb/aidl/Android.bp
+++ b/usb/aidl/Android.bp
@@ -33,11 +33,6 @@
java: {
sdk_version: "module_current",
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
versions_with_info: [
{
diff --git a/usb/aidl/default/Android.bp b/usb/aidl/default/Android.bp
index 7cb2822..ad331f9 100644
--- a/usb/aidl/default/Android.bp
+++ b/usb/aidl/default/Android.bp
@@ -37,8 +37,18 @@
"android.hardware.usb-V1-ndk",
"libbase",
"libbinder_ndk",
- "libcutils",
+ "libcutils",
"liblog",
"libutils",
],
}
+
+filegroup {
+ name: "android.hardware.usb-service.example.xml",
+ srcs: ["android.hardware.usb-service.example.xml"],
+}
+
+filegroup {
+ name: "android.hardware.usb-service.example.rc",
+ srcs: ["android.hardware.usb-service.example.rc"],
+}
diff --git a/usb/apex/Android.bp b/usb/apex/Android.bp
new file mode 100644
index 0000000..765aa21
--- /dev/null
+++ b/usb/apex/Android.bp
@@ -0,0 +1,60 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+apex_key {
+ name: "com.android.hardware.usb.key",
+ public_key: "com.android.hardware.usb.avbpubkey",
+ private_key: "com.android.hardware.usb.pem",
+}
+
+android_app_certificate {
+ name: "com.android.hardware.usb.certificate",
+ certificate: "com.android.hardware.usb",
+}
+
+apex {
+ name: "com.android.hardware.usb",
+ manifest: "manifest.json",
+ file_contexts: "file_contexts",
+ key: "com.android.hardware.usb.key",
+ certificate: ":com.android.hardware.usb.certificate",
+ updatable: false,
+ soc_specific: true,
+ use_vndk_as_stable: true,
+ binaries: ["android.hardware.usb-service.example"],
+ prebuilts: [
+ "com.android.hardware.usb.rc", // init .rc
+ "android.hardware.usb.accessory.prebuilt.xml",
+ "android.hardware.usb.host.prebuilt.xml",
+ ],
+ vintf_fragments: [":android.hardware.usb-service.example.xml"],
+}
+
+// Replace the binary path from /vendor/bin to /apex/{name}/bin in the init .rc file
+genrule {
+ name: "com.android.hardware.usb.rc-gen",
+ srcs: [":android.hardware.usb-service.example.rc"],
+ out: ["com.android.hardware.usb.rc"],
+ cmd: "sed -E 's/\\/vendor/\\/apex\\/com.android.hardware.usb/' $(in) > $(out)",
+}
+
+prebuilt_etc {
+ name: "com.android.hardware.usb.rc",
+ src: ":com.android.hardware.usb.rc-gen",
+ installable: false,
+}
diff --git a/usb/1.0/default/apex/com.android.hardware.usb.avbpubkey b/usb/apex/com.android.hardware.usb.avbpubkey
similarity index 100%
rename from usb/1.0/default/apex/com.android.hardware.usb.avbpubkey
rename to usb/apex/com.android.hardware.usb.avbpubkey
Binary files differ
diff --git a/usb/1.0/default/apex/com.android.hardware.usb.pem b/usb/apex/com.android.hardware.usb.pem
similarity index 100%
rename from usb/1.0/default/apex/com.android.hardware.usb.pem
rename to usb/apex/com.android.hardware.usb.pem
diff --git a/usb/1.0/default/apex/com.android.hardware.usb.pk8 b/usb/apex/com.android.hardware.usb.pk8
similarity index 100%
rename from usb/1.0/default/apex/com.android.hardware.usb.pk8
rename to usb/apex/com.android.hardware.usb.pk8
Binary files differ
diff --git a/usb/1.0/default/apex/com.android.hardware.usb.x509.pem b/usb/apex/com.android.hardware.usb.x509.pem
similarity index 100%
rename from usb/1.0/default/apex/com.android.hardware.usb.x509.pem
rename to usb/apex/com.android.hardware.usb.x509.pem
diff --git a/usb/apex/file_contexts b/usb/apex/file_contexts
new file mode 100644
index 0000000..f223a56
--- /dev/null
+++ b/usb/apex/file_contexts
@@ -0,0 +1,5 @@
+(/.*)? u:object_r:vendor_file:s0
+# Permission XMLs
+/etc/permissions(/.*)? u:object_r:vendor_configs_file:s0
+# binary
+/bin/hw/android\.hardware\.usb-service\.example u:object_r:hal_usb_default_exec:s0
\ No newline at end of file
diff --git a/usb/apex/manifest.json b/usb/apex/manifest.json
new file mode 100644
index 0000000..1a41b90
--- /dev/null
+++ b/usb/apex/manifest.json
@@ -0,0 +1,4 @@
+{
+ "name": "com.android.hardware.usb",
+ "version": 1
+}
diff --git a/usb/gadget/1.2/default/lib/UsbGadgetUtils.cpp b/usb/gadget/1.2/default/lib/UsbGadgetUtils.cpp
index fa50821..0924da7 100644
--- a/usb/gadget/1.2/default/lib/UsbGadgetUtils.cpp
+++ b/usb/gadget/1.2/default/lib/UsbGadgetUtils.cpp
@@ -170,7 +170,6 @@
if ((functions & GadgetFunction::RNDIS) != 0) {
ALOGI("setCurrentUsbFunctions rndis");
- if (linkFunction("gsi.rndis", (*functionCount)++)) return Status::ERROR;
std::string rndisFunction = GetProperty(kVendorRndisConfig, "");
if (rndisFunction != "") {
if (linkFunction(rndisFunction.c_str(), (*functionCount)++)) return Status::ERROR;
diff --git a/uwb/aidl/Android.bp b/uwb/aidl/Android.bp
index cc61046..7dc2b7f 100755
--- a/uwb/aidl/Android.bp
+++ b/uwb/aidl/Android.bp
@@ -21,9 +21,6 @@
enabled: false,
},
ndk: {
- vndk: {
- enabled: true,
- },
apex_available: [
"//apex_available:platform",
"com.android.uwb",
@@ -50,6 +47,7 @@
aidl_interface {
name: "android.hardware.uwb.fira_android",
+ owner: "google",
vendor_available: true,
srcs: ["android/hardware/uwb/fira_android/*.aidl"],
stability: "vintf",
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 cbe2068..6ec8d57 100644
--- a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
+++ b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
@@ -44,4 +44,9 @@
CCC_SUPPORTED_PULSE_SHAPE_COMBOS = 166,
CCC_SUPPORTED_RAN_MULTIPLIER = 167,
SUPPORTED_AOA_RESULT_REQ_ANTENNA_INTERLEAVING = 227,
+ SUPPORTED_MIN_RANGING_INTERVAL_MS = 228,
+ SUPPORTED_RANGE_DATA_NTF_CONFIG = 229,
+ SUPPORTED_RSSI_REPORTING = 230,
+ SUPPORTED_DIAGNOSTICS = 231,
+ SUPPORTED_MIN_SLOT_DURATION = 232,
}
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 cd2e122..fbcfbff 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
@@ -36,4 +36,5 @@
enum UwbVendorGidAndroidOids {
ANDROID_GET_POWER_STATS = 0,
ANDROID_SET_COUNTRY_CODE = 1,
+ ANDROID_RANGE_DIAGNOSTICS = 2,
}
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 d35728f..8413f06 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
@@ -43,4 +43,6 @@
NB_OF_RANGE_MEASUREMENTS = 227,
NB_OF_AZIMUTH_MEASUREMENTS = 228,
NB_OF_ELEVATION_MEASUREMENTS = 229,
+ ENABLE_DIAGNOSTICS = 232,
+ DIAGRAMS_FRAME_REPORTS_FIELDS = 233,
}
diff --git a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
index 0140fdd..b182f9d 100644
--- a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
+++ b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
@@ -150,4 +150,38 @@
* 0 - Feature not supported.
*/
SUPPORTED_AOA_RESULT_REQ_ANTENNA_INTERLEAVING = 0xE3,
+
+ /**
+ * 4 byte value to indicate supported min ranging interval in ms.
+ */
+ SUPPORTED_MIN_RANGING_INTERVAL_MS = 0xE4,
+
+ /**
+ * 4 byte bitmask to indicate the supported RANGE_DATA_NTF_CONFIG values
+ *
+ * Bitmask where each bit corresponds to values used in
+ * RANGE_DATA_NTF_CONFIG in SET_APP_CFG_CMD
+ */
+ SUPPORTED_RANGE_DATA_NTF_CONFIG = 0xE5,
+
+ /**
+ * 1 byte bitmask to indicate the supported RSSI_REPORTING values
+ * Values:
+ * 1 - Feature supported.
+ * 0 - Feature not supported.
+ */
+ SUPPORTED_RSSI_REPORTING = 0xE6,
+
+ /**
+ * 1 byte value to indicate support for diagnostics feature.
+ * Values:
+ * 1 - Feature supported.
+ * 0 - Feature not supported.
+ */
+ SUPPORTED_DIAGNOSTICS = 0xE7,
+
+ /**
+ * 4 byte value to indicate supported min slot duration in ms.
+ */
+ SUPPORTED_MIN_SLOT_DURATION = 0xE8,
}
diff --git a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl
index e389a2d..4768f55 100644
--- a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl
+++ b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl
@@ -30,5 +30,11 @@
ANDROID_GET_POWER_STATS = 0x0,
// Used to set the current regulatory country code (determined usinag
// SIM or hardcoded by OEM).
+ // Country code is sent as a 2 byte value corresponding to ISO-3166 country code.
+ // Note: "00" is used to indicate that the country code is unknown.
ANDROID_SET_COUNTRY_CODE = 0x1,
+ // Used by the notification to get UWB ranging diagnostics stats.
+ // Supported only if the UwbVendorCapabilityTlvTypes.SUPPORTED_DIAGNOSTICS set
+ // to 1.
+ ANDROID_RANGE_DIAGNOSTICS = 0x2,
}
diff --git a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorSessionAppConfigTlvTypes.aidl b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorSessionAppConfigTlvTypes.aidl
index f43b249..f303ed9 100644
--- a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorSessionAppConfigTlvTypes.aidl
+++ b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorSessionAppConfigTlvTypes.aidl
@@ -66,4 +66,23 @@
NB_OF_AZIMUTH_MEASUREMENTS = 0xE4,
/** 1 byte data */
NB_OF_ELEVATION_MEASUREMENTS = 0xE5,
+
+ /**
+ * Supported only if the UwbVendorCapabilityTlvTypes
+ * .SUPPORTED_DIAGNOSTICS set to 1.
+ */
+ /**
+ * 1 byte data
+ * 1 - Enable,
+ * 0 - Disable
+ */
+ ENABLE_DIAGNOSTICS = 0xE8,
+ /**
+ * 1 byte bitmask
+ * b0: Activate RSSIs field,
+ * b1: Activate AoAs field,
+ * b2: Activate CIRs field,
+ * b3 - b7: RFU
+ */
+ DIAGRAMS_FRAME_REPORTS_FIELDS = 0xE9,
}
diff --git a/vibrator/aidl/Android.bp b/vibrator/aidl/Android.bp
index d4d5857..c5936e3 100644
--- a/vibrator/aidl/Android.bp
+++ b/vibrator/aidl/Android.bp
@@ -17,12 +17,7 @@
stability: "vintf",
backend: {
java: {
- sdk_version: "module_current",
- },
- ndk: {
- vndk: {
- enabled: true,
- },
+ sdk_version: "system_current",
},
},
versions: [
diff --git a/vibrator/aidl/default/Android.bp b/vibrator/aidl/default/Android.bp
index c4140be..78bb4ed 100644
--- a/vibrator/aidl/default/Android.bp
+++ b/vibrator/aidl/default/Android.bp
@@ -57,33 +57,12 @@
cc_fuzz {
name: "android.hardware.vibrator-service.example_fuzzer",
host_supported: true,
+ defaults: ["service_fuzzer_defaults"],
static_libs: [
"android.hardware.vibrator-V2-ndk",
- "libbase",
- "libbinder_random_parcel",
- "libcutils",
"liblog",
"libvibratorexampleimpl",
],
- target: {
- android: {
- shared_libs: [
- "libbinder_ndk",
- "libbinder",
- "libutils",
- ],
- },
- host: {
- static_libs: [
- "libbinder_ndk",
- "libbinder",
- "libutils",
- ],
- },
- darwin: {
- enabled: false,
- },
- },
srcs: ["fuzzer.cpp"],
fuzz_config: {
cc: [
diff --git a/vibrator/aidl/default/example_vendor_java_client/Android.bp b/vibrator/aidl/default/example_vendor_java_client/Android.bp
new file mode 100644
index 0000000..f615cb1
--- /dev/null
+++ b/vibrator/aidl/default/example_vendor_java_client/Android.bp
@@ -0,0 +1,34 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library {
+ name: "libexample_vib_getter",
+ srcs: ["getter.cpp"],
+ vendor: true,
+ shared_libs: [
+ "liblog",
+ "libbinder_ndk",
+ ],
+ header_libs: ["jni_headers"],
+ stl: "c++_shared",
+ visibility: [":__subpackages__"],
+}
+
+android_app {
+ name: "ExampleVibratorJavaVendorClient",
+ privileged: true,
+ vendor: true,
+ static_libs: ["android.hardware.vibrator-V1-java"],
+ jni_libs: ["libexample_vib_getter"],
+ jarjar_rules: "jarjar.txt",
+ stl: "c++_shared",
+ srcs: ["example/vib/MyActivity.java"],
+ sdk_version: "system_current",
+ visibility: [":__subpackages__"],
+}
diff --git a/vibrator/aidl/default/example_vendor_java_client/AndroidManifest.xml b/vibrator/aidl/default/example_vendor_java_client/AndroidManifest.xml
new file mode 100644
index 0000000..0561066
--- /dev/null
+++ b/vibrator/aidl/default/example_vendor_java_client/AndroidManifest.xml
@@ -0,0 +1,7 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ package="example.vib">
+ <application>
+ <activity android:name=".MyActivity"/>
+ </application>
+</manifest>
diff --git a/vibrator/aidl/default/example_vendor_java_client/example/vib/MyActivity.java b/vibrator/aidl/default/example_vendor_java_client/example/vib/MyActivity.java
new file mode 100644
index 0000000..aadce8e
--- /dev/null
+++ b/vibrator/aidl/default/example_vendor_java_client/example/vib/MyActivity.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package example.vib;
+
+import android.app.Activity;
+import android.hardware.vibrator.IVibrator;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+public class MyActivity extends Activity {
+ private static native IBinder gimme(String name);
+
+ @Override
+ public void onCreate(Bundle b) {
+ super.onCreate(b);
+ System.loadLibrary("example_vib_getter");
+
+ // There is no API to get ahold of a Stable AIDL service from a vendor app
+ // in Java. This is because this is not the recommended way to get ahold
+ // of functionality in Android. The Android API Council recommendation is to
+ // implement uses-library APIs in the system/system_ext partition which add
+ // new APIs. AIDL as an API in Java is not recommended or supported way to
+ // communicate by apps - the recommendation is to use Java APIs. However,
+ // there also exists a large number of vendor apps which are coupled with
+ // hardware-specific code, and are therefore on the vendor partition. A
+ // large number of these use HIDL, and this is how they can continue to
+ // use that structure with AIDL.
+ IVibrator v =
+ IVibrator.Stub.asInterface(gimme("android.hardware.vibrator.IVibrator/default"));
+
+ try {
+ v.on(100 /*ms*/, null /*cb*/);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+
+ finish();
+ }
+}
diff --git a/vibrator/aidl/default/example_vendor_java_client/getter.cpp b/vibrator/aidl/default/example_vendor_java_client/getter.cpp
new file mode 100644
index 0000000..6115445
--- /dev/null
+++ b/vibrator/aidl/default/example_vendor_java_client/getter.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/binder_auto_utils.h>
+#include <android/binder_ibinder_jni.h>
+#include <android/binder_manager.h>
+#include <jni.h>
+#include <log/log.h>
+
+extern "C" JNIEXPORT jobject JNICALL
+Java_example_vib_MyActivity_gimme__Ljava_lang_String_2(JNIEnv* env, jclass /**/, jstring str) {
+ ALOGI("%s", __func__);
+
+ // Best practice is probably libnativehelper ScopedUtfChars or
+ // libbase ScopeGuard (for platform code), but this is with minimal
+ // dependencies.
+ const char* name = env->GetStringUTFChars(str, nullptr);
+
+ ALOGI("example vib gimme %s", name);
+
+ jobject jbinder = nullptr;
+
+ // Java does not have vendor variants. It's only safe to pass a service when
+ // 'vendor: true' if it is @VintfStability.
+ if (AServiceManager_isDeclared(name)) {
+ ndk::SpAIBinder binder = ndk::SpAIBinder(AServiceManager_waitForService(name));
+ jbinder = AIBinder_toJavaBinder(env, binder.get());
+ } else {
+ ALOGI("not declared");
+ }
+
+ env->ReleaseStringUTFChars(str, name);
+
+ return jbinder;
+}
diff --git a/vibrator/aidl/default/example_vendor_java_client/jarjar.txt b/vibrator/aidl/default/example_vendor_java_client/jarjar.txt
new file mode 100644
index 0000000..e7613a0
--- /dev/null
+++ b/vibrator/aidl/default/example_vendor_java_client/jarjar.txt
@@ -0,0 +1,2 @@
+rule android.hardware.** example.vib.ah.@1
+
diff --git a/vibrator/aidl/default/main.cpp b/vibrator/aidl/default/main.cpp
index feba2c7..7375889 100644
--- a/vibrator/aidl/default/main.cpp
+++ b/vibrator/aidl/default/main.cpp
@@ -29,15 +29,15 @@
// make a default vibrator service
auto vib = ndk::SharedRefBase::make<Vibrator>();
- const std::string vibName = std::string() + Vibrator::descriptor + "/default";
- binder_status_t status = AServiceManager_addService(vib->asBinder().get(), vibName.c_str());
+ binder_status_t status = AServiceManager_addService(
+ vib->asBinder().get(), Vibrator::makeServiceName("default").c_str());
CHECK_EQ(status, STATUS_OK);
// make the vibrator manager service with a different vibrator
auto managedVib = ndk::SharedRefBase::make<Vibrator>();
auto vibManager = ndk::SharedRefBase::make<VibratorManager>(std::move(managedVib));
- const std::string vibManagerName = std::string() + VibratorManager::descriptor + "/default";
- status = AServiceManager_addService(vibManager->asBinder().get(), vibManagerName.c_str());
+ status = AServiceManager_addService(vibManager->asBinder().get(),
+ VibratorManager::makeServiceName("default").c_str());
CHECK_EQ(status, STATUS_OK);
ABinderProcess_joinThreadPool();
diff --git a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
index 3841715..f50a5e7 100644
--- a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
+++ b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
@@ -332,6 +332,7 @@
sleep(1);
EXPECT_EQ(Status::EX_NONE, vibrator->setAmplitude(1.0f).exceptionCode());
sleep(1);
+ EXPECT_TRUE(vibrator->off().isOk());
}
}
@@ -443,7 +444,7 @@
effect.delayMs = std::rand() % (maxDelay + 1);
effect.primitive = primitive;
- effect.scale = static_cast<float>(std::rand()) / RAND_MAX;
+ effect.scale = static_cast<float>(std::rand()) / static_cast<float>(RAND_MAX);
composite.emplace_back(effect);
if (composite.size() == maxSize) {
diff --git a/weaver/aidl/Android.bp b/weaver/aidl/Android.bp
index 8b4306f..caa92aa 100644
--- a/weaver/aidl/Android.bp
+++ b/weaver/aidl/Android.bp
@@ -16,11 +16,6 @@
java: {
platform_apis: true,
},
- ndk: {
- vndk: {
- enabled: true,
- },
- },
},
versions: ["1"],
}
diff --git a/wifi/1.0/vts/OWNERS b/wifi/1.0/vts/OWNERS
deleted file mode 100644
index 287152d..0000000
--- a/wifi/1.0/vts/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 33618
-arabawy@google.com
-etancohen@google.com
diff --git a/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp b/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp
index e6e61cf..02f8209 100644
--- a/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp
+++ b/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp
@@ -66,7 +66,7 @@
bool configureChipToSupportIfaceTypeInternal(const sp<IWifiChip>& wifi_chip,
IfaceType type,
ChipModeId* configured_mode_id) {
- if (!configured_mode_id) {
+ if (!configured_mode_id || !wifi_chip.get()) {
return false;
}
const auto& status_and_modes = HIDL_INVOKE(wifi_chip, getAvailableModes);
diff --git a/wifi/1.1/vts/OWNERS b/wifi/1.1/vts/OWNERS
deleted file mode 100644
index 294fc82..0000000
--- a/wifi/1.1/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 33618
-include ../../1.0/vts/OWNERS
diff --git a/wifi/1.2/vts/OWNERS b/wifi/1.2/vts/OWNERS
deleted file mode 100644
index 294fc82..0000000
--- a/wifi/1.2/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 33618
-include ../../1.0/vts/OWNERS
diff --git a/wifi/1.3/vts/OWNERS b/wifi/1.3/vts/OWNERS
deleted file mode 100644
index 294fc82..0000000
--- a/wifi/1.3/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 33618
-include ../../1.0/vts/OWNERS
diff --git a/wifi/1.4/vts/OWNERS b/wifi/1.4/vts/OWNERS
deleted file mode 100644
index 294fc82..0000000
--- a/wifi/1.4/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 33618
-include ../../1.0/vts/OWNERS
diff --git a/wifi/1.4/vts/functional/wifi_hidl_test_utils_1_4.h b/wifi/1.4/vts/functional/wifi_hidl_test_utils_1_4.h
index a2c5815..ca7b57a 100644
--- a/wifi/1.4/vts/functional/wifi_hidl_test_utils_1_4.h
+++ b/wifi/1.4/vts/functional/wifi_hidl_test_utils_1_4.h
@@ -28,6 +28,6 @@
// These helper functions should be modified to return vectors if we support
// multiple instances.
android::sp<android::hardware::wifi::V1_4::IWifiChip> getWifiChip_1_4(
- const std::string& instance_name);
+ const std::string& instance_name);
android::sp<android::hardware::wifi::V1_4::IWifiApIface> getWifiApIface_1_4(
- const std::string& instance_name);
+ const std::string& instance_name);
diff --git a/wifi/1.5/vts/OWNERS b/wifi/1.5/vts/OWNERS
deleted file mode 100644
index 294fc82..0000000
--- a/wifi/1.5/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 33618
-include ../../1.0/vts/OWNERS
diff --git a/wifi/1.6/default/Android.bp b/wifi/1.6/default/Android.bp
index d48d183..0f98e71 100644
--- a/wifi/1.6/default/Android.bp
+++ b/wifi/1.6/default/Android.bp
@@ -16,42 +16,61 @@
default_applicable_licenses: ["hardware_interfaces_license"],
}
-filegroup {
- name: "android.hardware.wifi@1.0-service_srcs",
- srcs: ["service.cpp"],
+soong_config_module_type {
+ name: "wifi_hal_cc_defaults",
+ module_type: "cc_defaults",
+ config_namespace: "wifi",
+ bool_variables: [
+ "hidl_feature_aware", // WIFI_HIDL_FEATURE_AWARE
+ "hidl_feature_dual_interface", // WIFI_HIDL_FEATURE_DUAL_INTERFACE
+ "hidl_feature_disable_ap", // WIFI_HIDL_FEATURE_DISABLE_AP
+ "hidl_feature_disable_ap_mac_randomization", // WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION
+ "avoid_iface_reset_mac_change", // WIFI_AVOID_IFACE_RESET_MAC_CHANGE
+ ],
+ value_variables: [
+ "hal_interface_combinations", // WIFI_HAL_INTERFACE_COMBINATIONS
+ ],
+ properties: [
+ "cppflags",
+ ],
}
-cc_defaults {
- name: "android.hardware.wifi@1.0-service_default",
- srcs: [":android.hardware.wifi@1.0-service_srcs"],
- relative_install_path: "hw",
- soc_specific: true,
- shared_libs: [
- "android.hardware.wifi@1.0",
- "android.hardware.wifi@1.1",
- "android.hardware.wifi@1.2",
- "android.hardware.wifi@1.3",
- "android.hardware.wifi@1.4",
- "android.hardware.wifi@1.5",
- "android.hardware.wifi@1.6",
- "libbase",
- "libcutils",
- "libhidlbase",
- "liblog",
- "libnl",
- "libutils",
- "libwifi-system-iface",
- "libxml2",
- ],
+wifi_hal_cc_defaults {
+ name: "android.hardware.wifi@1.0-service-cppflags-defaults",
+ soong_config_variables: {
+ hidl_feature_aware: {
+ cppflags: ["-DWIFI_HIDL_FEATURE_AWARE"],
+ },
+ hidl_feature_dual_interface: {
+ cppflags: ["-DWIFI_HIDL_FEATURE_DUAL_INTERFACE"],
+ },
+ hidl_feature_disable_ap: {
+ cppflags: ["-DWIFI_HIDL_FEATURE_DISABLE_AP"],
+ },
+ hidl_feature_disable_ap_mac_randomization: {
+ cppflags: ["-DWIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION"],
+ },
+ avoid_iface_reset_mac_change: {
+ cppflags: ["-DWIFI_AVOID_IFACE_RESET_MAC_CHANGE"],
+ },
+ hal_interface_combinations: {
+ cppflags: ["-DWIFI_HAL_INTERFACE_COMBINATIONS=%s"],
+ },
+ },
+}
+
+cc_library_static {
+ name: "android.hardware.wifi@1.0-service-lib",
+ defaults: ["android.hardware.wifi@1.0-service-cppflags-defaults"],
+ proprietary: true,
+ compile_multilib: "first",
cppflags: [
"-Wall",
"-Werror",
"-Wextra",
],
-}
-
-filegroup {
- name: "android.hardware.wifi@1.0-service-lib_srcs",
+ // Allow implicit fallthroughs in wifi_legacy_hal.cpp until they are fixed.
+ cflags: ["-Wno-error=implicit-fallthrough"],
srcs: [
"hidl_struct_util.cpp",
"hidl_sync_util.cpp",
@@ -71,14 +90,17 @@
"wifi_sta_iface.cpp",
"wifi_status_util.cpp",
],
-}
-cc_defaults {
- name: "android.hardware.wifi@1.0-service-lib_defaults",
- srcs: [":android.hardware.wifi@1.0-service-lib_srcs"],
- relative_install_path: "hw",
- soc_specific: true,
shared_libs: [
+ "libbase",
+ "libcutils",
+ "libhidlbase",
+ "liblog",
+ "libnl",
+ "libutils",
+ "libwifi-hal",
+ "libwifi-system-iface",
+ "libxml2",
"android.hardware.wifi@1.0",
"android.hardware.wifi@1.1",
"android.hardware.wifi@1.2",
@@ -86,22 +108,131 @@
"android.hardware.wifi@1.4",
"android.hardware.wifi@1.5",
"android.hardware.wifi@1.6",
+ ],
+
+ export_include_dirs: ["."],
+}
+
+cc_binary {
+ name: "android.hardware.wifi@1.0-service",
+ vintf_fragments: ["android.hardware.wifi@1.0-service.xml"],
+ relative_install_path: "hw",
+ proprietary: true,
+ cppflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ ],
+ srcs: ["service.cpp"],
+ shared_libs: [
"libbase",
"libcutils",
"libhidlbase",
"liblog",
"libnl",
"libutils",
+ "libwifi-hal",
"libwifi-system-iface",
"libxml2",
+ "android.hardware.wifi@1.0",
+ "android.hardware.wifi@1.1",
+ "android.hardware.wifi@1.2",
+ "android.hardware.wifi@1.3",
+ "android.hardware.wifi@1.4",
+ "android.hardware.wifi@1.5",
+ "android.hardware.wifi@1.6",
],
- // Generated by building android.hardware.wifi@1.0-service-lib and printing LOCAL_CPPFLAGS.
+ static_libs: ["android.hardware.wifi@1.0-service-lib"],
+ init_rc: ["android.hardware.wifi@1.0-service.rc"],
+}
+
+cc_binary {
+ name: "android.hardware.wifi@1.0-service-lazy",
+ vintf_fragments: ["android.hardware.wifi@1.0-service.xml"],
+ overrides: ["android.hardware.wifi@1.0-service"],
+ cflags: ["-DLAZY_SERVICE"],
+ relative_install_path: "hw",
+ proprietary: true,
cppflags: [
"-Wall",
"-Werror",
"-Wextra",
- "-DWIFI_HIDL_FEATURE_DUAL_INTERFACE",
],
- export_include_dirs: ["."],
- include_dirs: ["external/libxml2/include"],
+ srcs: ["service.cpp"],
+ shared_libs: [
+ "libbase",
+ "libcutils",
+ "libhidlbase",
+ "liblog",
+ "libnl",
+ "libutils",
+ "libwifi-hal",
+ "libwifi-system-iface",
+ "libxml2",
+ "android.hardware.wifi@1.0",
+ "android.hardware.wifi@1.1",
+ "android.hardware.wifi@1.2",
+ "android.hardware.wifi@1.3",
+ "android.hardware.wifi@1.4",
+ "android.hardware.wifi@1.5",
+ "android.hardware.wifi@1.6",
+ ],
+ static_libs: ["android.hardware.wifi@1.0-service-lib"],
+ init_rc: ["android.hardware.wifi@1.0-service-lazy.rc"],
+}
+
+cc_test {
+ name: "android.hardware.wifi@1.0-service-tests",
+ proprietary: true,
+ compile_multilib: "first",
+ cppflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ ],
+ srcs: [
+ "tests/hidl_struct_util_unit_tests.cpp",
+ "tests/main.cpp",
+ "tests/mock_interface_tool.cpp",
+ "tests/mock_wifi_feature_flags.cpp",
+ "tests/mock_wifi_iface_util.cpp",
+ "tests/mock_wifi_legacy_hal.cpp",
+ "tests/mock_wifi_mode_controller.cpp",
+ "tests/ringbuffer_unit_tests.cpp",
+ "tests/wifi_nan_iface_unit_tests.cpp",
+ "tests/wifi_chip_unit_tests.cpp",
+ "tests/wifi_iface_util_unit_tests.cpp",
+ ],
+ static_libs: [
+ "libgmock",
+ "libgtest",
+ "android.hardware.wifi@1.0",
+ "android.hardware.wifi@1.1",
+ "android.hardware.wifi@1.2",
+ "android.hardware.wifi@1.3",
+ "android.hardware.wifi@1.4",
+ "android.hardware.wifi@1.5",
+ "android.hardware.wifi@1.6",
+ "android.hardware.wifi@1.0-service-lib",
+ ],
+ shared_libs: [
+ "libbase",
+ "libcutils",
+ "libhidlbase",
+ "liblog",
+ "libnl",
+ "libutils",
+ "libwifi-hal",
+ "libwifi-system-iface",
+ ],
+}
+
+filegroup {
+ name: "default-android.hardware.wifi@1.0-service.rc",
+ srcs: ["android.hardware.wifi@1.0-service.rc"],
+}
+
+filegroup {
+ name: "default-android.hardware.wifi@1.0-service.xml",
+ srcs: ["android.hardware.wifi@1.0-service.xml"],
}
diff --git a/wifi/1.6/default/Android.mk b/wifi/1.6/default/Android.mk
deleted file mode 100644
index ca1c022..0000000
--- a/wifi/1.6/default/Android.mk
+++ /dev/null
@@ -1,202 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-LOCAL_PATH := $(call my-dir)
-
-###
-### android.hardware.wifi static library
-###
-include $(CLEAR_VARS)
-LOCAL_MODULE := android.hardware.wifi@1.0-service-lib
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../NOTICE
-LOCAL_MODULE_RELATIVE_PATH := hw
-LOCAL_PROPRIETARY_MODULE := true
-LOCAL_CPPFLAGS := -Wall -Werror -Wextra
-ifdef WIFI_HAL_INTERFACE_COMBINATIONS
-LOCAL_CPPFLAGS += -DWIFI_HAL_INTERFACE_COMBINATIONS="$(WIFI_HAL_INTERFACE_COMBINATIONS)"
-endif
-ifdef WIFI_HIDL_FEATURE_AWARE
-LOCAL_CPPFLAGS += -DWIFI_HIDL_FEATURE_AWARE
-endif
-ifdef WIFI_HIDL_FEATURE_DUAL_INTERFACE
-LOCAL_CPPFLAGS += -DWIFI_HIDL_FEATURE_DUAL_INTERFACE
-endif
-ifdef WIFI_HIDL_FEATURE_DISABLE_AP
-LOCAL_CPPFLAGS += -DWIFI_HIDL_FEATURE_DISABLE_AP
-endif
-ifdef WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION
-LOCAL_CPPFLAGS += -DWIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION
-endif
-ifdef WIFI_AVOID_IFACE_RESET_MAC_CHANGE
-LOCAL_CPPFLAGS += -DWIFI_AVOID_IFACE_RESET_MAC_CHANGE
-endif
-# Allow implicit fallthroughs in wifi_legacy_hal.cpp until they are fixed.
-LOCAL_CFLAGS += -Wno-error=implicit-fallthrough
-LOCAL_SRC_FILES := \
- hidl_struct_util.cpp \
- hidl_sync_util.cpp \
- ringbuffer.cpp \
- wifi.cpp \
- wifi_ap_iface.cpp \
- wifi_chip.cpp \
- wifi_feature_flags.cpp \
- wifi_iface_util.cpp \
- wifi_legacy_hal.cpp \
- wifi_legacy_hal_factory.cpp \
- wifi_legacy_hal_stubs.cpp \
- wifi_mode_controller.cpp \
- wifi_nan_iface.cpp \
- wifi_p2p_iface.cpp \
- wifi_rtt_controller.cpp \
- wifi_sta_iface.cpp \
- wifi_status_util.cpp
-LOCAL_SHARED_LIBRARIES := \
- libbase \
- libcutils \
- libhidlbase \
- liblog \
- libnl \
- libutils \
- libwifi-hal \
- libwifi-system-iface \
- libxml2 \
- android.hardware.wifi@1.0 \
- android.hardware.wifi@1.1 \
- android.hardware.wifi@1.2 \
- android.hardware.wifi@1.3 \
- android.hardware.wifi@1.4 \
- android.hardware.wifi@1.5 \
- android.hardware.wifi@1.6
-LOCAL_C_INCLUDES += $(TOP)/external/libxml2/include
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
-include $(BUILD_STATIC_LIBRARY)
-
-###
-### android.hardware.wifi daemon
-###
-include $(CLEAR_VARS)
-LOCAL_MODULE := android.hardware.wifi@1.0-service
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../NOTICE
-LOCAL_VINTF_FRAGMENTS := android.hardware.wifi@1.0-service.xml
-LOCAL_MODULE_RELATIVE_PATH := hw
-LOCAL_PROPRIETARY_MODULE := true
-LOCAL_CPPFLAGS := -Wall -Werror -Wextra
-LOCAL_SRC_FILES := \
- service.cpp
-LOCAL_SHARED_LIBRARIES := \
- libbase \
- libcutils \
- libhidlbase \
- liblog \
- libnl \
- libutils \
- libwifi-hal \
- libwifi-system-iface \
- libxml2 \
- android.hardware.wifi@1.0 \
- android.hardware.wifi@1.1 \
- android.hardware.wifi@1.2 \
- android.hardware.wifi@1.3 \
- android.hardware.wifi@1.4 \
- android.hardware.wifi@1.5 \
- android.hardware.wifi@1.6
-LOCAL_STATIC_LIBRARIES := \
- android.hardware.wifi@1.0-service-lib
-LOCAL_INIT_RC := android.hardware.wifi@1.0-service.rc
-include $(BUILD_EXECUTABLE)
-
-###
-### android.hardware.wifi daemon
-###
-include $(CLEAR_VARS)
-LOCAL_MODULE := android.hardware.wifi@1.0-service-lazy
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../NOTICE
-LOCAL_VINTF_FRAGMENTS := android.hardware.wifi@1.0-service.xml
-LOCAL_OVERRIDES_MODULES := android.hardware.wifi@1.0-service
-LOCAL_CFLAGS := -DLAZY_SERVICE
-LOCAL_MODULE_RELATIVE_PATH := hw
-LOCAL_PROPRIETARY_MODULE := true
-LOCAL_CPPFLAGS := -Wall -Werror -Wextra
-LOCAL_SRC_FILES := \
- service.cpp
-LOCAL_SHARED_LIBRARIES := \
- libbase \
- libcutils \
- libhidlbase \
- liblog \
- libnl \
- libutils \
- libwifi-hal \
- libwifi-system-iface \
- libxml2 \
- android.hardware.wifi@1.0 \
- android.hardware.wifi@1.1 \
- android.hardware.wifi@1.2 \
- android.hardware.wifi@1.3 \
- android.hardware.wifi@1.4 \
- android.hardware.wifi@1.5 \
- android.hardware.wifi@1.6
-LOCAL_STATIC_LIBRARIES := \
- android.hardware.wifi@1.0-service-lib
-LOCAL_INIT_RC := android.hardware.wifi@1.0-service-lazy.rc
-include $(BUILD_EXECUTABLE)
-
-###
-### android.hardware.wifi unit tests.
-###
-include $(CLEAR_VARS)
-LOCAL_MODULE := android.hardware.wifi@1.0-service-tests
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../NOTICE
-LOCAL_PROPRIETARY_MODULE := true
-LOCAL_CPPFLAGS := -Wall -Werror -Wextra
-LOCAL_SRC_FILES := \
- tests/hidl_struct_util_unit_tests.cpp \
- tests/main.cpp \
- tests/mock_interface_tool.cpp \
- tests/mock_wifi_feature_flags.cpp \
- tests/mock_wifi_iface_util.cpp \
- tests/mock_wifi_legacy_hal.cpp \
- tests/mock_wifi_mode_controller.cpp \
- tests/ringbuffer_unit_tests.cpp \
- tests/wifi_nan_iface_unit_tests.cpp \
- tests/wifi_chip_unit_tests.cpp \
- tests/wifi_iface_util_unit_tests.cpp
-LOCAL_STATIC_LIBRARIES := \
- libgmock \
- libgtest \
- android.hardware.wifi@1.0 \
- android.hardware.wifi@1.1 \
- android.hardware.wifi@1.2 \
- android.hardware.wifi@1.3 \
- android.hardware.wifi@1.4 \
- android.hardware.wifi@1.5 \
- android.hardware.wifi@1.6 \
- android.hardware.wifi@1.0-service-lib
-LOCAL_SHARED_LIBRARIES := \
- libbase \
- libcutils \
- libhidlbase \
- liblog \
- libnl \
- libutils \
- libwifi-hal \
- libwifi-system-iface
-include $(BUILD_NATIVE_TEST)
diff --git a/wifi/1.6/default/OWNERS b/wifi/1.6/default/OWNERS
deleted file mode 100644
index cf81c79..0000000
--- a/wifi/1.6/default/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-arabawy@google.com
-etancohen@google.com
diff --git a/wifi/1.6/default/wifi_legacy_hal.cpp b/wifi/1.6/default/wifi_legacy_hal.cpp
index 2211897..c9bcdc5 100644
--- a/wifi/1.6/default/wifi_legacy_hal.cpp
+++ b/wifi/1.6/default/wifi_legacy_hal.cpp
@@ -555,7 +555,7 @@
status = global_func_table_.wifi_read_packet_filter(
getIfaceHandle(iface_name), /*src_offset=*/0, buffer.data(), buffer.size());
- return {status, move(buffer)};
+ return {status, std::move(buffer)};
}
std::pair<wifi_error, wifi_gscan_capabilities> WifiLegacyHal::getGscanCapabilities(
diff --git a/wifi/1.6/vts/OWNERS b/wifi/1.6/vts/OWNERS
deleted file mode 100644
index 294fc82..0000000
--- a/wifi/1.6/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 33618
-include ../../1.0/vts/OWNERS
diff --git a/wifi/OWNERS b/wifi/OWNERS
new file mode 100644
index 0000000..c10bbab
--- /dev/null
+++ b/wifi/OWNERS
@@ -0,0 +1,10 @@
+# Bug component: 33618
+
+# Please assign all bugs related to /hardware/interfaces/wifi to the team alias:
+#
+# android-wifi-team@google.com
+#
+# This will get them auto-assigned to the on-call triage engineer, ensuring quickest response.
+#
+arabawy@google.com
+etancohen@google.com
diff --git a/wifi/aidl/Android.bp b/wifi/aidl/Android.bp
new file mode 100644
index 0000000..c0ca667
--- /dev/null
+++ b/wifi/aidl/Android.bp
@@ -0,0 +1,44 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+aidl_interface {
+ name: "android.hardware.wifi",
+ vendor_available: true,
+ srcs: [
+ "android/hardware/wifi/*.aidl",
+ ],
+ stability: "vintf",
+ backend: {
+ java: {
+ sdk_version: "module_current",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.wifi",
+ ],
+ min_sdk_version: "30",
+ lint: {
+ enabled: false,
+ },
+ },
+ },
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifi.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifi.aidl
new file mode 100644
index 0000000..cc995fc
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifi.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+interface IWifi {
+ @PropagateAllowBlocking android.hardware.wifi.IWifiChip getChip(int chipId);
+ int[] getChipIds();
+ boolean isStarted();
+ void registerEventCallback(in android.hardware.wifi.IWifiEventCallback callback);
+ void start();
+ void stop();
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiApIface.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiApIface.aidl
new file mode 100644
index 0000000..a102b97
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiApIface.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+interface IWifiApIface {
+ String getName();
+ String[] getBridgedInstances();
+ byte[6] getFactoryMacAddress();
+ void setCountryCode(in byte[2] code);
+ int[] getValidFrequenciesForBand(in android.hardware.wifi.WifiBand band);
+ void resetToFactoryMacAddress();
+ void setMacAddress(in byte[6] mac);
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiChip.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiChip.aidl
new file mode 100644
index 0000000..647891f
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiChip.aidl
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+interface IWifiChip {
+ void configureChip(in int modeId);
+ @PropagateAllowBlocking android.hardware.wifi.IWifiApIface createApIface();
+ @PropagateAllowBlocking android.hardware.wifi.IWifiApIface createBridgedApIface();
+ @PropagateAllowBlocking android.hardware.wifi.IWifiNanIface createNanIface();
+ @PropagateAllowBlocking android.hardware.wifi.IWifiP2pIface createP2pIface();
+ @PropagateAllowBlocking android.hardware.wifi.IWifiRttController createRttController(in android.hardware.wifi.IWifiStaIface boundIface);
+ @PropagateAllowBlocking android.hardware.wifi.IWifiStaIface createStaIface();
+ void enableDebugErrorAlerts(in boolean enable);
+ void flushRingBufferToFile();
+ void forceDumpToDebugRingBuffer(in String ringName);
+ @PropagateAllowBlocking android.hardware.wifi.IWifiApIface getApIface(in String ifname);
+ String[] getApIfaceNames();
+ android.hardware.wifi.IWifiChip.ChipMode[] getAvailableModes();
+ android.hardware.wifi.IWifiChip.ChipCapabilityMask getCapabilities();
+ android.hardware.wifi.WifiDebugHostWakeReasonStats getDebugHostWakeReasonStats();
+ android.hardware.wifi.WifiDebugRingBufferStatus[] getDebugRingBuffersStatus();
+ int getId();
+ int getMode();
+ @PropagateAllowBlocking android.hardware.wifi.IWifiNanIface getNanIface(in String ifname);
+ String[] getNanIfaceNames();
+ @PropagateAllowBlocking android.hardware.wifi.IWifiP2pIface getP2pIface(in String ifname);
+ String[] getP2pIfaceNames();
+ @PropagateAllowBlocking android.hardware.wifi.IWifiStaIface getStaIface(in String ifname);
+ String[] getStaIfaceNames();
+ android.hardware.wifi.WifiRadioCombinationMatrix getSupportedRadioCombinationsMatrix();
+ android.hardware.wifi.WifiUsableChannel[] getUsableChannels(in android.hardware.wifi.WifiBand band, in android.hardware.wifi.WifiIfaceMode ifaceModeMask, in android.hardware.wifi.IWifiChip.UsableChannelFilter filterMask);
+ void registerEventCallback(in android.hardware.wifi.IWifiChipEventCallback callback);
+ void removeApIface(in String ifname);
+ void removeIfaceInstanceFromBridgedApIface(in String brIfaceName, in String ifaceInstanceName);
+ void removeNanIface(in String ifname);
+ void removeP2pIface(in String ifname);
+ void removeStaIface(in String ifname);
+ android.hardware.wifi.IWifiChip.ChipDebugInfo requestChipDebugInfo();
+ byte[] requestDriverDebugDump();
+ byte[] requestFirmwareDebugDump();
+ void resetTxPowerScenario();
+ void selectTxPowerScenario(in android.hardware.wifi.IWifiChip.TxPowerScenario scenario);
+ void setCoexUnsafeChannels(in android.hardware.wifi.IWifiChip.CoexUnsafeChannel[] unsafeChannels, in android.hardware.wifi.IWifiChip.CoexRestriction restrictions);
+ void setCountryCode(in byte[2] code);
+ void setLatencyMode(in android.hardware.wifi.IWifiChip.LatencyMode mode);
+ void setMultiStaPrimaryConnection(in String ifName);
+ void setMultiStaUseCase(in android.hardware.wifi.IWifiChip.MultiStaUseCase useCase);
+ void startLoggingToDebugRingBuffer(in String ringName, in android.hardware.wifi.WifiDebugRingBufferVerboseLevel verboseLevel, in int maxIntervalInSec, in int minDataSizeInBytes);
+ void stopLoggingToDebugRingBuffer();
+ void triggerSubsystemRestart();
+ const int NO_POWER_CAP_CONSTANT = 2147483647;
+ @Backing(type="int") @VintfStability
+ enum ChipCapabilityMask {
+ DEBUG_MEMORY_FIRMWARE_DUMP = 1,
+ DEBUG_MEMORY_DRIVER_DUMP = 2,
+ DEBUG_RING_BUFFER_CONNECT_EVENT = 4,
+ DEBUG_RING_BUFFER_POWER_EVENT = 8,
+ DEBUG_RING_BUFFER_WAKELOCK_EVENT = 16,
+ DEBUG_RING_BUFFER_VENDOR_DATA = 32,
+ DEBUG_HOST_WAKE_REASON_STATS = 64,
+ DEBUG_ERROR_ALERTS = 128,
+ SET_TX_POWER_LIMIT = 256,
+ D2D_RTT = 512,
+ D2AP_RTT = 1024,
+ USE_BODY_HEAD_SAR = 2048,
+ SET_LATENCY_MODE = 4096,
+ P2P_RAND_MAC = 8192,
+ WIGIG = 16384,
+ }
+ @VintfStability
+ parcelable ChipConcurrencyCombinationLimit {
+ android.hardware.wifi.IfaceConcurrencyType[] types;
+ int maxIfaces;
+ }
+ @VintfStability
+ parcelable ChipConcurrencyCombination {
+ android.hardware.wifi.IWifiChip.ChipConcurrencyCombinationLimit[] limits;
+ }
+ @VintfStability
+ parcelable ChipDebugInfo {
+ String driverDescription;
+ String firmwareDescription;
+ }
+ @VintfStability
+ parcelable ChipIfaceCombinationLimit {
+ android.hardware.wifi.IfaceType[] types;
+ int maxIfaces;
+ }
+ @VintfStability
+ parcelable ChipIfaceCombination {
+ android.hardware.wifi.IWifiChip.ChipIfaceCombinationLimit[] limits;
+ }
+ @VintfStability
+ parcelable ChipMode {
+ int id;
+ android.hardware.wifi.IWifiChip.ChipConcurrencyCombination[] availableCombinations;
+ }
+ @Backing(type="int") @VintfStability
+ enum CoexRestriction {
+ WIFI_DIRECT = 1,
+ SOFTAP = 2,
+ WIFI_AWARE = 4,
+ }
+ @VintfStability
+ parcelable CoexUnsafeChannel {
+ android.hardware.wifi.WifiBand band;
+ int channel;
+ int powerCapDbm;
+ }
+ @Backing(type="int") @VintfStability
+ enum LatencyMode {
+ NORMAL = 0,
+ LOW = 1,
+ }
+ @Backing(type="byte") @VintfStability
+ enum MultiStaUseCase {
+ DUAL_STA_TRANSIENT_PREFER_PRIMARY = 0,
+ DUAL_STA_NON_TRANSIENT_UNBIASED = 1,
+ }
+ @Backing(type="int") @VintfStability
+ enum TxPowerScenario {
+ VOICE_CALL = 0,
+ ON_HEAD_CELL_OFF = 1,
+ ON_HEAD_CELL_ON = 2,
+ ON_BODY_CELL_OFF = 3,
+ ON_BODY_CELL_ON = 4,
+ }
+ @Backing(type="int") @VintfStability
+ enum UsableChannelFilter {
+ CELLULAR_COEXISTENCE = 1,
+ CONCURRENCY = 2,
+ NAN_INSTANT_MODE = 4,
+ }
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiChipEventCallback.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiChipEventCallback.aidl
new file mode 100644
index 0000000..3fd8533
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiChipEventCallback.aidl
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+interface IWifiChipEventCallback {
+ oneway void onChipReconfigureFailure(in android.hardware.wifi.WifiStatusCode status);
+ oneway void onChipReconfigured(in int modeId);
+ oneway void onDebugErrorAlert(in int errorCode, in byte[] debugData);
+ oneway void onDebugRingBufferDataAvailable(in android.hardware.wifi.WifiDebugRingBufferStatus status, in byte[] data);
+ oneway void onIfaceAdded(in android.hardware.wifi.IfaceType type, in String name);
+ oneway void onIfaceRemoved(in android.hardware.wifi.IfaceType type, in String name);
+ oneway void onRadioModeChange(in android.hardware.wifi.IWifiChipEventCallback.RadioModeInfo[] radioModeInfos);
+ @VintfStability
+ parcelable IfaceInfo {
+ String name;
+ int channel;
+ }
+ @VintfStability
+ parcelable RadioModeInfo {
+ int radioId;
+ android.hardware.wifi.WifiBand bandInfo;
+ android.hardware.wifi.IWifiChipEventCallback.IfaceInfo[] ifaceInfos;
+ }
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiEventCallback.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiEventCallback.aidl
new file mode 100644
index 0000000..00e5cb6
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiEventCallback.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+interface IWifiEventCallback {
+ oneway void onFailure(in android.hardware.wifi.WifiStatusCode status);
+ oneway void onStart();
+ oneway void onStop();
+ oneway void onSubsystemRestart(in android.hardware.wifi.WifiStatusCode status);
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiNanIface.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiNanIface.aidl
new file mode 100644
index 0000000..070ca24
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiNanIface.aidl
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+interface IWifiNanIface {
+ String getName();
+ void configRequest(in char cmdId, in android.hardware.wifi.NanConfigRequest msg1, in android.hardware.wifi.NanConfigRequestSupplemental msg2);
+ void createDataInterfaceRequest(in char cmdId, in String ifaceName);
+ void deleteDataInterfaceRequest(in char cmdId, in String ifaceName);
+ void disableRequest(in char cmdId);
+ void enableRequest(in char cmdId, in android.hardware.wifi.NanEnableRequest msg1, in android.hardware.wifi.NanConfigRequestSupplemental msg2);
+ void getCapabilitiesRequest(in char cmdId);
+ void initiateDataPathRequest(in char cmdId, in android.hardware.wifi.NanInitiateDataPathRequest msg);
+ void registerEventCallback(in android.hardware.wifi.IWifiNanIfaceEventCallback callback);
+ void respondToDataPathIndicationRequest(in char cmdId, in android.hardware.wifi.NanRespondToDataPathIndicationRequest msg);
+ void startPublishRequest(in char cmdId, in android.hardware.wifi.NanPublishRequest msg);
+ void startSubscribeRequest(in char cmdId, in android.hardware.wifi.NanSubscribeRequest msg);
+ void stopPublishRequest(in char cmdId, in byte sessionId);
+ void stopSubscribeRequest(in char cmdId, in byte sessionId);
+ void terminateDataPathRequest(in char cmdId, in int ndpInstanceId);
+ void transmitFollowupRequest(in char cmdId, in android.hardware.wifi.NanTransmitFollowupRequest msg);
+ const int MIN_DATA_PATH_CONFIG_PASSPHRASE_LENGTH = 8;
+ const int MAX_DATA_PATH_CONFIG_PASSPHRASE_LENGTH = 63;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiNanIfaceEventCallback.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiNanIfaceEventCallback.aidl
new file mode 100644
index 0000000..591cd8c
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiNanIfaceEventCallback.aidl
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+interface IWifiNanIfaceEventCallback {
+ oneway void eventClusterEvent(in android.hardware.wifi.NanClusterEventInd event);
+ oneway void eventDataPathConfirm(in android.hardware.wifi.NanDataPathConfirmInd event);
+ oneway void eventDataPathRequest(in android.hardware.wifi.NanDataPathRequestInd event);
+ oneway void eventDataPathScheduleUpdate(in android.hardware.wifi.NanDataPathScheduleUpdateInd event);
+ oneway void eventDataPathTerminated(in int ndpInstanceId);
+ oneway void eventDisabled(in android.hardware.wifi.NanStatus status);
+ oneway void eventFollowupReceived(in android.hardware.wifi.NanFollowupReceivedInd event);
+ oneway void eventMatch(in android.hardware.wifi.NanMatchInd event);
+ oneway void eventMatchExpired(in byte discoverySessionId, in int peerId);
+ oneway void eventPublishTerminated(in byte sessionId, in android.hardware.wifi.NanStatus status);
+ oneway void eventSubscribeTerminated(in byte sessionId, in android.hardware.wifi.NanStatus status);
+ oneway void eventTransmitFollowup(in char id, in android.hardware.wifi.NanStatus status);
+ oneway void notifyCapabilitiesResponse(in char id, in android.hardware.wifi.NanStatus status, in android.hardware.wifi.NanCapabilities capabilities);
+ oneway void notifyConfigResponse(in char id, in android.hardware.wifi.NanStatus status);
+ oneway void notifyCreateDataInterfaceResponse(in char id, in android.hardware.wifi.NanStatus status);
+ oneway void notifyDeleteDataInterfaceResponse(in char id, in android.hardware.wifi.NanStatus status);
+ oneway void notifyDisableResponse(in char id, in android.hardware.wifi.NanStatus status);
+ oneway void notifyEnableResponse(in char id, in android.hardware.wifi.NanStatus status);
+ oneway void notifyInitiateDataPathResponse(in char id, in android.hardware.wifi.NanStatus status, in int ndpInstanceId);
+ oneway void notifyRespondToDataPathIndicationResponse(in char id, in android.hardware.wifi.NanStatus status);
+ oneway void notifyStartPublishResponse(in char id, in android.hardware.wifi.NanStatus status, in byte sessionId);
+ oneway void notifyStartSubscribeResponse(in char id, in android.hardware.wifi.NanStatus status, in byte sessionId);
+ oneway void notifyStopPublishResponse(in char id, in android.hardware.wifi.NanStatus status);
+ oneway void notifyStopSubscribeResponse(in char id, in android.hardware.wifi.NanStatus status);
+ oneway void notifyTerminateDataPathResponse(in char id, in android.hardware.wifi.NanStatus status);
+ oneway void notifyTransmitFollowupResponse(in char id, in android.hardware.wifi.NanStatus status);
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiP2pIface.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiP2pIface.aidl
new file mode 100644
index 0000000..5e9948e
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiP2pIface.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+interface IWifiP2pIface {
+ String getName();
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiRttController.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiRttController.aidl
new file mode 100644
index 0000000..730a055
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiRttController.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.wifi;
+@VintfStability
+interface IWifiRttController {
+ void disableResponder(in int cmdId);
+ void enableResponder(in int cmdId, in android.hardware.wifi.WifiChannelInfo channelHint, in int maxDurationInSeconds, in android.hardware.wifi.RttResponder info);
+ android.hardware.wifi.IWifiStaIface getBoundIface();
+ android.hardware.wifi.RttCapabilities getCapabilities();
+ android.hardware.wifi.RttResponder getResponderInfo();
+ void rangeCancel(in int cmdId, in android.hardware.wifi.MacAddress[] addrs);
+ void rangeRequest(in int cmdId, in android.hardware.wifi.RttConfig[] rttConfigs);
+ void registerEventCallback(in android.hardware.wifi.IWifiRttControllerEventCallback callback);
+ void setLci(in int cmdId, in android.hardware.wifi.RttLciInformation lci);
+ void setLcr(in int cmdId, in android.hardware.wifi.RttLcrInformation lcr);
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiRttControllerEventCallback.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiRttControllerEventCallback.aidl
new file mode 100644
index 0000000..a6a33fc
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiRttControllerEventCallback.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+interface IWifiRttControllerEventCallback {
+ oneway void onResults(in int cmdId, in android.hardware.wifi.RttResult[] results);
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiStaIface.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiStaIface.aidl
new file mode 100644
index 0000000..2f0dfa1
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiStaIface.aidl
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+interface IWifiStaIface {
+ String getName();
+ void configureRoaming(in android.hardware.wifi.StaRoamingConfig config);
+ void disableLinkLayerStatsCollection();
+ void enableLinkLayerStatsCollection(in boolean debug);
+ void enableNdOffload(in boolean enable);
+ android.hardware.wifi.StaApfPacketFilterCapabilities getApfPacketFilterCapabilities();
+ android.hardware.wifi.StaBackgroundScanCapabilities getBackgroundScanCapabilities();
+ android.hardware.wifi.IWifiStaIface.StaIfaceCapabilityMask getCapabilities();
+ android.hardware.wifi.WifiDebugRxPacketFateReport[] getDebugRxPacketFates();
+ android.hardware.wifi.WifiDebugTxPacketFateReport[] getDebugTxPacketFates();
+ byte[6] getFactoryMacAddress();
+ android.hardware.wifi.StaLinkLayerStats getLinkLayerStats();
+ android.hardware.wifi.StaRoamingCapabilities getRoamingCapabilities();
+ int[] getValidFrequenciesForBand(in android.hardware.wifi.WifiBand band);
+ void installApfPacketFilter(in byte[] program);
+ byte[] readApfPacketFilterData();
+ void registerEventCallback(in android.hardware.wifi.IWifiStaIfaceEventCallback callback);
+ void setMacAddress(in byte[6] mac);
+ void setRoamingState(in android.hardware.wifi.StaRoamingState state);
+ void setScanMode(in boolean enable);
+ void startBackgroundScan(in int cmdId, in android.hardware.wifi.StaBackgroundScanParameters params);
+ void startDebugPacketFateMonitoring();
+ void startRssiMonitoring(in int cmdId, in int maxRssi, in int minRssi);
+ void startSendingKeepAlivePackets(in int cmdId, in byte[] ipPacketData, in char etherType, in byte[6] srcAddress, in byte[6] dstAddress, in int periodInMs);
+ void stopBackgroundScan(in int cmdId);
+ void stopRssiMonitoring(in int cmdId);
+ void stopSendingKeepAlivePackets(in int cmdId);
+ @Backing(type="int") @VintfStability
+ enum StaIfaceCapabilityMask {
+ APF = 1,
+ BACKGROUND_SCAN = 2,
+ LINK_LAYER_STATS = 4,
+ RSSI_MONITOR = 8,
+ CONTROL_ROAMING = 16,
+ PROBE_IE_ALLOWLIST = 32,
+ SCAN_RAND = 64,
+ STA_5G = 128,
+ HOTSPOT = 256,
+ PNO = 512,
+ TDLS = 1024,
+ TDLS_OFFCHANNEL = 2048,
+ ND_OFFLOAD = 4096,
+ KEEP_ALIVE = 8192,
+ DEBUG_PACKET_FATE = 16384,
+ }
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiStaIfaceEventCallback.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiStaIfaceEventCallback.aidl
new file mode 100644
index 0000000..48b85b0
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiStaIfaceEventCallback.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+interface IWifiStaIfaceEventCallback {
+ oneway void onBackgroundFullScanResult(in int cmdId, in int bucketsScanned, in android.hardware.wifi.StaScanResult result);
+ oneway void onBackgroundScanFailure(in int cmdId);
+ oneway void onBackgroundScanResults(in int cmdId, in android.hardware.wifi.StaScanData[] scanDatas);
+ oneway void onRssiThresholdBreached(in int cmdId, in byte[6] currBssid, in int currRssi);
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IfaceConcurrencyType.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IfaceConcurrencyType.aidl
new file mode 100644
index 0000000..0a3ad1a
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IfaceConcurrencyType.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@Backing(type="int") @VintfStability
+enum IfaceConcurrencyType {
+ STA = 0,
+ AP = 1,
+ AP_BRIDGED = 2,
+ P2P = 3,
+ NAN_IFACE = 4,
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IfaceType.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IfaceType.aidl
new file mode 100644
index 0000000..dbdc439
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IfaceType.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@Backing(type="int") @VintfStability
+enum IfaceType {
+ STA = 0,
+ AP = 1,
+ P2P = 2,
+ NAN_IFACE = 3,
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/MacAddress.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/MacAddress.aidl
new file mode 100644
index 0000000..c4a0613
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/MacAddress.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable MacAddress {
+ byte[6] data;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanBandIndex.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanBandIndex.aidl
new file mode 100644
index 0000000..ca6c910
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanBandIndex.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@Backing(type="int") @VintfStability
+enum NanBandIndex {
+ NAN_BAND_24GHZ = 0,
+ NAN_BAND_5GHZ = 1,
+ NAN_BAND_6GHZ = 2,
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanBandSpecificConfig.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanBandSpecificConfig.aidl
new file mode 100644
index 0000000..57540b3
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanBandSpecificConfig.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable NanBandSpecificConfig {
+ byte rssiClose;
+ byte rssiMiddle;
+ byte rssiCloseProximity;
+ char dwellTimeMs;
+ char scanPeriodSec;
+ boolean validDiscoveryWindowIntervalVal;
+ byte discoveryWindowIntervalVal;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanCapabilities.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanCapabilities.aidl
new file mode 100644
index 0000000..c44654e
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanCapabilities.aidl
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable NanCapabilities {
+ int maxConcurrentClusters;
+ int maxPublishes;
+ int maxSubscribes;
+ int maxServiceNameLen;
+ int maxMatchFilterLen;
+ int maxTotalMatchFilterLen;
+ int maxServiceSpecificInfoLen;
+ int maxExtendedServiceSpecificInfoLen;
+ int maxNdiInterfaces;
+ int maxNdpSessions;
+ int maxAppInfoLen;
+ int maxQueuedTransmitFollowupMsgs;
+ int maxSubscribeInterfaceAddresses;
+ android.hardware.wifi.NanCipherSuiteType supportedCipherSuites;
+ boolean instantCommunicationModeSupportFlag;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanCipherSuiteType.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanCipherSuiteType.aidl
new file mode 100644
index 0000000..4450956
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanCipherSuiteType.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@Backing(type="int") @VintfStability
+enum NanCipherSuiteType {
+ NONE = 0,
+ SHARED_KEY_128_MASK = 1,
+ SHARED_KEY_256_MASK = 2,
+ PUBLIC_KEY_128_MASK = 4,
+ PUBLIC_KEY_256_MASK = 8,
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanClusterEventInd.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanClusterEventInd.aidl
new file mode 100644
index 0000000..7a3ff81
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanClusterEventInd.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable NanClusterEventInd {
+ android.hardware.wifi.NanClusterEventType eventType;
+ byte[6] addr;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanClusterEventType.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanClusterEventType.aidl
new file mode 100644
index 0000000..1dfa45f
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanClusterEventType.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@Backing(type="int") @VintfStability
+enum NanClusterEventType {
+ DISCOVERY_MAC_ADDRESS_CHANGED = 0,
+ STARTED_CLUSTER = 1,
+ JOINED_CLUSTER = 2,
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanConfigRequest.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanConfigRequest.aidl
new file mode 100644
index 0000000..5ead651
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanConfigRequest.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable NanConfigRequest {
+ byte masterPref;
+ boolean disableDiscoveryAddressChangeIndication;
+ boolean disableStartedClusterIndication;
+ boolean disableJoinedClusterIndication;
+ boolean includePublishServiceIdsInBeacon;
+ byte numberOfPublishServiceIdsInBeacon;
+ boolean includeSubscribeServiceIdsInBeacon;
+ byte numberOfSubscribeServiceIdsInBeacon;
+ char rssiWindowSize;
+ int macAddressRandomizationIntervalSec;
+ android.hardware.wifi.NanBandSpecificConfig[3] bandSpecificConfig;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanConfigRequestSupplemental.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanConfigRequestSupplemental.aidl
new file mode 100644
index 0000000..682699e
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanConfigRequestSupplemental.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable NanConfigRequestSupplemental {
+ int discoveryBeaconIntervalMs;
+ int numberOfSpatialStreamsInDiscovery;
+ boolean enableDiscoveryWindowEarlyTermination;
+ boolean enableRanging;
+ boolean enableInstantCommunicationMode;
+ int instantModeChannel;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanDataPathChannelCfg.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanDataPathChannelCfg.aidl
new file mode 100644
index 0000000..ce75288
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanDataPathChannelCfg.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@Backing(type="int") @VintfStability
+enum NanDataPathChannelCfg {
+ CHANNEL_NOT_REQUESTED = 0,
+ REQUEST_CHANNEL_SETUP = 1,
+ FORCE_CHANNEL_SETUP = 2,
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanDataPathChannelInfo.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanDataPathChannelInfo.aidl
new file mode 100644
index 0000000..d111db7
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanDataPathChannelInfo.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable NanDataPathChannelInfo {
+ int channelFreq;
+ android.hardware.wifi.WifiChannelWidthInMhz channelBandwidth;
+ int numSpatialStreams;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanDataPathConfirmInd.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanDataPathConfirmInd.aidl
new file mode 100644
index 0000000..2e1e2ca
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanDataPathConfirmInd.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable NanDataPathConfirmInd {
+ int ndpInstanceId;
+ boolean dataPathSetupSuccess;
+ byte[6] peerNdiMacAddr;
+ byte[] appInfo;
+ android.hardware.wifi.NanStatus status;
+ android.hardware.wifi.NanDataPathChannelInfo[] channelInfo;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanDataPathRequestInd.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanDataPathRequestInd.aidl
new file mode 100644
index 0000000..74d5b73
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanDataPathRequestInd.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable NanDataPathRequestInd {
+ byte discoverySessionId;
+ byte[6] peerDiscMacAddr;
+ int ndpInstanceId;
+ boolean securityRequired;
+ byte[] appInfo;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanDataPathScheduleUpdateInd.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanDataPathScheduleUpdateInd.aidl
new file mode 100644
index 0000000..5fabf55
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanDataPathScheduleUpdateInd.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable NanDataPathScheduleUpdateInd {
+ byte[6] peerDiscoveryAddress;
+ android.hardware.wifi.NanDataPathChannelInfo[] channelInfo;
+ int[] ndpInstanceIds;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanDataPathSecurityConfig.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanDataPathSecurityConfig.aidl
new file mode 100644
index 0000000..635dbce
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanDataPathSecurityConfig.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable NanDataPathSecurityConfig {
+ android.hardware.wifi.NanDataPathSecurityType securityType;
+ android.hardware.wifi.NanCipherSuiteType cipherType;
+ byte[32] pmk;
+ byte[] passphrase;
+ byte[16] scid;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanDataPathSecurityType.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanDataPathSecurityType.aidl
new file mode 100644
index 0000000..64288ca
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanDataPathSecurityType.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@Backing(type="int") @VintfStability
+enum NanDataPathSecurityType {
+ OPEN = 0,
+ PMK = 1,
+ PASSPHRASE = 2,
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanDebugConfig.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanDebugConfig.aidl
new file mode 100644
index 0000000..b84d891
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanDebugConfig.aidl
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable NanDebugConfig {
+ boolean validClusterIdVals;
+ char clusterIdBottomRangeVal;
+ char clusterIdTopRangeVal;
+ boolean validIntfAddrVal;
+ byte[6] intfAddrVal;
+ boolean validOuiVal;
+ int ouiVal;
+ boolean validRandomFactorForceVal;
+ byte randomFactorForceVal;
+ boolean validHopCountForceVal;
+ byte hopCountForceVal;
+ boolean validDiscoveryChannelVal;
+ int[3] discoveryChannelMhzVal;
+ boolean validUseBeaconsInBandVal;
+ boolean[3] useBeaconsInBandVal;
+ boolean validUseSdfInBandVal;
+ boolean[3] useSdfInBandVal;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanDiscoveryCommonConfig.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanDiscoveryCommonConfig.aidl
new file mode 100644
index 0000000..761cdbb
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanDiscoveryCommonConfig.aidl
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable NanDiscoveryCommonConfig {
+ byte sessionId;
+ char ttlSec;
+ char discoveryWindowPeriod;
+ byte discoveryCount;
+ byte[] serviceName;
+ android.hardware.wifi.NanMatchAlg discoveryMatchIndicator;
+ byte[] serviceSpecificInfo;
+ byte[] extendedServiceSpecificInfo;
+ byte[] rxMatchFilter;
+ byte[] txMatchFilter;
+ boolean useRssiThreshold;
+ boolean disableDiscoveryTerminationIndication;
+ boolean disableMatchExpirationIndication;
+ boolean disableFollowupReceivedIndication;
+ android.hardware.wifi.NanDataPathSecurityConfig securityConfig;
+ boolean rangingRequired;
+ int rangingIntervalMs;
+ android.hardware.wifi.NanRangingIndication configRangingIndications;
+ char distanceIngressCm;
+ char distanceEgressCm;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanEnableRequest.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanEnableRequest.aidl
new file mode 100644
index 0000000..eaa009c
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanEnableRequest.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable NanEnableRequest {
+ boolean[3] operateInBand;
+ byte hopCountMax;
+ android.hardware.wifi.NanConfigRequest configParams;
+ android.hardware.wifi.NanDebugConfig debugConfigs;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanFollowupReceivedInd.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanFollowupReceivedInd.aidl
new file mode 100644
index 0000000..743ad9d
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanFollowupReceivedInd.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable NanFollowupReceivedInd {
+ byte discoverySessionId;
+ int peerId;
+ byte[6] addr;
+ boolean receivedInFaw;
+ byte[] serviceSpecificInfo;
+ byte[] extendedServiceSpecificInfo;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanInitiateDataPathRequest.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanInitiateDataPathRequest.aidl
new file mode 100644
index 0000000..697e29a
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanInitiateDataPathRequest.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable NanInitiateDataPathRequest {
+ int peerId;
+ byte[6] peerDiscMacAddr;
+ android.hardware.wifi.NanDataPathChannelCfg channelRequestType;
+ int channel;
+ String ifaceName;
+ android.hardware.wifi.NanDataPathSecurityConfig securityConfig;
+ byte[] appInfo;
+ byte[] serviceNameOutOfBand;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanMatchAlg.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanMatchAlg.aidl
new file mode 100644
index 0000000..dab33ad
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanMatchAlg.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@Backing(type="int") @VintfStability
+enum NanMatchAlg {
+ MATCH_ONCE = 0,
+ MATCH_CONTINUOUS = 1,
+ MATCH_NEVER = 2,
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanMatchInd.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanMatchInd.aidl
new file mode 100644
index 0000000..ae430c4
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanMatchInd.aidl
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable NanMatchInd {
+ byte discoverySessionId;
+ int peerId;
+ byte[6] addr;
+ byte[] serviceSpecificInfo;
+ byte[] extendedServiceSpecificInfo;
+ byte[] matchFilter;
+ boolean matchOccurredInBeaconFlag;
+ boolean outOfResourceFlag;
+ byte rssiValue;
+ android.hardware.wifi.NanCipherSuiteType peerCipherType;
+ boolean peerRequiresSecurityEnabledInNdp;
+ boolean peerRequiresRanging;
+ int rangingMeasurementInMm;
+ android.hardware.wifi.NanRangingIndication rangingIndicationType;
+ byte[] scid;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPublishRequest.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPublishRequest.aidl
new file mode 100644
index 0000000..d8d6b1b
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPublishRequest.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable NanPublishRequest {
+ android.hardware.wifi.NanDiscoveryCommonConfig baseConfigs;
+ android.hardware.wifi.NanPublishType publishType;
+ android.hardware.wifi.NanTxType txType;
+ boolean autoAcceptDataPathRequests;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPublishType.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPublishType.aidl
new file mode 100644
index 0000000..fc9b7a0
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPublishType.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@Backing(type="int") @VintfStability
+enum NanPublishType {
+ UNSOLICITED = 0,
+ SOLICITED = 1,
+ UNSOLICITED_SOLICITED = 2,
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanRangingIndication.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanRangingIndication.aidl
new file mode 100644
index 0000000..d03dffc
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanRangingIndication.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@Backing(type="int") @VintfStability
+enum NanRangingIndication {
+ CONTINUOUS_INDICATION_MASK = 1,
+ INGRESS_MET_MASK = 2,
+ EGRESS_MET_MASK = 4,
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanRespondToDataPathIndicationRequest.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanRespondToDataPathIndicationRequest.aidl
new file mode 100644
index 0000000..5542ff6
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanRespondToDataPathIndicationRequest.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable NanRespondToDataPathIndicationRequest {
+ boolean acceptRequest;
+ int ndpInstanceId;
+ String ifaceName;
+ android.hardware.wifi.NanDataPathSecurityConfig securityConfig;
+ byte[] appInfo;
+ byte[] serviceNameOutOfBand;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanSrfType.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanSrfType.aidl
new file mode 100644
index 0000000..3c0583c
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanSrfType.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@Backing(type="int") @VintfStability
+enum NanSrfType {
+ BLOOM_FILTER = 0,
+ PARTIAL_MAC_ADDR = 1,
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanStatus.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanStatus.aidl
new file mode 100644
index 0000000..834558a
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanStatus.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable NanStatus {
+ android.hardware.wifi.NanStatusCode status;
+ String description;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanStatusCode.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanStatusCode.aidl
new file mode 100644
index 0000000..9eaf518
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanStatusCode.aidl
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@Backing(type="int") @VintfStability
+enum NanStatusCode {
+ SUCCESS = 0,
+ INTERNAL_FAILURE = 1,
+ PROTOCOL_FAILURE = 2,
+ INVALID_SESSION_ID = 3,
+ NO_RESOURCES_AVAILABLE = 4,
+ INVALID_ARGS = 5,
+ INVALID_PEER_ID = 6,
+ INVALID_NDP_ID = 7,
+ NAN_NOT_ALLOWED = 8,
+ NO_OTA_ACK = 9,
+ ALREADY_ENABLED = 10,
+ FOLLOWUP_TX_QUEUE_FULL = 11,
+ UNSUPPORTED_CONCURRENCY_NAN_DISABLED = 12,
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanSubscribeRequest.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanSubscribeRequest.aidl
new file mode 100644
index 0000000..bf176a5
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanSubscribeRequest.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable NanSubscribeRequest {
+ android.hardware.wifi.NanDiscoveryCommonConfig baseConfigs;
+ android.hardware.wifi.NanSubscribeType subscribeType;
+ android.hardware.wifi.NanSrfType srfType;
+ boolean srfRespondIfInAddressSet;
+ boolean shouldUseSrf;
+ boolean isSsiRequiredForMatch;
+ android.hardware.wifi.MacAddress[] intfAddr;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanSubscribeType.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanSubscribeType.aidl
new file mode 100644
index 0000000..325e40b
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanSubscribeType.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@Backing(type="int") @VintfStability
+enum NanSubscribeType {
+ PASSIVE = 0,
+ ACTIVE = 1,
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanTransmitFollowupRequest.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanTransmitFollowupRequest.aidl
new file mode 100644
index 0000000..20c94d9
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanTransmitFollowupRequest.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable NanTransmitFollowupRequest {
+ byte discoverySessionId;
+ int peerId;
+ byte[6] addr;
+ boolean isHighPriority;
+ boolean shouldUseDiscoveryWindow;
+ byte[] serviceSpecificInfo;
+ byte[] extendedServiceSpecificInfo;
+ boolean disableFollowupResultIndication;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanTxType.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanTxType.aidl
new file mode 100644
index 0000000..6f7696f
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanTxType.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@Backing(type="int") @VintfStability
+enum NanTxType {
+ BROADCAST = 0,
+ UNICAST = 1,
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttBw.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttBw.aidl
new file mode 100644
index 0000000..bd7efff
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttBw.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@Backing(type="int") @VintfStability
+enum RttBw {
+ BW_5MHZ = 1,
+ BW_10MHZ = 2,
+ BW_20MHZ = 4,
+ BW_40MHZ = 8,
+ BW_80MHZ = 16,
+ BW_160MHZ = 32,
+ BW_320MHZ = 64,
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttCapabilities.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttCapabilities.aidl
new file mode 100644
index 0000000..cf64687
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttCapabilities.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable RttCapabilities {
+ boolean rttOneSidedSupported;
+ boolean rttFtmSupported;
+ boolean lciSupported;
+ boolean lcrSupported;
+ boolean responderSupported;
+ android.hardware.wifi.RttPreamble preambleSupport;
+ android.hardware.wifi.RttBw bwSupport;
+ byte mcVersion;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttConfig.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttConfig.aidl
new file mode 100644
index 0000000..ccdf2ce
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttConfig.aidl
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable RttConfig {
+ byte[6] addr;
+ android.hardware.wifi.RttType type;
+ android.hardware.wifi.RttPeerType peer;
+ android.hardware.wifi.WifiChannelInfo channel;
+ int burstPeriod;
+ int numBurst;
+ int numFramesPerBurst;
+ int numRetriesPerRttFrame;
+ int numRetriesPerFtmr;
+ boolean mustRequestLci;
+ boolean mustRequestLcr;
+ int burstDuration;
+ android.hardware.wifi.RttPreamble preamble;
+ android.hardware.wifi.RttBw bw;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttLciInformation.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttLciInformation.aidl
new file mode 100644
index 0000000..0fcf151
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttLciInformation.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.wifi;
+@VintfStability
+parcelable RttLciInformation {
+ long latitude;
+ long longitude;
+ int altitude;
+ byte latitudeUnc;
+ byte longitudeUnc;
+ byte altitudeUnc;
+ android.hardware.wifi.RttMotionPattern motionPattern;
+ int floor;
+ int heightAboveFloor;
+ int heightUnc;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttLcrInformation.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttLcrInformation.aidl
new file mode 100644
index 0000000..c756dda
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttLcrInformation.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable RttLcrInformation {
+ byte[2] countryCode;
+ String civicInfo;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttMotionPattern.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttMotionPattern.aidl
new file mode 100644
index 0000000..7c8e369
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttMotionPattern.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@Backing(type="int") @VintfStability
+enum RttMotionPattern {
+ NOT_EXPECTED = 0,
+ EXPECTED = 1,
+ UNKNOWN = 2,
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttPeerType.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttPeerType.aidl
new file mode 100644
index 0000000..23fa7f6
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttPeerType.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@Backing(type="int") @VintfStability
+enum RttPeerType {
+ AP = 1,
+ STA = 2,
+ P2P_GO = 3,
+ P2P_CLIENT = 4,
+ NAN_TYPE = 5,
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttPreamble.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttPreamble.aidl
new file mode 100644
index 0000000..02e6479
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttPreamble.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@Backing(type="int") @VintfStability
+enum RttPreamble {
+ LEGACY = 1,
+ HT = 2,
+ VHT = 4,
+ HE = 8,
+ EHT = 16,
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttResponder.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttResponder.aidl
new file mode 100644
index 0000000..41463b5
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttResponder.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable RttResponder {
+ android.hardware.wifi.WifiChannelInfo channel;
+ android.hardware.wifi.RttPreamble preamble;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttResult.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttResult.aidl
new file mode 100644
index 0000000..743e0bd
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttResult.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.wifi;
+@VintfStability
+parcelable RttResult {
+ byte[6] addr;
+ int burstNum;
+ int measurementNumber;
+ int successNumber;
+ byte numberPerBurstPeer;
+ android.hardware.wifi.RttStatus status;
+ byte retryAfterDuration;
+ android.hardware.wifi.RttType type;
+ int rssi;
+ int rssiSpread;
+ android.hardware.wifi.WifiRateInfo txRate;
+ android.hardware.wifi.WifiRateInfo rxRate;
+ long rtt;
+ long rttSd;
+ long rttSpread;
+ int distanceInMm;
+ int distanceSdInMm;
+ int distanceSpreadInMm;
+ long timeStampInUs;
+ int burstDurationInMs;
+ int negotiatedBurstNum;
+ android.hardware.wifi.WifiInformationElement lci;
+ android.hardware.wifi.WifiInformationElement lcr;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttStatus.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttStatus.aidl
new file mode 100644
index 0000000..2817497
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttStatus.aidl
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@Backing(type="int") @VintfStability
+enum RttStatus {
+ SUCCESS = 0,
+ FAILURE = 1,
+ FAIL_NO_RSP = 2,
+ FAIL_REJECTED = 3,
+ FAIL_NOT_SCHEDULED_YET = 4,
+ FAIL_TM_TIMEOUT = 5,
+ FAIL_AP_ON_DIFF_CHANNEL = 6,
+ FAIL_NO_CAPABILITY = 7,
+ ABORTED = 8,
+ FAIL_INVALID_TS = 9,
+ FAIL_PROTOCOL = 10,
+ FAIL_SCHEDULE = 11,
+ FAIL_BUSY_TRY_LATER = 12,
+ INVALID_REQ = 13,
+ NO_WIFI = 14,
+ FAIL_FTM_PARAM_OVERRIDE = 15,
+ NAN_RANGING_PROTOCOL_FAILURE = 16,
+ NAN_RANGING_CONCURRENCY_NOT_SUPPORTED = 17,
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttType.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttType.aidl
new file mode 100644
index 0000000..2b6087a
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttType.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@Backing(type="int") @VintfStability
+enum RttType {
+ ONE_SIDED = 1,
+ TWO_SIDED = 2,
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/Ssid.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/Ssid.aidl
new file mode 100644
index 0000000..98b523f
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/Ssid.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable Ssid {
+ byte[32] data;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaApfPacketFilterCapabilities.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaApfPacketFilterCapabilities.aidl
new file mode 100644
index 0000000..3b4d785
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaApfPacketFilterCapabilities.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable StaApfPacketFilterCapabilities {
+ int version;
+ int maxLength;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaBackgroundScanBucketEventReportSchemeMask.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaBackgroundScanBucketEventReportSchemeMask.aidl
new file mode 100644
index 0000000..1041dd7
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaBackgroundScanBucketEventReportSchemeMask.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@Backing(type="int") @VintfStability
+enum StaBackgroundScanBucketEventReportSchemeMask {
+ EACH_SCAN = 1,
+ FULL_RESULTS = 2,
+ NO_BATCH = 4,
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaBackgroundScanBucketParameters.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaBackgroundScanBucketParameters.aidl
new file mode 100644
index 0000000..b49d406
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaBackgroundScanBucketParameters.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable StaBackgroundScanBucketParameters {
+ int bucketIdx;
+ android.hardware.wifi.WifiBand band;
+ int[] frequencies;
+ int periodInMs;
+ android.hardware.wifi.StaBackgroundScanBucketEventReportSchemeMask eventReportScheme;
+ int exponentialMaxPeriodInMs;
+ int exponentialBase;
+ int exponentialStepCount;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaBackgroundScanCapabilities.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaBackgroundScanCapabilities.aidl
new file mode 100644
index 0000000..758dd97
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaBackgroundScanCapabilities.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable StaBackgroundScanCapabilities {
+ int maxCacheSize;
+ int maxBuckets;
+ int maxApCachePerScan;
+ int maxReportingThreshold;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaBackgroundScanLimits.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaBackgroundScanLimits.aidl
new file mode 100644
index 0000000..05d0277
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaBackgroundScanLimits.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@Backing(type="int") @VintfStability
+enum StaBackgroundScanLimits {
+ MAX_CHANNELS = 16,
+ MAX_BUCKETS = 16,
+ MAX_AP_CACHE_PER_SCAN = 32,
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaBackgroundScanParameters.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaBackgroundScanParameters.aidl
new file mode 100644
index 0000000..0773566
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaBackgroundScanParameters.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable StaBackgroundScanParameters {
+ int basePeriodInMs;
+ int maxApPerScan;
+ int reportThresholdPercent;
+ int reportThresholdNumScans;
+ android.hardware.wifi.StaBackgroundScanBucketParameters[] buckets;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaLinkLayerIfaceContentionTimeStats.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaLinkLayerIfaceContentionTimeStats.aidl
new file mode 100644
index 0000000..4dee6de
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaLinkLayerIfaceContentionTimeStats.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable StaLinkLayerIfaceContentionTimeStats {
+ int contentionTimeMinInUsec;
+ int contentionTimeMaxInUsec;
+ int contentionTimeAvgInUsec;
+ int contentionNumSamples;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaLinkLayerIfacePacketStats.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaLinkLayerIfacePacketStats.aidl
new file mode 100644
index 0000000..eddf52e
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaLinkLayerIfacePacketStats.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable StaLinkLayerIfacePacketStats {
+ long rxMpdu;
+ long txMpdu;
+ long lostMpdu;
+ long retries;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaLinkLayerIfaceStats.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaLinkLayerIfaceStats.aidl
new file mode 100644
index 0000000..cf68fc6
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaLinkLayerIfaceStats.aidl
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable StaLinkLayerIfaceStats {
+ int beaconRx;
+ int avgRssiMgmt;
+ android.hardware.wifi.StaLinkLayerIfacePacketStats wmeBePktStats;
+ android.hardware.wifi.StaLinkLayerIfacePacketStats wmeBkPktStats;
+ android.hardware.wifi.StaLinkLayerIfacePacketStats wmeViPktStats;
+ android.hardware.wifi.StaLinkLayerIfacePacketStats wmeVoPktStats;
+ byte timeSliceDutyCycleInPercent;
+ android.hardware.wifi.StaLinkLayerIfaceContentionTimeStats wmeBeContentionTimeStats;
+ android.hardware.wifi.StaLinkLayerIfaceContentionTimeStats wmeBkContentionTimeStats;
+ android.hardware.wifi.StaLinkLayerIfaceContentionTimeStats wmeViContentionTimeStats;
+ android.hardware.wifi.StaLinkLayerIfaceContentionTimeStats wmeVoContentionTimeStats;
+ android.hardware.wifi.StaPeerInfo[] peers;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaLinkLayerRadioStats.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaLinkLayerRadioStats.aidl
new file mode 100644
index 0000000..84d24c9
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaLinkLayerRadioStats.aidl
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable StaLinkLayerRadioStats {
+ int onTimeInMs;
+ int txTimeInMs;
+ int[] txTimeInMsPerLevel;
+ int rxTimeInMs;
+ int onTimeInMsForScan;
+ int onTimeInMsForNanScan;
+ int onTimeInMsForBgScan;
+ int onTimeInMsForRoamScan;
+ int onTimeInMsForPnoScan;
+ int onTimeInMsForHs20Scan;
+ android.hardware.wifi.WifiChannelStats[] channelStats;
+ int radioId;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaLinkLayerStats.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaLinkLayerStats.aidl
new file mode 100644
index 0000000..9c05346
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaLinkLayerStats.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable StaLinkLayerStats {
+ android.hardware.wifi.StaLinkLayerIfaceStats iface;
+ android.hardware.wifi.StaLinkLayerRadioStats[] radios;
+ long timeStampInMs;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaPeerInfo.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaPeerInfo.aidl
new file mode 100644
index 0000000..93a901f
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaPeerInfo.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable StaPeerInfo {
+ char staCount;
+ char chanUtil;
+ android.hardware.wifi.StaRateStat[] rateStats;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaRateStat.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaRateStat.aidl
new file mode 100644
index 0000000..43b69fc
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaRateStat.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable StaRateStat {
+ android.hardware.wifi.WifiRateInfo rateInfo;
+ int txMpdu;
+ int rxMpdu;
+ int mpduLost;
+ int retries;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaRoamingCapabilities.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaRoamingCapabilities.aidl
new file mode 100644
index 0000000..9eed877
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaRoamingCapabilities.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable StaRoamingCapabilities {
+ int maxBlocklistSize;
+ int maxAllowlistSize;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaRoamingConfig.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaRoamingConfig.aidl
new file mode 100644
index 0000000..2b37cee
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaRoamingConfig.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable StaRoamingConfig {
+ android.hardware.wifi.MacAddress[] bssidBlocklist;
+ android.hardware.wifi.Ssid[] ssidAllowlist;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaRoamingState.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaRoamingState.aidl
new file mode 100644
index 0000000..1f3d91f
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaRoamingState.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@Backing(type="byte") @VintfStability
+enum StaRoamingState {
+ DISABLED = 0,
+ ENABLED = 1,
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaScanData.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaScanData.aidl
new file mode 100644
index 0000000..5903760
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaScanData.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable StaScanData {
+ android.hardware.wifi.StaScanDataFlagMask flags;
+ int bucketsScanned;
+ android.hardware.wifi.StaScanResult[] results;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaScanDataFlagMask.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaScanDataFlagMask.aidl
new file mode 100644
index 0000000..dc8f2f1
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaScanDataFlagMask.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@Backing(type="int") @VintfStability
+enum StaScanDataFlagMask {
+ INTERRUPTED = 1,
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaScanResult.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaScanResult.aidl
new file mode 100644
index 0000000..9a8d297
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaScanResult.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable StaScanResult {
+ long timeStampInUs;
+ byte[] ssid;
+ byte[6] bssid;
+ int rssi;
+ int frequency;
+ char beaconPeriodInMs;
+ char capability;
+ android.hardware.wifi.WifiInformationElement[] informationElements;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiAntennaMode.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiAntennaMode.aidl
new file mode 100644
index 0000000..b47b7f5
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiAntennaMode.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@Backing(type="int") @VintfStability
+enum WifiAntennaMode {
+ WIFI_ANTENNA_MODE_UNSPECIFIED = 0,
+ WIFI_ANTENNA_MODE_1X1 = 1,
+ WIFI_ANTENNA_MODE_2X2 = 2,
+ WIFI_ANTENNA_MODE_3X3 = 3,
+ WIFI_ANTENNA_MODE_4X4 = 4,
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiBand.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiBand.aidl
new file mode 100644
index 0000000..e9a87ee
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiBand.aidl
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@Backing(type="int") @VintfStability
+enum WifiBand {
+ BAND_UNSPECIFIED = 0,
+ BAND_24GHZ = 1,
+ BAND_5GHZ = 2,
+ BAND_5GHZ_DFS = 4,
+ BAND_5GHZ_WITH_DFS = 6,
+ BAND_24GHZ_5GHZ = 3,
+ BAND_24GHZ_5GHZ_WITH_DFS = 7,
+ BAND_6GHZ = 8,
+ BAND_5GHZ_6GHZ = 10,
+ BAND_24GHZ_5GHZ_6GHZ = 11,
+ BAND_24GHZ_5GHZ_WITH_DFS_6GHZ = 15,
+ BAND_60GHZ = 16,
+ BAND_24GHZ_5GHZ_6GHZ_60GHZ = 27,
+ BAND_24GHZ_5GHZ_WITH_DFS_6GHZ_60GHZ = 31,
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiChannelInfo.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiChannelInfo.aidl
new file mode 100644
index 0000000..297c923
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiChannelInfo.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable WifiChannelInfo {
+ android.hardware.wifi.WifiChannelWidthInMhz width;
+ int centerFreq;
+ int centerFreq0;
+ int centerFreq1;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiChannelStats.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiChannelStats.aidl
new file mode 100644
index 0000000..c6e7acc
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiChannelStats.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable WifiChannelStats {
+ android.hardware.wifi.WifiChannelInfo channel;
+ int onTimeInMs;
+ int ccaBusyTimeInMs;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiChannelWidthInMhz.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiChannelWidthInMhz.aidl
new file mode 100644
index 0000000..8c45044
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiChannelWidthInMhz.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@Backing(type="int") @VintfStability
+enum WifiChannelWidthInMhz {
+ WIDTH_INVALID = -1,
+ WIDTH_20 = 0,
+ WIDTH_40 = 1,
+ WIDTH_80 = 2,
+ WIDTH_160 = 3,
+ WIDTH_80P80 = 4,
+ WIDTH_5 = 5,
+ WIDTH_10 = 6,
+ WIDTH_320 = 7,
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiDebugHostWakeReasonRxIcmpPacketDetails.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiDebugHostWakeReasonRxIcmpPacketDetails.aidl
new file mode 100644
index 0000000..8415e09
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiDebugHostWakeReasonRxIcmpPacketDetails.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable WifiDebugHostWakeReasonRxIcmpPacketDetails {
+ int icmpPkt;
+ int icmp6Pkt;
+ int icmp6Ra;
+ int icmp6Na;
+ int icmp6Ns;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiDebugHostWakeReasonRxMulticastPacketDetails.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiDebugHostWakeReasonRxMulticastPacketDetails.aidl
new file mode 100644
index 0000000..30301d3
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiDebugHostWakeReasonRxMulticastPacketDetails.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable WifiDebugHostWakeReasonRxMulticastPacketDetails {
+ int ipv4RxMulticastAddrCnt;
+ int ipv6RxMulticastAddrCnt;
+ int otherRxMulticastAddrCnt;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiDebugHostWakeReasonRxPacketDetails.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiDebugHostWakeReasonRxPacketDetails.aidl
new file mode 100644
index 0000000..8118322
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiDebugHostWakeReasonRxPacketDetails.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable WifiDebugHostWakeReasonRxPacketDetails {
+ int rxUnicastCnt;
+ int rxMulticastCnt;
+ int rxBroadcastCnt;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiDebugHostWakeReasonStats.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiDebugHostWakeReasonStats.aidl
new file mode 100644
index 0000000..1766476
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiDebugHostWakeReasonStats.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable WifiDebugHostWakeReasonStats {
+ int totalCmdEventWakeCnt;
+ int[] cmdEventWakeCntPerType;
+ int totalDriverFwLocalWakeCnt;
+ int[] driverFwLocalWakeCntPerType;
+ int totalRxPacketWakeCnt;
+ android.hardware.wifi.WifiDebugHostWakeReasonRxPacketDetails rxPktWakeDetails;
+ android.hardware.wifi.WifiDebugHostWakeReasonRxMulticastPacketDetails rxMulticastPkWakeDetails;
+ android.hardware.wifi.WifiDebugHostWakeReasonRxIcmpPacketDetails rxIcmpPkWakeDetails;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiDebugPacketFateFrameInfo.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiDebugPacketFateFrameInfo.aidl
new file mode 100644
index 0000000..2ff6cfc
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiDebugPacketFateFrameInfo.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable WifiDebugPacketFateFrameInfo {
+ android.hardware.wifi.WifiDebugPacketFateFrameType frameType;
+ long frameLen;
+ long driverTimestampUsec;
+ long firmwareTimestampUsec;
+ byte[] frameContent;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiDebugPacketFateFrameType.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiDebugPacketFateFrameType.aidl
new file mode 100644
index 0000000..ee26f2e
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiDebugPacketFateFrameType.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@Backing(type="int") @VintfStability
+enum WifiDebugPacketFateFrameType {
+ UNKNOWN = 0,
+ ETHERNET_II = 1,
+ MGMT_80211 = 2,
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiDebugRingBufferFlags.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiDebugRingBufferFlags.aidl
new file mode 100644
index 0000000..f210e82
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiDebugRingBufferFlags.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@Backing(type="int") @VintfStability
+enum WifiDebugRingBufferFlags {
+ HAS_BINARY_ENTRIES = 1,
+ HAS_ASCII_ENTRIES = 2,
+ HAS_PER_PACKET_ENTRIES = 4,
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiDebugRingBufferStatus.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiDebugRingBufferStatus.aidl
new file mode 100644
index 0000000..e4249d9
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiDebugRingBufferStatus.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable WifiDebugRingBufferStatus {
+ String ringName;
+ int flags;
+ int ringId;
+ int sizeInBytes;
+ int freeSizeInBytes;
+ int verboseLevel;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiDebugRingBufferVerboseLevel.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiDebugRingBufferVerboseLevel.aidl
new file mode 100644
index 0000000..e614f3f
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiDebugRingBufferVerboseLevel.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@Backing(type="int") @VintfStability
+enum WifiDebugRingBufferVerboseLevel {
+ NONE = 0,
+ DEFAULT = 1,
+ VERBOSE = 2,
+ EXCESSIVE = 3,
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiDebugRxPacketFate.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiDebugRxPacketFate.aidl
new file mode 100644
index 0000000..75abb4e
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiDebugRxPacketFate.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@Backing(type="int") @VintfStability
+enum WifiDebugRxPacketFate {
+ SUCCESS = 0,
+ FW_QUEUED = 1,
+ FW_DROP_FILTER = 2,
+ FW_DROP_INVALID = 3,
+ FW_DROP_NOBUFS = 4,
+ FW_DROP_OTHER = 5,
+ DRV_QUEUED = 6,
+ DRV_DROP_FILTER = 7,
+ DRV_DROP_INVALID = 8,
+ DRV_DROP_NOBUFS = 9,
+ DRV_DROP_OTHER = 10,
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiDebugRxPacketFateReport.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiDebugRxPacketFateReport.aidl
new file mode 100644
index 0000000..bfe0c0a
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiDebugRxPacketFateReport.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable WifiDebugRxPacketFateReport {
+ android.hardware.wifi.WifiDebugRxPacketFate fate;
+ android.hardware.wifi.WifiDebugPacketFateFrameInfo frameInfo;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiDebugTxPacketFate.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiDebugTxPacketFate.aidl
new file mode 100644
index 0000000..e360c2c
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiDebugTxPacketFate.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.wifi;
+@Backing(type="int") @VintfStability
+enum WifiDebugTxPacketFate {
+ ACKED = 0,
+ SENT = 1,
+ FW_QUEUED = 2,
+ FW_DROP_INVALID = 3,
+ FW_DROP_NOBUFS = 4,
+ FW_DROP_OTHER = 5,
+ DRV_QUEUED = 6,
+ DRV_DROP_INVALID = 7,
+ DRV_DROP_NOBUFS = 8,
+ DRV_DROP_OTHER = 9,
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiDebugTxPacketFateReport.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiDebugTxPacketFateReport.aidl
new file mode 100644
index 0000000..aee5c31
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiDebugTxPacketFateReport.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable WifiDebugTxPacketFateReport {
+ android.hardware.wifi.WifiDebugTxPacketFate fate;
+ android.hardware.wifi.WifiDebugPacketFateFrameInfo frameInfo;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiIfaceMode.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiIfaceMode.aidl
new file mode 100644
index 0000000..e2fe57a
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiIfaceMode.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@Backing(type="int") @VintfStability
+enum WifiIfaceMode {
+ IFACE_MODE_STA = 1,
+ IFACE_MODE_SOFTAP = 2,
+ IFACE_MODE_IBSS = 4,
+ IFACE_MODE_P2P_CLIENT = 8,
+ IFACE_MODE_P2P_GO = 16,
+ IFACE_MODE_NAN = 32,
+ IFACE_MODE_MESH = 64,
+ IFACE_MODE_TDLS = 128,
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiInformationElement.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiInformationElement.aidl
new file mode 100644
index 0000000..27ba0db
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiInformationElement.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable WifiInformationElement {
+ byte id;
+ byte[] data;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiRadioCombination.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiRadioCombination.aidl
new file mode 100644
index 0000000..f060db8
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiRadioCombination.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable WifiRadioCombination {
+ android.hardware.wifi.WifiRadioConfiguration[] radioConfigurations;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiRadioCombinationMatrix.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiRadioCombinationMatrix.aidl
new file mode 100644
index 0000000..ea86c4f
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiRadioCombinationMatrix.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable WifiRadioCombinationMatrix {
+ android.hardware.wifi.WifiRadioCombination[] radioCombinations;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiRadioConfiguration.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiRadioConfiguration.aidl
new file mode 100644
index 0000000..5169351
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiRadioConfiguration.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable WifiRadioConfiguration {
+ android.hardware.wifi.WifiBand bandInfo;
+ android.hardware.wifi.WifiAntennaMode antennaMode;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiRateInfo.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiRateInfo.aidl
new file mode 100644
index 0000000..c4aca63
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiRateInfo.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable WifiRateInfo {
+ android.hardware.wifi.WifiRatePreamble preamble;
+ android.hardware.wifi.WifiRateNss nss;
+ android.hardware.wifi.WifiChannelWidthInMhz bw;
+ byte rateMcsIdx;
+ int bitRateInKbps;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiRateNss.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiRateNss.aidl
new file mode 100644
index 0000000..0ad6f04
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiRateNss.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@Backing(type="int") @VintfStability
+enum WifiRateNss {
+ NSS_1x1 = 0,
+ NSS_2x2 = 1,
+ NSS_3x3 = 2,
+ NSS_4x4 = 3,
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiRatePreamble.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiRatePreamble.aidl
new file mode 100644
index 0000000..04b6358
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiRatePreamble.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@Backing(type="int") @VintfStability
+enum WifiRatePreamble {
+ OFDM = 0,
+ CCK = 1,
+ HT = 2,
+ VHT = 3,
+ RESERVED = 4,
+ HE = 5,
+ EHT = 6,
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiStatusCode.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiStatusCode.aidl
new file mode 100644
index 0000000..f27661c
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiStatusCode.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.wifi;
+@Backing(type="int") @VintfStability
+enum WifiStatusCode {
+ SUCCESS = 0,
+ ERROR_WIFI_CHIP_INVALID = 1,
+ ERROR_WIFI_IFACE_INVALID = 2,
+ ERROR_WIFI_RTT_CONTROLLER_INVALID = 3,
+ ERROR_NOT_SUPPORTED = 4,
+ ERROR_NOT_AVAILABLE = 5,
+ ERROR_NOT_STARTED = 6,
+ ERROR_INVALID_ARGS = 7,
+ ERROR_BUSY = 8,
+ ERROR_UNKNOWN = 9,
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiUsableChannel.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiUsableChannel.aidl
new file mode 100644
index 0000000..94e3a8a
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiUsableChannel.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable WifiUsableChannel {
+ int channel;
+ android.hardware.wifi.WifiChannelWidthInMhz channelBandwidth;
+ android.hardware.wifi.WifiIfaceMode ifaceModeMask;
+}
diff --git a/wifi/aidl/android/hardware/wifi/IWifi.aidl b/wifi/aidl/android/hardware/wifi/IWifi.aidl
new file mode 100644
index 0000000..1d86421
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/IWifi.aidl
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.IWifiChip;
+import android.hardware.wifi.IWifiEventCallback;
+
+/**
+ * This is the root of the HAL module and is the interface returned when
+ * loading an implementation of the Wi-Fi HAL. There must be at most one
+ * module loaded in the system.
+ */
+@VintfStability
+interface IWifi {
+ /**
+ * Gets an AIDL interface object for the chip corresponding to the
+ * provided chipId.
+ *
+ * @param chipId ID of the chip.
+ * @return AIDL interface object representing the chip.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.NOT_STARTED|,
+ * |WifiStatusCode.UNKNOWN|
+ */
+ @PropagateAllowBlocking IWifiChip getChip(int chipId);
+
+ /**
+ * Retrieves the list of all chip id's on the device.
+ * The corresponding |IWifiChip| object for any chip can be
+ * retrieved using the |getChip| method.
+ *
+ * @return List of all chip id's on the device.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.NOT_STARTED|,
+ * |WifiStatusCode.UNKNOWN|
+ */
+ int[] getChipIds();
+
+ /**
+ * Get the current state of the HAL.
+ *
+ * @return true if started, false otherwise.
+ */
+ boolean isStarted();
+
+ /**
+ * Requests notifications of significant HAL events. Multiple calls to
+ * this must register multiple callbacks, each of which must receive all
+ * events. |IWifiEventCallback| object registration must be independent of the
+ * state of the rest of the HAL and must persist though stops/starts. These
+ * objects must be deleted when the corresponding client process is dead.
+ *
+ * @param callback An instance of the |IWifiEventCallback| AIDL interface
+ * object.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.UNKNOWN|
+ */
+ void registerEventCallback(in IWifiEventCallback callback);
+
+ /**
+ * Perform any setup that is required to make use of the module.
+ * If the module is already started then this must be a noop.
+ * Must trigger |IWifiEventCallback.onStart| on success.
+ *
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.NOT_AVAILABLE|,
+ * |WifiStatusCode.UNKNOWN|
+ */
+ void start();
+
+ /**
+ * Tear down any state, ongoing commands, etc. If the module is already
+ * stopped then this must be a noop. After calling this, all |IWifiChip|
+ * objects will be considered invalid.
+ * Must trigger |IWifiEventCallback.onStop| on success.
+ * Must trigger |IWifiEventCallback.onFailure| on failure.
+ *
+ * Calling stop() and then start() is a valid way of resetting state in
+ * the HAL, driver, and firmware.
+ *
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.NOT_STARTED|,
+ * |WifiStatusCode.UNKNOWN|
+ */
+ void stop();
+}
diff --git a/wifi/aidl/android/hardware/wifi/IWifiApIface.aidl b/wifi/aidl/android/hardware/wifi/IWifiApIface.aidl
new file mode 100644
index 0000000..71ea385
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/IWifiApIface.aidl
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.WifiBand;
+
+/**
+ * Represents a network interface in AP mode.
+ *
+ * This can be obtained through |IWifiChip.getApIface|.
+ */
+@VintfStability
+interface IWifiApIface {
+ /**
+ * Get the name of this interface.
+ *
+ * @return Name of this interface.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|
+ */
+ String getName();
+
+ /**
+ * Get the names of the bridged AP instances.
+ *
+ * @return Vector containing the names of the bridged AP
+ * instances. Note: Returns an empty vector for a non-bridged AP.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ String[] getBridgedInstances();
+
+ /**
+ * Gets the factory MAC address of the interface.
+ *
+ * @return Factory MAC address of the interface.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ byte[6] getFactoryMacAddress();
+
+ /**
+ * Set country code for this iface.
+ *
+ * @param code 2 byte country code (as defined in ISO 3166) to set.
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |WifiStatusCode.SUCCESS|,
+ * |WifiStatusCode.FAILURE_UNKNOWN|,
+ * |WifiStatusCode.FAILURE_IFACE_INVALID|
+ */
+ void setCountryCode(in byte[2] code);
+
+ /**
+ * Used to query the list of valid frequencies (depending on country code set)
+ * for the provided band.
+ *
+ * @param band Band for which the frequency list is being generated.
+ * @return Vector of valid frequencies for the provided band.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ int[] getValidFrequenciesForBand(in WifiBand band);
+
+ /**
+ * Reset all of the AP interfaces' MAC address to the factory MAC address.
+ *
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ void resetToFactoryMacAddress();
+
+ /**
+ * Changes the MAC address of the interface to the given MAC address.
+ *
+ * @param mac MAC address to change to.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ void setMacAddress(in byte[6] mac);
+}
diff --git a/wifi/aidl/android/hardware/wifi/IWifiChip.aidl b/wifi/aidl/android/hardware/wifi/IWifiChip.aidl
new file mode 100644
index 0000000..fe9a6f3
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/IWifiChip.aidl
@@ -0,0 +1,1096 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.IWifiApIface;
+import android.hardware.wifi.IWifiChipEventCallback;
+import android.hardware.wifi.IWifiNanIface;
+import android.hardware.wifi.IWifiP2pIface;
+import android.hardware.wifi.IWifiRttController;
+import android.hardware.wifi.IWifiStaIface;
+import android.hardware.wifi.IfaceConcurrencyType;
+import android.hardware.wifi.IfaceType;
+import android.hardware.wifi.WifiBand;
+import android.hardware.wifi.WifiDebugHostWakeReasonStats;
+import android.hardware.wifi.WifiDebugRingBufferStatus;
+import android.hardware.wifi.WifiDebugRingBufferVerboseLevel;
+import android.hardware.wifi.WifiIfaceMode;
+import android.hardware.wifi.WifiRadioCombinationMatrix;
+import android.hardware.wifi.WifiUsableChannel;
+
+/**
+ * Interface that represents a chip that must be configured as a single unit.
+ */
+@VintfStability
+interface IWifiChip {
+ /**
+ * Capabilities exposed by this chip.
+ */
+ @VintfStability
+ @Backing(type="int")
+ enum ChipCapabilityMask {
+ /**
+ * Memory dump of Firmware.
+ */
+ DEBUG_MEMORY_FIRMWARE_DUMP = 1 << 0,
+ /**
+ * Memory dump of Driver.
+ */
+ DEBUG_MEMORY_DRIVER_DUMP = 1 << 1,
+ /**
+ * Connectivity events reported via debug ring buffer.
+ */
+ DEBUG_RING_BUFFER_CONNECT_EVENT = 1 << 2,
+ /**
+ * Power events reported via debug ring buffer.
+ */
+ DEBUG_RING_BUFFER_POWER_EVENT = 1 << 3,
+ /**
+ * Wakelock events reported via debug ring buffer.
+ */
+ DEBUG_RING_BUFFER_WAKELOCK_EVENT = 1 << 4,
+ /**
+ * Vendor data reported via debug ring buffer.
+ * This mostly contains firmware event logs.
+ */
+ DEBUG_RING_BUFFER_VENDOR_DATA = 1 << 5,
+ /**
+ * Host wake reasons stats collection.
+ */
+ DEBUG_HOST_WAKE_REASON_STATS = 1 << 6,
+ /**
+ * Error alerts.
+ */
+ DEBUG_ERROR_ALERTS = 1 << 7,
+ /**
+ * Set/Reset Tx Power limits.
+ */
+ SET_TX_POWER_LIMIT = 1 << 8,
+ /**
+ * Device to Device RTT.
+ */
+ D2D_RTT = 1 << 9,
+ /**
+ * Device to AP RTT.
+ */
+ D2AP_RTT = 1 << 10,
+ /**
+ * Set/Reset Tx Power limits.
+ */
+ USE_BODY_HEAD_SAR = 1 << 11,
+ /**
+ * Set Latency Mode.
+ */
+ SET_LATENCY_MODE = 1 << 12,
+ /**
+ * Support P2P MAC randomization.
+ */
+ P2P_RAND_MAC = 1 << 13,
+ /**
+ * Chip can operate in the 60GHz band (WiGig chip).
+ */
+ WIGIG = 1 << 14,
+ }
+
+ /**
+ * Set of interface concurrency types, along with the maximum number of interfaces that can have
+ * one of the specified concurrency types for a given ChipConcurrencyCombination. See
+ * ChipConcurrencyCombination below for examples.
+ */
+ @VintfStability
+ parcelable ChipConcurrencyCombinationLimit {
+ IfaceConcurrencyType[] types;
+ int maxIfaces;
+ }
+
+ /**
+ * Set of interfaces that can operate concurrently when in a given mode. See
+ * ChipMode below.
+ *
+ * For example:
+ * [{STA} <= 2]
+ * At most two STA interfaces are supported
+ * [], [STA], [STA+STA]
+ *
+ * [{STA} <= 1, {NAN} <= 1, {AP_BRIDGED} <= 1]
+ * Any combination of STA, NAN, AP_BRIDGED
+ * [], [STA], [NAN], [AP_BRIDGED], [STA+NAN], [STA+AP_BRIDGED], [NAN+AP_BRIDGED],
+ * [STA+NAN+AP_BRIDGED]
+ *
+ * [{STA} <= 1, {NAN,P2P} <= 1]
+ * Optionally a STA and either NAN or P2P
+ * [], [STA], [STA+NAN], [STA+P2P], [NAN], [P2P]
+ * Not included [NAN+P2P], [STA+NAN+P2P]
+ *
+ * [{STA} <= 1, {STA,NAN} <= 1]
+ * Optionally a STA and either a second STA or a NAN
+ * [], [STA], [STA+NAN], [STA+STA], [NAN]
+ * Not included [STA+STA+NAN]
+ */
+ @VintfStability
+ parcelable ChipConcurrencyCombination {
+ ChipConcurrencyCombinationLimit[] limits;
+ }
+
+ /**
+ * Information about the version of the driver and firmware running this chip.
+ *
+ * The information in these ASCII strings are vendor specific and does not
+ * need to follow any particular format. It may be dumped as part of the bug
+ * report.
+ */
+ @VintfStability
+ parcelable ChipDebugInfo {
+ String driverDescription;
+ String firmwareDescription;
+ }
+
+ /**
+ * Set of interface types, along with the maximum number of interfaces that can have
+ * one of the specified types for a given ChipIfaceCombination. See
+ * ChipIfaceCombination for examples.
+ */
+ @VintfStability
+ parcelable ChipIfaceCombinationLimit {
+ IfaceType[] types;
+ int maxIfaces;
+ }
+
+ /**
+ * Set of interfaces that can operate concurrently when in a given mode. See
+ * ChipMode below.
+ *
+ * For example:
+ * [{STA} <= 2]
+ * At most two STA interfaces are supported
+ * [], [STA], [STA+STA]
+ *
+ * [{STA} <= 1, {NAN} <= 1, {AP} <= 1]
+ * Any combination of STA, NAN, AP
+ * [], [STA], [NAN], [AP], [STA+NAN], [STA+AP], [NAN+AP], [STA+NAN+AP]
+ *
+ * [{STA} <= 1, {NAN,P2P} <= 1]
+ * Optionally a STA and either NAN or P2P
+ * [], [STA], [STA+NAN], [STA+P2P], [NAN], [P2P]
+ * Not included [NAN+P2P], [STA+NAN+P2P]
+ *
+ * [{STA} <= 1, {STA,NAN} <= 1]
+ * Optionally a STA and either a second STA or a NAN
+ * [], [STA], [STA+NAN], [STA+STA], [NAN]
+ * Not included [STA+STA+NAN]
+ */
+ @VintfStability
+ parcelable ChipIfaceCombination {
+ ChipIfaceCombinationLimit[] limits;
+ }
+
+ /**
+ * A mode that the chip can be put in. A mode defines a set of constraints on
+ * the interfaces that can exist while in that mode. Modes define a unit of
+ * configuration where all interfaces must be torn down to switch to a
+ * different mode. Some HALs may only have a single mode, but an example where
+ * multiple modes would be required is if a chip has different firmwares with
+ * different capabilities.
+ *
+ * When in a mode, it must be possible to perform any combination of creating
+ * and removing interfaces as long as at least one of the
+ * ChipConcurrencyCombinations is satisfied. This means that if a chip has two
+ * available combinations, [{STA} <= 1] and [{AP_BRIDGED} <= 1] then it is expected
+ * that exactly one STA type or one AP_BRIDGED type can be created, but it
+ * is not expected that both a STA and AP_BRIDGED type could be created. If it
+ * was then there would be a single available combination
+ * [{STA} <=1, {AP_BRIDGED} <= 1].
+ *
+ * When switching between two available combinations it is expected that
+ * interfaces only supported by the initial combination must be removed until
+ * the target combination is also satisfied. At that point new interfaces
+ * satisfying only the target combination can be added (meaning the initial
+ * combination limits will no longer satisfied). The addition of these new
+ * interfaces must not impact the existence of interfaces that satisfy both
+ * combinations.
+ *
+ * For example, a chip with available combinations:
+ * [{STA} <= 2, {NAN} <=1] and [{STA} <=1, {NAN} <= 1, {AP_BRIDGED} <= 1}]
+ * If the chip currently has 3 interfaces STA, STA and NAN and wants to add an
+ * AP_BRIDGED interface in place of one of the STAs, then one of the STA interfaces
+ * must be removed first, and then the AP interface can be created after
+ * the STA has been torn down. During this process the remaining STA and NAN
+ * interfaces must not be removed/recreated.
+ *
+ * If a chip does not support this kind of reconfiguration in this mode then
+ * the combinations must be separated into two separate modes. Before
+ * switching modes, all interfaces must be torn down, the mode switch must be
+ * enacted, and when it completes the new interfaces must be brought up.
+ */
+ @VintfStability
+ parcelable ChipMode {
+ /**
+ * Id that can be used to put the chip in this mode.
+ */
+ int id;
+ /**
+ * A list of the possible interface concurrency type combinations that the
+ * chip can have while in this mode.
+ */
+ ChipConcurrencyCombination[] availableCombinations;
+ }
+
+ /**
+ * Wi-Fi coex channel avoidance support.
+ */
+ const int NO_POWER_CAP_CONSTANT = 0x7FFFFFFF;
+
+ @VintfStability
+ @Backing(type="int")
+ enum CoexRestriction {
+ WIFI_DIRECT = 1 << 0,
+ SOFTAP = 1 << 1,
+ WIFI_AWARE = 1 << 2,
+ }
+
+ /**
+ * Representation of a Wi-Fi channel for Wi-Fi coex channel avoidance.
+ */
+ @VintfStability
+ parcelable CoexUnsafeChannel {
+ /*
+ * Band of the channel.
+ */
+ WifiBand band;
+ /*
+ * Channel number.
+ */
+ int channel;
+ /**
+ * The power cap will be a maximum power value in dbm that is allowed to be transmitted by
+ * the chip on this channel. A value of PowerCapConstant.NO_POWER_CAP means no limitation
+ * on transmitted power is needed by the chip for this channel.
+ */
+ int powerCapDbm;
+ }
+
+ /**
+ * This enum represents the different latency modes that can be set through |setLatencyMode|.
+ */
+ @VintfStability
+ @Backing(type="int")
+ enum LatencyMode {
+ NORMAL = 0,
+ LOW = 1,
+ }
+
+ /**
+ * When there are 2 or more simultaneous STA connections, this use case hint indicates what
+ * use-case is being enabled by the framework. This use case hint can be used by the firmware
+ * to modify various firmware configurations like:
+ * - Allowed BSSIDs the firmware can choose for the initial connection/roaming attempts.
+ * - Duty cycle to choose for the 2 STA connections if the radio is in MCC mode.
+ * - Whether roaming, APF and other offloads need to be enabled or not.
+ * Note:
+ * - This will be invoked before an active wifi connection is established on the second
+ * interface.
+ * - This use-case hint is implicitly void when the second STA interface is brought down.
+ * - When there is only 1 STA interface, we should still retain the last use case
+ * set, which must become active the next time multi STA is enabled.
+ * 1. Initialize with single STA.
+ * 2. Framework creates second STA.
+ * 3. Framework sets use case to DUAL_STA_NON_TRANSIENT_UNBIASED.
+ * 4. Framework destroys second STA. Only 1 STA remains.
+ * 5. Framework recreates second STA.
+ * 6. The active use case remains DUAL_STA_NON_TRANSIENT_UNBIASED (i.e. firmware should not
+ * automatically change it during period of single STA unless requested by framework).
+ */
+ @VintfStability
+ @Backing(type="byte")
+ enum MultiStaUseCase {
+ /**
+ * Usage:
+ * - This will be sent down for make before break use-case.
+ * - Platform is trying to speculatively connect to a second network and evaluate it without
+ * disrupting the primary connection.
+ * Requirements for Firmware:
+ * - Do not reduce the number of tx/rx chains of primary connection.
+ * - If using MCC, should set the MCC duty cycle of the primary connection to be higher than
+ * the secondary connection (maybe 70/30 split).
+ * - Should pick the best BSSID for the secondary STA (disregard the chip mode) independent
+ * of the primary STA:
+ * - Don’t optimize for DBS vs MCC/SCC
+ * - Should not impact the primary connection’s bssid selection:
+ * - Don’t downgrade chains of the existing primary connection.
+ * - Don’t optimize for DBS vs MCC/SCC.
+ */
+ DUAL_STA_TRANSIENT_PREFER_PRIMARY = 0,
+ /**
+ * Usage:
+ * - This will be sent down for any app requested peer to peer connections.
+ * - In this case, both the connections need to be allocated equal resources.
+ * - For the peer to peer use case, BSSID for the secondary connection will be chosen by the
+ * framework.
+ *
+ * Requirements for Firmware:
+ * - Can choose MCC or DBS mode depending on the MCC efficiency and HW capability.
+ * - If using MCC, set the MCC duty cycle of the primary connection to be equal to the
+ * secondary connection.
+ * - Prefer BSSID candidates which will help provide the best "overall" performance for both
+ * the connections.
+ */
+ DUAL_STA_NON_TRANSIENT_UNBIASED = 1,
+ }
+
+ /**
+ * List of preset wifi radio TX power levels for different scenarios.
+ * The actual power values (typically varies based on the channel,
+ * 802.11 connection type, number of MIMO streams, etc) for each scenario
+ * is defined by the OEM as a BDF file since it varies for each wifi chip
+ * vendor and device.
+ */
+ @VintfStability
+ @Backing(type="int")
+ enum TxPowerScenario {
+ VOICE_CALL = 0,
+ ON_HEAD_CELL_OFF = 1,
+ ON_HEAD_CELL_ON = 2,
+ ON_BODY_CELL_OFF = 3,
+ ON_BODY_CELL_ON = 4,
+ }
+
+ /**
+ * Usable Wifi channels filter masks.
+ */
+ @VintfStability
+ @Backing(type="int")
+ enum UsableChannelFilter {
+ /**
+ * Filter Wifi channels that should be avoided due to extreme
+ * cellular coexistence restrictions. Some Wifi channels can have
+ * extreme interference from/to cellular due to short frequency
+ * seperation with neighboring cellular channels, or when there
+ * is harmonic and intermodulation interference. Channels which
+ * only have some performance degradation (e.g. power back off is
+ * sufficient to deal with coexistence issue) can be included and
+ * should not be filtered out.
+ */
+ CELLULAR_COEXISTENCE = 1 << 0,
+ /**
+ * Filter based on concurrency state.
+ * Examples:
+ * - 5GHz SAP operation may be supported in standalone mode, but if
+ * there is a STA connection on a 5GHz DFS channel, none of the 5GHz
+ * channels are usable for SAP if device does not support DFS SAP mode.
+ * - P2P GO may not be supported on indoor channels in the EU during
+ * standalone mode but if there is a STA connection on indoor channel.
+ * P2P GO may be supported by some vendors on the same STA channel.
+ */
+ CONCURRENCY = 1 << 1,
+ /**
+ * Filter Wifi channels that are supported for NAN 3.1 Instant communication mode.
+ * This filter should only be applied to a NAN interface.
+ * - If 5G is supported, then default discovery channel 149/44 is considered.
+ * - If 5G is not supported, then channel 6 has to be considered.
+ */
+ NAN_INSTANT_MODE = 1 << 2,
+ }
+
+ /**
+ * Configure the Chip.
+ * This may NOT be called to reconfigure a chip due to an internal
+ * limitation. Calling this when chip is already configured in a different
+ * mode must trigger an ERROR_NOT_SUPPORTED failure.
+ * If you want to do reconfiguration, please call |IWifi.stop| and |IWifi.start|
+ * to restart Wifi HAL before calling this.
+ * Any existing |IWifiIface| objects must be marked invalid after this call.
+ * If this fails then the chip is now in an undefined state and
+ * configureChip must be called again.
+ * Must trigger |IWifiChipEventCallback.onChipReconfigured| on success.
+ * Must trigger |IWifiEventCallback.onFailure| on failure.
+ *
+ * @param modeId Mode that the chip must switch to, corresponding to the
+ * id property of the target ChipMode.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ void configureChip(in int modeId);
+
+ /**
+ * Create an AP iface on the chip.
+ *
+ * Depending on the mode the chip is configured in, the interface creation
+ * may fail (code: |WifiStatusCode.ERROR_NOT_AVAILABLE|) if we've already
+ * reached the maximum allowed (specified in |ChipIfaceCombination|) number
+ * of ifaces of the AP type.
+ *
+ * @return AIDL interface object representing the iface if
+ * successful, null otherwise.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|
+ */
+ @PropagateAllowBlocking IWifiApIface createApIface();
+
+ /**
+ * Create a bridged AP iface on the chip.
+ *
+ * Depending on the mode the chip is configured in, the interface creation
+ * may fail (code: |WifiStatusCode.ERROR_NOT_AVAILABLE|) if we've already
+ * reached the maximum allowed (specified in |ChipIfaceCombination|) number
+ * of ifaces of the AP type.
+ *
+ * @return AIDL interface object representing the iface if
+ * successful, null otherwise.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|
+ */
+ @PropagateAllowBlocking IWifiApIface createBridgedApIface();
+
+ /**
+ * Create a NAN iface on the chip.
+ *
+ * Depending on the mode the chip is configured in, the interface creation
+ * may fail (code: |WifiStatusCode.ERROR_NOT_AVAILABLE|) if we've already
+ * reached the maximum allowed (specified in |ChipIfaceCombination|) number
+ * of ifaces of the NAN type.
+ *
+ * @return AIDL interface object representing the iface if
+ * successful, null otherwise.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|
+ */
+ @PropagateAllowBlocking IWifiNanIface createNanIface();
+
+ /**
+ * Create a P2P iface on the chip.
+ *
+ * Depending on the mode the chip is configured in, the interface creation
+ * may fail (code: |WifiStatusCode.ERROR_NOT_AVAILABLE|) if we've already
+ * reached the maximum allowed (specified in |ChipIfaceCombination|) number
+ * of ifaces of the P2P type.
+ *
+ * @return AIDL interface object representing the iface if
+ * successful, null otherwise.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|
+ */
+ @PropagateAllowBlocking IWifiP2pIface createP2pIface();
+
+ /**
+ * Create an RTTController instance.
+ *
+ * RTT controller can be either:
+ * a) Bound to a specific STA iface by passing in the corresponding
+ * |IWifiStaIface| object in the |boundIface| param, OR
+ * b) Let the implementation decide the iface to use for RTT operations
+ * by passing null in the |boundIface| param.
+ *
+ * @param boundIface AIDL interface object representing the STA iface if
+ * the responder must be bound to a specific iface, null otherwise.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|
+ */
+ @PropagateAllowBlocking IWifiRttController createRttController(in IWifiStaIface boundIface);
+
+ /**
+ * Create a STA iface on the chip.
+ *
+ * Depending on the mode the chip is configured in, the interface creation
+ * may fail (code: |WifiStatusCode.ERROR_NOT_AVAILABLE|) if we've already
+ * reached the maximum allowed (specified in |ChipIfaceCombination|) number
+ * of ifaces of the STA type.
+ *
+ * @return AIDL interface object representing the iface if
+ * successful, null otherwise.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|
+ */
+ @PropagateAllowBlocking IWifiStaIface createStaIface();
+
+ /**
+ * API to enable/disable alert notifications from the chip.
+ * These alerts must be used to notify the framework of any fatal error events
+ * that the chip encounters via |IWifiChipEventCallback.onDebugErrorAlert| method.
+ * Must fail if |ChipCapabilityMask.DEBUG_ERROR_ALERTS| is not set.
+ *
+ * @param enable true to enable, false to disable.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.NOT_AVAILABLE|,
+ * |WifiStatusCode.UNKNOWN|
+ */
+ void enableDebugErrorAlerts(in boolean enable);
+
+ /**
+ * API to flush debug ring buffer data to files.
+ *
+ * Force flush debug ring buffer using IBase::debug.
+ * This API helps to collect firmware/driver/pkt logs.
+ *
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.UNKNOWN|
+ */
+ void flushRingBufferToFile();
+
+ /**
+ * API to force dump data into the corresponding ring buffer.
+ * This is to be invoked during bugreport collection.
+ *
+ * @param ringName Name of the ring for which data collection should
+ * be forced. This can be retrieved via the corresponding
+ * |WifiDebugRingBufferStatus|.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.ERROR_NOT_STARTED|,
+ * |WifiStatusCode.NOT_AVAILABLE|,
+ * |WifiStatusCode.UNKNOWN|
+ */
+ void forceDumpToDebugRingBuffer(in String ringName);
+
+ /**
+ * Gets an AIDL interface object for the AP Iface corresponding
+ * to the provided ifname.
+ *
+ * @param ifname Name of the iface.
+ * @return AIDL interface object representing the iface if
+ * it exists, null otherwise.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+ * |WifiStatusCode.ERROR_INVALID_ARGS|
+ */
+ @PropagateAllowBlocking IWifiApIface getApIface(in String ifname);
+
+ /**
+ * List all the AP iface names configured on the chip.
+ * The corresponding |IWifiApIface| object for any iface
+ * can be retrieved using the |getApIface| method.
+ *
+ * @return List of all AP iface names on the chip.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|
+ */
+ String[] getApIfaceNames();
+
+ /**
+ * Get the set of operation modes that the chip supports.
+ *
+ * @return List of modes supported by the device.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|
+ */
+ ChipMode[] getAvailableModes();
+
+ /**
+ * Get the capabilities supported by this chip.
+ *
+ * @return Bitset of |ChipCapabilityMask| values.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ ChipCapabilityMask getCapabilities();
+
+ /**
+ * API to retrieve the wifi wake up reason stats for debugging.
+ * The driver is expected to start maintaining these stats once the chip
+ * is configured using |configureChip|. These stats must be reset whenever
+ * the chip is reconfigured or the HAL is stopped.
+ *
+ * @return Instance of |WifiDebugHostWakeReasonStats|.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.NOT_AVAILABLE|,
+ * |WifiStatusCode.UNKNOWN|
+ */
+ WifiDebugHostWakeReasonStats getDebugHostWakeReasonStats();
+
+ /**
+ * The WiFi debug ring buffer life cycle is as follows:
+ * - At initialization, the framework must call |getDebugRingBuffersStatus|.
+ * to obtain the names and list of supported ring buffers.
+ * The driver may expose several different rings, each holding a different
+ * type of data (connection events, power events, etc).
+ * - When WiFi operations start, the framework must call
+ * |startLoggingToDebugRingBuffer| to trigger log collection for a specific
+ * ring. The vebose level for each ring buffer can be specified in this API.
+ * - During wifi operations, the driver must periodically report per ring data
+ * to framework by invoking the
+ * |IWifiChipEventCallback.onDebugRingBufferDataAvailable| callback.
+ * - When capturing a bug report, the framework must indicate to driver that
+ * all the data has to be uploaded urgently by calling |forceDumpToDebugRingBuffer|.
+ *
+ * The data uploaded by driver must be stored by the framework in separate files,
+ * with one stream of file per ring. The framework must store the files in pcapng
+ * format, allowing for easy merging and parsing with network analyzer tools.
+ * TODO: Since we're no longer dumping the raw data, storing in separate
+ * pcapng files for parsing later must not work anymore.
+ */
+
+ /*
+ * API to get the status of all ring buffers supported by driver.
+ *
+ * @return Vector of |WifiDebugRingBufferStatus| corresponding to the
+ * status of each ring buffer on the device.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.NOT_AVAILABLE|,
+ * |WifiStatusCode.UNKNOWN|
+ */
+ WifiDebugRingBufferStatus[] getDebugRingBuffersStatus();
+
+ /**
+ * Get the Id assigned to this chip.
+ *
+ * @return Assigned chip Id.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|
+ */
+ int getId();
+
+ /**
+ * Get the current mode that the chip is in.
+ *
+ * @return Mode that the chip is currently configured to,
+ * corresponding to the Id property of the target ChipMode.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|
+ */
+ int getMode();
+
+ /**
+ * Gets an AIDL interface object for the NAN Iface corresponding
+ * to the provided ifname.
+ *
+ * @param ifname Name of the iface.
+ * @return AIDL interface object representing the iface if
+ * it exists, null otherwise.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+ * |WifiStatusCode.ERROR_INVALID_ARGS|
+ */
+ @PropagateAllowBlocking IWifiNanIface getNanIface(in String ifname);
+
+ /**
+ * List all the NAN iface names configured on the chip.
+ * The corresponding |IWifiNanIface| object for any iface can
+ * be retrieved using the |getNanIface| method.
+ *
+ * @return List of all NAN iface names on the chip.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|
+ */
+ String[] getNanIfaceNames();
+
+ /**
+ * Gets an AIDL interface object for the P2P Iface corresponding
+ * to the provided ifname.
+ *
+ * @param ifname Name of the iface.
+ * @return AIDL interface object representing the iface if
+ * it exists, null otherwise.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+ * |WifiStatusCode.ERROR_INVALID_ARGS|
+ */
+ @PropagateAllowBlocking IWifiP2pIface getP2pIface(in String ifname);
+
+ /**
+ * List all the P2P iface names configured on the chip.
+ * The corresponding |IWifiP2pIface| object for any iface can
+ * be retrieved using the |getP2pIface| method.
+ *
+ * @return List of all P2P iface names on the chip.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|
+ */
+ String[] getP2pIfaceNames();
+
+ /**
+ * Gets an AIDL interface object for the STA Iface corresponding
+ * to the provided ifname.
+ *
+ * @param ifname Name of the iface.
+ * @return AIDL interface object representing the iface if
+ * it exists, null otherwise.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+ * |WifiStatusCode.ERROR_INVALID_ARGS|
+ */
+ @PropagateAllowBlocking IWifiStaIface getStaIface(in String ifname);
+
+ /**
+ * List all the STA iface names configured on the chip.
+ * The corresponding |IWifiStaIface| object for any iface can
+ * be retrieved using the |getStaIface| method.
+ *
+ * @param List of all STA iface names on the chip.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|
+ */
+ String[] getStaIfaceNames();
+
+ /**
+ * Retrieve the list of all the possible radio combinations supported by this
+ * chip.
+ *
+ * @return A list of all the possible radio combinations represented by
+ * |WifiRadioCombinationMatrix|.
+ * For example, in case of a chip which has two radios, where one radio is
+ * capable of 2.4GHz 2X2 only and another radio which is capable of either
+ * 5GHz or 6GHz 2X2, the number of possible radio combinations in this case
+ * is 5 and the possible combinations are:
+ * {{{2G 2X2}}, //Standalone 2G
+ * {{5G 2X2}}, //Standalone 5G
+ * {{6G 2X2}}, //Standalone 6G
+ * {{2G 2X2}, {5G 2X2}}, //2G+5G DBS
+ * {{2G 2X2}, {6G 2X2}}} //2G+6G DBS
+ * Note: Since this chip doesn’t support 5G+6G simultaneous operation,
+ * as there is only one radio which can support both bands, it can only
+ * do MCC 5G+6G. This table should not get populated with possible MCC
+ * configurations. This is only for simultaneous radio configurations
+ * (such as standalone, multi band simultaneous or single band simultaneous).
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.FAILURE_UNKNOWN|
+ *
+ */
+ WifiRadioCombinationMatrix getSupportedRadioCombinationsMatrix();
+
+ /**
+ * Retrieve a list of usable Wifi channels for the specified band &
+ * operational modes.
+ *
+ * The list of usable Wifi channels in a given band depends on factors
+ * like current country code, operational mode (e.g. STA, SAP, WFD-CLI,
+ * WFD-GO, TDLS, NAN) and other restrictons due to DFS, cellular coexistence
+ * and concurrency state of the device.
+ *
+ * @param band |WifiBand| for which list of usable channels is requested.
+ * @param ifaceModeMask Bitmask of the modes represented by |WifiIfaceMode|.
+ * Bitmask respresents all the modes that the caller is interested
+ * in (e.g. STA, SAP, CLI, GO, TDLS, NAN). E.g. If the caller is
+ * interested in knowing usable channels for P2P CLI, P2P GO & NAN,
+ * ifaceModeMask would be set to
+ * IFACE_MODE_P2P_CLIENT|IFACE_MODE_P2P_GO|IFACE_MODE_NAN.
+ * @param filterMask Bitmask of filters represented by
+ * |UsableChannelFilter|. Specifies whether driver should filter
+ * channels based on additional criteria. If no filter is specified,
+ * then the driver should return usable channels purely based on
+ * regulatory constraints.
+ * @return List of channels represented by |WifiUsableChannel|.
+ * Each entry represents a channel frequency, bandwidth and
+ * bitmask of modes (e.g. STA, SAP, CLI, GO, TDLS, NAN) that are
+ * allowed on that channel. E.g. If only STA mode can be supported
+ * on an indoor channel, only the IFACE_MODE_STA bit would be set
+ * for that channel. If 5GHz SAP cannot be supported, then none of
+ * the 5GHz channels will have IFACE_MODE_SOFTAP bit set.
+ * Note: Bits do not represent concurrency state. Each bit only
+ * represents whether a particular mode is allowed on that channel.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.ERROR_INVALID_ARGS|,
+ * |WifiStatusCode.FAILURE_UNKNOWN|
+ */
+ WifiUsableChannel[] getUsableChannels(
+ in WifiBand band, in WifiIfaceMode ifaceModeMask, in UsableChannelFilter filterMask);
+
+ /**
+ * Requests notifications of significant events on this chip. Multiple calls
+ * to this must register multiple callbacks, each of which must receive all
+ * events.
+ *
+ * @param callback An instance of the |IWifiChipEventCallback| AIDL interface
+ * object.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|
+ */
+ void registerEventCallback(in IWifiChipEventCallback callback);
+
+ /**
+ * Removes the AP Iface with the provided ifname.
+ * Any further calls on the corresponding |IWifiApIface| AIDL interface
+ * object must fail.
+ *
+ * @param ifname Name of the iface.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+ * |WifiStatusCode.ERROR_INVALID_ARGS|
+ */
+ void removeApIface(in String ifname);
+
+ /**
+ * Removes an instance of AP iface with name |ifaceInstanceName| from the
+ * bridge AP with name |brIfaceName|.
+ *
+ * Use the API |removeApIface| with the brIfaceName to remove the bridge iface.
+ *
+ * @param brIfaceName Name of the bridged AP iface.
+ * @param ifaceInstanceName Name of the AP instance. The empty instance is
+ * invalid.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+ * |WifiStatusCode.ERROR_INVALID_ARGS|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|
+ */
+ void removeIfaceInstanceFromBridgedApIface(in String brIfaceName, in String ifaceInstanceName);
+
+ /**
+ * Removes the NAN Iface with the provided ifname.
+ * Any further calls on the corresponding |IWifiNanIface| AIDL interface
+ * object must fail.
+ *
+ * @param ifname Name of the iface.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+ * |WifiStatusCode.ERROR_INVALID_ARGS|
+ */
+ void removeNanIface(in String ifname);
+
+ /**
+ * Removes the P2P Iface with the provided ifname.
+ * Any further calls on the corresponding |IWifiP2pIface| AIDL interface
+ * object must fail.
+ *
+ * @param ifname Name of the iface.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+ * |WifiStatusCode.ERROR_INVALID_ARGS|
+ */
+ void removeP2pIface(in String ifname);
+
+ /**
+ * Removes the STA Iface with the provided ifname.
+ * Any further calls on the corresponding |IWifiStaIface| AIDL interface
+ * object must fail.
+ *
+ * @param ifname Name of the iface.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+ * |WifiStatusCode.ERROR_INVALID_ARGS|
+ */
+ void removeStaIface(in String ifname);
+
+ /**
+ * Request information about the chip.
+ *
+ * @return Instance of |ChipDebugInfo|.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ ChipDebugInfo requestChipDebugInfo();
+
+ /**
+ * Request vendor debug info from the driver.
+ *
+ * @return Vector of bytes retrieved from the driver.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ byte[] requestDriverDebugDump();
+
+ /**
+ * Request vendor debug info from the firmware.
+ *
+ * @return Vector of bytes retrieved from the firmware.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ byte[] requestFirmwareDebugDump();
+
+ /**
+ * API to reset TX power levels.
+ * This is used to indicate the end of the previously selected TX power
+ * scenario and let the wifi chip fall back to the default power values.
+ *
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.NOT_AVAILABLE|,
+ * |WifiStatusCode.UNKNOWN|
+ */
+ void resetTxPowerScenario();
+
+ /**
+ * API to select one of the preset TX power scenarios.
+ *
+ * The framework must invoke this method with the appropriate scenario to let
+ * the wifi chip change its transmitting power levels.
+ * OEM's should define various power profiles for each of the scenarios
+ * above (defined in |TxPowerScenario|) in a vendor extension.
+ *
+ * @param scenario One of the preselected scenarios defined in
+ * |TxPowerScenario|.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.NOT_AVAILABLE|,
+ * |WifiStatusCode.UNKNOWN|
+ */
+ void selectTxPowerScenario(in TxPowerScenario scenario);
+
+ /**
+ * Invoked to indicate that the provided |CoexUnsafeChannels| should be avoided with the
+ * specified restrictions.
+ *
+ * Channel avoidance is a suggestion and should be done on a best-effort approach. If a provided
+ * channel is used, then the specified power cap should be applied.
+ *
+ * In addition, hard restrictions on the Wifi modes may be indicated by |CoexRestriction| bits
+ * (WIFI_DIRECT, SOFTAP, WIFI_AWARE) in the |restrictions| bitfield. If a hard restriction is
+ * provided, then the channels should be completely avoided for the provided Wifi modes instead
+ * of by best-effort.
+ *
+ * @param unsafeChannels List of |CoexUnsafeChannels| to avoid.
+ * @param restrictions Bitset of |CoexRestriction| values indicating Wifi interfaces to
+ * completely avoid.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+ * |WifiStatusCode.ERROR_INVALID_ARGS|,
+ */
+ void setCoexUnsafeChannels(
+ in CoexUnsafeChannel[] unsafeChannels, in CoexRestriction restrictions);
+
+ /**
+ * Set country code for this Wifi chip.
+ *
+ * Country code is global setting across the Wifi chip and not Wifi
+ * interface (STA or AP) specific.
+ *
+ * @param code 2 byte country code (as defined in ISO 3166) to set.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.FAILURE_UNKNOWN|,
+ * |WifiStatusCode.FAILURE_IFACE_INVALID|
+ */
+ void setCountryCode(in byte[2] code);
+
+ /**
+ * API to set the wifi latency mode
+ *
+ * The latency mode is a hint to the HAL to enable or disable Wi-Fi latency
+ * optimization. The optimization should be enabled if the mode is set to |LOW|
+ * and should be disabled if the mode is set to |NORMAL|.
+ * Wi-Fi latency optimization may trade-off latency against other Wi-Fi
+ * functionality such as scanning, roaming, etc. but it should not result in
+ * completely halting this functionality.
+ *
+ * The low latency mode targets applications such as gaming and virtual reality.
+ */
+ void setLatencyMode(in LatencyMode mode);
+
+ /**
+ * Invoked to indicate that the provided iface is the primary STA iface when more
+ * than 1 STA ifaces are concurrently active.
+ * Notes:
+ * - If the wifi firmware/chip cannot support multiple instances of any offload
+ * (like roaming, APF, rssi threshold, etc), the firmware should ensure that these
+ * offloads are at least enabled for the primary interface. If the new primary interface is
+ * already connected to a network, the firmware must switch all the offloads on
+ * this new interface without disconnecting.
+ * - When there is only 1 STA interface, the firmware must still retain the last primary
+ * connection, which must become active the next time multi STA is enabled.
+ *
+ * @param ifname Name of the STA iface.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+ * |WifiStatusCode.ERROR_INVALID_ARGS|
+ */
+ void setMultiStaPrimaryConnection(in String ifName);
+
+ /**
+ * Invoked to indicate the STA + STA use-case that is active.
+ *
+ * Refer to documentation of |MultiStaUseCase| for details.
+ *
+ * @param useCase Use case that is active.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+ * |WifiStatusCode.ERROR_INVALID_ARGS|
+ */
+ void setMultiStaUseCase(in MultiStaUseCase useCase);
+
+ /**
+ * API to trigger the debug data collection.
+ *
+ * @param ringName Name of the ring for which data collection
+ * shall start. This can be retrieved via the corresponding
+ * |WifiDebugRingBufferStatus|.
+ * @param verboseLevel Verbose level for logging.
+ * @parm maxIntervalInSec Maximum interval in seconds for driver to invoke
+ * |onDebugRingBufferData|, ignore if zero.
+ * @parm minDataSizeInBytes: Minimum data size in buffer for driver to invoke
+ * |onDebugRingBufferData|, ignore if zero.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.NOT_AVAILABLE|,
+ * |WifiStatusCode.UNKNOWN|
+ */
+ void startLoggingToDebugRingBuffer(in String ringName,
+ in WifiDebugRingBufferVerboseLevel verboseLevel, in int maxIntervalInSec,
+ in int minDataSizeInBytes);
+
+ /**
+ * API to stop the debug data collection for all ring buffers.
+ *
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.NOT_AVAILABLE|,
+ * |WifiStatusCode.UNKNOWN|
+ */
+ void stopLoggingToDebugRingBuffer();
+
+ /**
+ * Trigger subsystem restart.
+ *
+ * If the framework detects a problem (e.g. connection failure),
+ * it must call this function to attempt recovery.
+ *
+ * When the wifi HAL receives |triggerSubsystemRestart|, it must restart
+ * the wlan subsystem, especially the wlan firmware.
+ *
+ * Regarding the callback function for subsystem restart, refer to documentation of
+ * |IWifiEventCallback.onSubsystemRestart| for details.
+ *
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ void triggerSubsystemRestart();
+}
diff --git a/wifi/aidl/android/hardware/wifi/IWifiChipEventCallback.aidl b/wifi/aidl/android/hardware/wifi/IWifiChipEventCallback.aidl
new file mode 100644
index 0000000..2bc4c0e
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/IWifiChipEventCallback.aidl
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.IfaceType;
+import android.hardware.wifi.WifiBand;
+import android.hardware.wifi.WifiDebugRingBufferStatus;
+import android.hardware.wifi.WifiStatusCode;
+
+/**
+ * Wifi chip event callbacks.
+ */
+@VintfStability
+oneway interface IWifiChipEventCallback {
+ /**
+ * Struct describing the state of each iface operating on the radio chain
+ * (hardware MAC) on the device.
+ */
+ @VintfStability
+ parcelable IfaceInfo {
+ /**
+ * Name of the interface (ex. wlan0).
+ */
+ String name;
+ /**
+ * Wifi channel on which this interface is operating.
+ */
+ int channel;
+ }
+
+ /**
+ * Struct describing the state of each hardware radio chain (hardware MAC)
+ * on the device.
+ */
+ @VintfStability
+ parcelable RadioModeInfo {
+ /**
+ * Identifier for this radio chain. This is vendor dependent and used
+ * only for debugging purposes.
+ */
+ int radioId;
+ /**
+ * List of bands on which this radio chain is operating.
+ * Can be one of:
+ * a) |WifiBand.BAND_24GHZ| => 2.4Ghz.
+ * b) |WifiBand.BAND_5GHZ| => 5Ghz.
+ * c) |WifiBand.BAND_24GHZ_5GHZ| => 2.4Ghz + 5Ghz (Radio is time sharing
+ * across the 2 bands).
+ * d) |WifiBand.BAND_6GHZ| => 6Ghz.
+ * e) |WifiBand.BAND_5GHZ_6GHZ| => 5Ghz + 6Ghz (Radio is time sharing
+ * across the 2 bands).
+ * f) |WifiBand.BAND_24GHZ_5GHZ_6GHZ| => 2.4Ghz + 5Ghz + 6Ghz (Radio is
+ * time sharing across the 3 bands).
+ */
+ WifiBand bandInfo;
+ /**
+ * List of interfaces on this radio chain (hardware MAC).
+ */
+ IfaceInfo[] ifaceInfos;
+ }
+
+ /**
+ * Callback indicating that a chip reconfiguration failed. This is a fatal
+ * error and any iface objects available previously must be considered
+ * invalid. The client can attempt to recover by trying to reconfigure the
+ * chip again using |IWifiChip.configureChip|.
+ *
+ * @param status Failure reason code.
+ */
+ void onChipReconfigureFailure(in WifiStatusCode status);
+
+ /**
+ * Callback indicating that the chip has been reconfigured successfully. At
+ * this point the interfaces available in the mode must be able to be
+ * configured. When this is called, any previous iface objects must be
+ * considered invalid.
+ *
+ * @param modeId The mode that the chip switched to, corresponding to the id
+ * property of the target ChipMode.
+ */
+ void onChipReconfigured(in int modeId);
+
+ /**
+ * Callback indicating that the chip has encountered a fatal error.
+ * Client must not attempt to parse either the errorCode or debugData.
+ * Must only be captured in a bugreport.
+ *
+ * @param errorCode Vendor defined error code.
+ * @param debugData Vendor defined data used for debugging.
+ */
+ void onDebugErrorAlert(in int errorCode, in byte[] debugData);
+
+ /**
+ * Callbacks for reporting debug ring buffer data.
+ *
+ * The ring buffer data collection is event based:
+ * - Driver calls this callback when new records are available, the
+ * |WifiDebugRingBufferStatus| passed up to framework in the callback
+ * indicates to framework if more data is available in the ring buffer.
+ * It is not expected that driver will necessarily always empty the ring
+ * immediately as data is available. Instead the driver will report data
+ * every X seconds, or if N bytes are available, based on the parameters
+ * set via |startLoggingToDebugRingBuffer|.
+ * - In the case where a bug report has to be captured, the framework will
+ * require driver to upload all data immediately. This is indicated to
+ * driver when framework calls |forceDumpToDebugRingBuffer|. The driver
+ * will start sending all available data in the indicated ring by repeatedly
+ * invoking this callback.
+ *
+ * @param status Status of the corresponding ring buffer. This should
+ * contain the name of the ring buffer on which the data is
+ * available.
+ * @param data Raw bytes of data sent by the driver. Must be dumped
+ * out to a bugreport and post processed.
+ */
+ void onDebugRingBufferDataAvailable(in WifiDebugRingBufferStatus status, in byte[] data);
+
+ /**
+ * Callback indicating that a new iface has been added to the chip.
+ *
+ * @param type Type of iface added.
+ * @param name Name of iface added.
+ */
+ void onIfaceAdded(in IfaceType type, in String name);
+
+ /**
+ * Callback indicating that an existing iface has been removed from the chip.
+ *
+ * @param type Type of iface removed.
+ * @param name Name of iface removed.
+ */
+ void onIfaceRemoved(in IfaceType type, in String name);
+
+ /**
+ * Indicates a radio mode change.
+ * Radio mode change could be a result of:
+ * a) Bringing up concurrent interfaces (ex. STA + AP).
+ * b) Change in operating band of one of the concurrent interfaces
+ * ( ex. STA connection moved from 2.4G to 5G)
+ *
+ * @param radioModeInfos List of RadioModeInfo structures for each
+ * radio chain (hardware MAC) on the device.
+ */
+ void onRadioModeChange(in RadioModeInfo[] radioModeInfos);
+}
diff --git a/wifi/aidl/android/hardware/wifi/IWifiEventCallback.aidl b/wifi/aidl/android/hardware/wifi/IWifiEventCallback.aidl
new file mode 100644
index 0000000..761bbf5
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/IWifiEventCallback.aidl
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.WifiStatusCode;
+
+@VintfStability
+oneway interface IWifiEventCallback {
+ /**
+ * Called when the Wi-Fi system failed in a way that caused it be disabled.
+ * Calling start again must restart Wi-Fi as if stop then start was called
+ * (full state reset). When this event is received all IWifiChip & IWifiIface
+ * objects retrieved after the last call to start will be considered invalid.
+ *
+ * @param status Failure reason code.
+ */
+ void onFailure(in WifiStatusCode status);
+
+ /**
+ * Called in response to a call to start indicating that the operation
+ * completed. After this callback the HAL must be fully operational.
+ */
+ void onStart();
+
+ /**
+ * Called in response to a call to stop indicating that the operation
+ * completed. When this event is received all IWifiChip objects retrieved
+ * after the last call to start will be considered invalid.
+ */
+ void onStop();
+
+ /**
+ * Must be called when the Wi-Fi subsystem restart completes.
+ * Once this event is received, framework must fully reset the Wi-Fi stack state.
+ *
+ * @param status Status code.
+ */
+ void onSubsystemRestart(in WifiStatusCode status);
+}
diff --git a/wifi/aidl/android/hardware/wifi/IWifiNanIface.aidl b/wifi/aidl/android/hardware/wifi/IWifiNanIface.aidl
new file mode 100644
index 0000000..45644b4
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/IWifiNanIface.aidl
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.IWifiNanIfaceEventCallback;
+import android.hardware.wifi.NanConfigRequest;
+import android.hardware.wifi.NanConfigRequestSupplemental;
+import android.hardware.wifi.NanEnableRequest;
+import android.hardware.wifi.NanInitiateDataPathRequest;
+import android.hardware.wifi.NanPublishRequest;
+import android.hardware.wifi.NanRespondToDataPathIndicationRequest;
+import android.hardware.wifi.NanSubscribeRequest;
+import android.hardware.wifi.NanTransmitFollowupRequest;
+
+/**
+ * Interface used to represent a single NAN (Neighbour Aware Network) iface.
+ *
+ * References to "NAN Spec" are to the Wi-Fi Alliance "Wi-Fi Neighbor Awareness
+ * Networking (NAN) Technical Specification".
+ */
+@VintfStability
+interface IWifiNanIface {
+ /**
+ * Minimum length of Passphrase argument for a data-path configuration.
+ */
+ const int MIN_DATA_PATH_CONFIG_PASSPHRASE_LENGTH = 8;
+
+ /**
+ * Maximum length of Passphrase argument for a data-path configuration.
+ */
+ const int MAX_DATA_PATH_CONFIG_PASSPHRASE_LENGTH = 63;
+
+ /**
+ * Get the name of this iface.
+ *
+ * @return Name of this iface.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|
+ */
+ String getName();
+
+ /**
+ * Configures an existing NAN functionality (i.e. assumes
+ * |IWifiNanIface.enableRequest| already submitted and succeeded).
+ * Asynchronous response is with |IWifiNanIfaceEventCallback.notifyConfigResponse|.
+ *
+ * @param cmdId Command Id to use for this invocation.
+ * @param msg1 Instance of |NanConfigRequest|.
+ * @param msg2 Instance of |NanConfigRequestSupplemental|.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_INVALID_ARGS|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ void configRequest(
+ in char cmdId, in NanConfigRequest msg1, in NanConfigRequestSupplemental msg2);
+
+ /**
+ * Create a NAN Data Interface.
+ * Asynchronous response is with |IWifiNanIfaceEventCallback.notifyCreateDataInterfaceResponse|.
+ *
+ * @param cmdId Command Id to use for this invocation.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ void createDataInterfaceRequest(in char cmdId, in String ifaceName);
+
+ /**
+ * Delete a NAN Data Interface.
+ * Asynchronous response is with |IWifiNanIfaceEventCallback.notifyDeleteDataInterfaceResponse|.
+ *
+ * @param cmdId Command Id to use for this invocation.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ void deleteDataInterfaceRequest(in char cmdId, in String ifaceName);
+
+ /**
+ * Disable NAN functionality.
+ * Asynchronous response is with |IWifiNanIfaceEventCallback.notifyDisableResponse|.
+ *
+ * @param cmdId Command Id to use for this invocation.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ void disableRequest(in char cmdId);
+
+ /**
+ * Configures and activates NAN clustering (does not start
+ * a discovery session or set up data-interfaces or data-paths). Use the
+ * |IWifiNanIface.configureRequest| method to change the configuration of an already enabled
+ * NAN interface.
+ * Asynchronous response is with |IWifiNanIfaceEventCallback.notifyEnableResponse|.
+ *
+ * @param cmdId Command Id to use for this invocation.
+ * @param msg1 Instance of |NanEnableRequest|.
+ * @param msg2 Instance of |NanConfigRequestSupplemental|.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_INVALID_ARGS|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ void enableRequest(
+ in char cmdId, in NanEnableRequest msg1, in NanConfigRequestSupplemental msg2);
+
+ /**
+ * Get NAN capabilities. Asynchronous response is with
+ * |IWifiNanIfaceEventCallback.notifyCapabilitiesResponse|.
+ *
+ * @param cmdId Command Id to use for this invocation.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ void getCapabilitiesRequest(in char cmdId);
+
+ /**
+ * Initiate a data-path (NDP) setup operation: Initiator.
+ * Asynchronous response is with |IWifiNanIfaceEventCallback.notifyInitiateDataPathResponse|.
+ *
+ * @param cmdId Command Id to use for this invocation.
+ * @param msg Instance of |NanInitiateDataPathRequest|.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_INVALID_ARGS|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ void initiateDataPathRequest(in char cmdId, in NanInitiateDataPathRequest msg);
+
+ /**
+ * Requests notifications of significant events on this iface. Multiple calls
+ * to this must register multiple callbacks, each of which must receive all
+ * events.
+ *
+ * @param callback An instance of the |IWifiNanIfaceEventCallback| AIDL interface
+ * object.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|
+ */
+ void registerEventCallback(in IWifiNanIfaceEventCallback callback);
+
+ /**
+ * Respond to a received data indication as part of a data-path (NDP) setup operation.
+ * An indication is received by the Responder from the Initiator.
+ * Asynchronous response is with
+ * |IWifiNanIfaceEventCallback.notifyRespondToDataPathIndicationResponse|.
+ *
+ * @param cmdId Command Id to use for this invocation.
+ * @param msg Instance of |NanRespondToDataPathIndicationRequest|.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_INVALID_ARGS|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ void respondToDataPathIndicationRequest(
+ in char cmdId, in NanRespondToDataPathIndicationRequest msg);
+
+ /**
+ * Publish request to start advertising a discovery service.
+ * Asynchronous response is with |IWifiNanIfaceEventCallback.notifyStartPublishResponse|.
+ *
+ * @param cmdId Command Id to use for this invocation.
+ * @param msg Instance of |NanPublishRequest|.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_INVALID_ARGS|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ void startPublishRequest(in char cmdId, in NanPublishRequest msg);
+
+ /**
+ * Subscribe request to start searching for a discovery service.
+ * Asynchronous response is with |IWifiNanIfaceEventCallback.notifyStartSubscribeResponse|.
+ *
+ * @param cmdId Command Id to use for this invocation.
+ * @param msg Instance of |NanSubscribeRequest|.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_INVALID_ARGS|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ void startSubscribeRequest(in char cmdId, in NanSubscribeRequest msg);
+
+ /**
+ * Stop publishing a discovery service.
+ * Asynchronous response is with |IWifiNanIfaceEventCallback.notifyStopPublishResponse|.
+ *
+ * @param cmdId Command Id to use for this invocation.
+ * @param sessionId ID of the publish discovery session to be stopped.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ void stopPublishRequest(in char cmdId, in byte sessionId);
+
+ /**
+ * Stop subscribing to a discovery service.
+ * Asynchronous response is with |IWifiNanIfaceEventCallback.notifyStopSubscribeResponse|.
+ *
+ * @param cmdId Command Id to use for this invocation.
+ * @param sessionId ID of the subscribe discovery session to be stopped.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ void stopSubscribeRequest(in char cmdId, in byte sessionId);
+
+ /**
+ * Data-path (NDP) termination request. Executed by either Initiator or Responder.
+ * Asynchronous response is with |IWifiNanIfaceEventCallback.notifyTerminateDataPathResponse|.
+ *
+ * @param cmdId Command Id to use for this invocation.
+ * @param ndpInstanceId Data-path instance ID to be terminated.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ void terminateDataPathRequest(in char cmdId, in int ndpInstanceId);
+
+ /**
+ * NAN transmit follow up message request.
+ * Asynchronous response is with |IWifiNanIfaceEventCallback.notifyTransmitFollowupResponse|.
+ *
+ * @param cmdId Command Id to use for this invocation.
+ * @param msg Instance of |NanTransmitFollowupRequest|.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_INVALID_ARGS|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ void transmitFollowupRequest(in char cmdId, in NanTransmitFollowupRequest msg);
+}
diff --git a/wifi/aidl/android/hardware/wifi/IWifiNanIfaceEventCallback.aidl b/wifi/aidl/android/hardware/wifi/IWifiNanIfaceEventCallback.aidl
new file mode 100644
index 0000000..470b7ba
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/IWifiNanIfaceEventCallback.aidl
@@ -0,0 +1,322 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.NanCapabilities;
+import android.hardware.wifi.NanClusterEventInd;
+import android.hardware.wifi.NanDataPathConfirmInd;
+import android.hardware.wifi.NanDataPathRequestInd;
+import android.hardware.wifi.NanDataPathScheduleUpdateInd;
+import android.hardware.wifi.NanFollowupReceivedInd;
+import android.hardware.wifi.NanMatchInd;
+import android.hardware.wifi.NanStatus;
+
+/**
+ * NAN Response and Asynchronous Event Callbacks.
+ *
+ * References to "NAN Spec" are to the Wi-Fi Alliance "Wi-Fi Neighbor Awareness
+ * Networking (NAN) Technical Specification".
+ */
+@VintfStability
+oneway interface IWifiNanIfaceEventCallback {
+ /**
+ * Callback indicating that a cluster event has been received.
+ *
+ * @param event NanClusterEventInd containing event details.
+ */
+ void eventClusterEvent(in NanClusterEventInd event);
+
+ /**
+ * Callback indicating that a data-path (NDP) setup has been completed.
+ * Received by both Initiator and Responder.
+ *
+ * @param event NanDataPathConfirmInd containing event details.
+ */
+ void eventDataPathConfirm(in NanDataPathConfirmInd event);
+
+ /**
+ * Callback indicating that a data-path (NDP) setup has been requested by
+ * an Initiator peer (received by the intended Responder).
+ *
+ * @param event NanDataPathRequestInd containing event details.
+ */
+ void eventDataPathRequest(in NanDataPathRequestInd event);
+
+ /**
+ * Callback indicating that a data-path (NDP) schedule has been updated
+ * (e.g. channels have been changed).
+ *
+ * @param event NanDataPathScheduleUpdateInd containing event details.
+ */
+ void eventDataPathScheduleUpdate(in NanDataPathScheduleUpdateInd event);
+
+ /**
+ * Callback indicating that a list of data-paths (NDP) have been terminated.
+ * Received by both Initiator and Responder.
+ *
+ * @param ndpInstanceId Data-path ID of the terminated data-path.
+ */
+ void eventDataPathTerminated(in int ndpInstanceId);
+
+ /**
+ * Callback indicating that a NAN has been disabled.
+ *
+ * @param status NanStatus describing the reason for the disable event.
+ * Possible status codes are:
+ * |NanStatusCode.SUCCESS|
+ * |NanStatusCode.UNSUPPORTED_CONCURRENCY_NAN_DISABLED|
+ */
+ void eventDisabled(in NanStatus status);
+
+ /**
+ * Callback indicating that a followup message has been received from a peer.
+ *
+ * @param event NanFollowupReceivedInd containing event details.
+ */
+ void eventFollowupReceived(in NanFollowupReceivedInd event);
+
+ /**
+ * Callback indicating that a match has occurred: i.e. a service has been
+ * discovered.
+ *
+ * @param event NanMatchInd containing event details.
+ */
+ void eventMatch(in NanMatchInd event);
+
+ /**
+ * Callback indicating that a previously discovered match (service) has expired.
+ *
+ * @param discoverySessionId Discovery session ID of the expired match.
+ * @param peerId Peer ID of the expired match.
+ */
+ void eventMatchExpired(in byte discoverySessionId, in int peerId);
+
+ /**
+ * Callback indicating that an active publish session has terminated.
+ *
+ * @param sessionId Discovery session ID of the terminated session.
+ * @param status NanStatus describing the reason for the session termination.
+ * Possible status codes are:
+ * |NanStatusCode.SUCCESS|
+ */
+ void eventPublishTerminated(in byte sessionId, in NanStatus status);
+
+ /**
+ * Callback indicating that an active subscribe session has terminated.
+ *
+ * @param sessionId Discovery session ID of the terminated session.
+ * @param status NanStatus describing the reason for the session termination.
+ * Possible status codes are:
+ * |NanStatusCode.SUCCESS|
+ */
+ void eventSubscribeTerminated(in byte sessionId, in NanStatus status);
+
+ /**
+ * Callback providing status on a completed followup message transmit operation.
+ *
+ * @param cmdId Command Id corresponding to the original |transmitFollowupRequest| request.
+ * @param status NanStatus of the operation. Possible status codes are:
+ * |NanStatusCode.SUCCESS|
+ * |NanStatusCode.NO_OTA_ACK|
+ * |NanStatusCode.PROTOCOL_FAILURE|
+ */
+ void eventTransmitFollowup(in char id, in NanStatus status);
+
+ /**
+ * Callback invoked in response to a capability request
+ * |IWifiNanIface.getCapabilitiesRequest|.
+ *
+ * @param cmdId Command Id corresponding to the original request.
+ * @param status NanStatus of the operation. Possible status codes are:
+ * |NanStatusCode.SUCCESS|
+ * @param capabilities Capability data.
+ */
+ void notifyCapabilitiesResponse(
+ in char id, in NanStatus status, in NanCapabilities capabilities);
+
+ /**
+ * Callback invoked in response to a config request |IWifiNanIface.configRequest|.
+ *
+ * @param cmdId Command Id corresponding to the original request.
+ * @param status NanStatus of the operation. Possible status codes are:
+ * |NanStatusCode.SUCCESS|
+ * |NanStatusCode.INVALID_ARGS|
+ * |NanStatusCode.INTERNAL_FAILURE|
+ * |NanStatusCode.PROTOCOL_FAILURE|
+ */
+ void notifyConfigResponse(in char id, in NanStatus status);
+
+ /**
+ * Callback invoked in response to a create data interface request
+ * |IWifiNanIface.createDataInterfaceRequest|.
+ *
+ * @param cmdId Command Id corresponding to the original request.
+ * @param status NanStatus of the operation. Possible status codes are:
+ * |NanStatusCode.SUCCESS|
+ * |NanStatusCode.INVALID_ARGS|
+ * |NanStatusCode.INTERNAL_FAILURE|
+ */
+ void notifyCreateDataInterfaceResponse(in char id, in NanStatus status);
+
+ /**
+ * Callback invoked in response to a delete data interface request
+ * |IWifiNanIface.deleteDataInterfaceRequest|.
+ *
+ * @param cmdId Command Id corresponding to the original request.
+ * @param status NanStatus of the operation. Possible status codes are:
+ * |NanStatusCode.SUCCESS|
+ * |NanStatusCode.INVALID_ARGS|
+ * |NanStatusCode.INTERNAL_FAILURE|
+ */
+ void notifyDeleteDataInterfaceResponse(in char id, in NanStatus status);
+
+ /**
+ * Callback invoked in response to a disable request |IWifiNanIface.disableRequest|.
+ *
+ * @param cmdId Command Id corresponding to the original request.
+ * @param status NanStatus of the operation. Possible status codes are:
+ * |NanStatusCode.SUCCESS|
+ * |NanStatusCode.PROTOCOL_FAILURE|
+ */
+ void notifyDisableResponse(in char id, in NanStatus status);
+
+ /**
+ * Callback invoked in response to an enable request |IWifiNanIface.enableRequest|.
+ *
+ * @param cmdId Command Id corresponding to the original request.
+ * @param status NanStatus of the operation. Possible status codes are:
+ * |NanStatusCode.SUCCESS|
+ * |NanStatusCode.ALREADY_ENABLED|
+ * |NanStatusCode.INVALID_ARGS|
+ * |NanStatusCode.INTERNAL_FAILURE|
+ * |NanStatusCode.PROTOCOL_FAILURE|
+ * |NanStatusCode.NAN_NOT_ALLOWED|
+ */
+ void notifyEnableResponse(in char id, in NanStatus status);
+
+ /**
+ * Callback invoked in response to an initiate data path request
+ * |IWifiNanIface.initiateDataPathRequest|.
+ *
+ * @param cmdId Command Id corresponding to the original request.
+ * @param status NanStatus of the operation. Possible status codes are:
+ * |NanStatusCode.SUCCESS|
+ * |NanStatusCode.INVALID_ARGS|
+ * |NanStatusCode.INTERNAL_FAILURE|
+ * |NanStatusCode.PROTOCOL_FAILURE|
+ * |NanStatusCode.INVALID_PEER_ID|
+ * @param ndpInstanceId ID of the new data path being negotiated (on successful status).
+ */
+ void notifyInitiateDataPathResponse(in char id, in NanStatus status, in int ndpInstanceId);
+
+ /**
+ * Callback invoked in response to a respond to data path indication request
+ * |IWifiNanIface.respondToDataPathIndicationRequest|.
+ *
+ * @param cmdId Command Id corresponding to the original request.
+ * @param status NanStatus of the operation. Possible status codes are:
+ * |NanStatusCode.SUCCESS|
+ * |NanStatusCode.INVALID_ARGS|
+ * |NanStatusCode.INTERNAL_FAILURE|
+ * |NanStatusCode.PROTOCOL_FAILURE|
+ * |NanStatusCode.INVALID_NDP_ID|
+ */
+ void notifyRespondToDataPathIndicationResponse(in char id, in NanStatus status);
+
+ /**
+ * Callback invoked to notify the status of the start publish request
+ * |IWifiNanIface.startPublishRequest|.
+ *
+ * @param cmdId Command Id corresponding to the original request.
+ * @param status NanStatus of the operation. Possible status codes are:
+ * |NanStatusCode.SUCCESS|
+ * |NanStatusCode.INVALID_ARGS|
+ * |NanStatusCode.PROTOCOL_FAILURE|
+ * |NanStatusCode.NO_RESOURCES_AVAILABLE|
+ * |NanStatusCode.INVALID_SESSION_ID|
+ * @param sessionId ID of the new publish session (if successfully created).
+ */
+ void notifyStartPublishResponse(in char id, in NanStatus status, in byte sessionId);
+
+ /**
+ * Callback invoked to notify the status of the start subscribe request
+ * |IWifiNanIface.startSubscribeRequest|.
+ *
+ * @param cmdId Command Id corresponding to the original request.
+ * @param status NanStatus of the operation. Possible status codes are:
+ * |NanStatusCode.SUCCESS|
+ * |NanStatusCode.INVALID_ARGS|
+ * |NanStatusCode.PROTOCOL_FAILURE|
+ * |NanStatusCode.NO_RESOURCES_AVAILABLE|
+ * |NanStatusCode.INVALID_SESSION_ID|
+ * @param sessionId ID of the new subscribe session (if successfully created).
+ */
+ void notifyStartSubscribeResponse(in char id, in NanStatus status, in byte sessionId);
+
+ /**
+ * Callback invoked in response to a stop publish request
+ * |IWifiNanIface.stopPublishRequest|.
+ *
+ * @param cmdId Command Id corresponding to the original request.
+ * @param status NanStatus of the operation. Possible status codes are:
+ * |NanStatusCode.SUCCESS|
+ * |NanStatusCode.INVALID_SESSION_ID|
+ * |NanStatusCode.INTERNAL_FAILURE|
+ */
+ void notifyStopPublishResponse(in char id, in NanStatus status);
+
+ /**
+ * Callback invoked in response to a stop subscribe request
+ * |IWifiNanIface.stopSubscribeRequest|.
+ *
+ * @param cmdId Command Id corresponding to the original request.
+ * @param status NanStatus of the operation. Possible status codes are:
+ * |NanStatusCode.SUCCESS|
+ * |NanStatusCode.INVALID_SESSION_ID|
+ * |NanStatusCode.INTERNAL_FAILURE|
+ */
+ void notifyStopSubscribeResponse(in char id, in NanStatus status);
+
+ /**
+ * Callback invoked in response to a terminate data path request
+ * |IWifiNanIface.terminateDataPathRequest|.
+ *
+ * @param cmdId Command Id corresponding to the original request.
+ * @param status NanStatus of the operation. Possible status codes are:
+ * |NanStatusCode.SUCCESS|
+ * |NanStatusCode.INVALID_ARGS|
+ * |NanStatusCode.INTERNAL_FAILURE|
+ * |NanStatusCode.PROTOCOL_FAILURE|
+ * |NanStatusCode.INVALID_NDP_ID|
+ */
+ void notifyTerminateDataPathResponse(in char id, in NanStatus status);
+
+ /**
+ * Callback invoked in response to a transmit followup request
+ * |IWifiNanIface.transmitFollowupRequest|.
+ *
+ * @param cmdId Command Id corresponding to the original request.
+ * @param status NanStatus of the operation. Possible status codes are:
+ * |NanStatusCode.SUCCESS|
+ * |NanStatusCode.INVALID_ARGS|
+ * |NanStatusCode.INTERNAL_FAILURE|
+ * |NanStatusCode.INVALID_SESSION_ID|
+ * |NanStatusCode.INVALID_PEER_ID|
+ * |NanStatusCode.FOLLOWUP_TX_QUEUE_FULL|
+ */
+ void notifyTransmitFollowupResponse(in char id, in NanStatus status);
+}
diff --git a/wifi/aidl/android/hardware/wifi/IWifiP2pIface.aidl b/wifi/aidl/android/hardware/wifi/IWifiP2pIface.aidl
new file mode 100644
index 0000000..287f41d
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/IWifiP2pIface.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Interface used to represent a single P2P iface.
+ */
+@VintfStability
+interface IWifiP2pIface {
+ /**
+ * Get the name of this iface.
+ *
+ * @return Name of this iface.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|
+ */
+ String getName();
+}
diff --git a/wifi/aidl/android/hardware/wifi/IWifiRttController.aidl b/wifi/aidl/android/hardware/wifi/IWifiRttController.aidl
new file mode 100644
index 0000000..99e1a81
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/IWifiRttController.aidl
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.IWifiRttControllerEventCallback;
+import android.hardware.wifi.IWifiStaIface;
+import android.hardware.wifi.MacAddress;
+import android.hardware.wifi.RttCapabilities;
+import android.hardware.wifi.RttConfig;
+import android.hardware.wifi.RttLciInformation;
+import android.hardware.wifi.RttLcrInformation;
+import android.hardware.wifi.RttResponder;
+import android.hardware.wifi.WifiChannelInfo;
+
+/**
+ * Interface used to perform RTT (Round trip time) operations.
+ */
+@VintfStability
+interface IWifiRttController {
+ /**
+ * Disable RTT responder mode.
+ *
+ * @param cmdId Command Id corresponding to the original request.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_RTT_CONTROLLER_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ void disableResponder(in int cmdId);
+
+ /**
+ * Enable RTT responder mode.
+ *
+ * @param cmdId Command Id to use for this invocation.
+ * @parm channelHint Hint for the channel information where RTT responder
+ * must be enabled on.
+ * @param maxDurationInSeconds Timeout of responder mode.
+ * @param info Instance of |RttResponderInfo|.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_RTT_CONTROLLER_INVALID|,
+ * |WifiStatusCode.ERROR_INVALID_ARGS|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ void enableResponder(in int cmdId, in WifiChannelInfo channelHint, in int maxDurationInSeconds,
+ in RttResponder info);
+
+ /**
+ * Get the iface on which the RTT operations must be performed.
+ *
+ * @return AIDL interface object representing the iface if bound
+ * to a specific iface, null otherwise
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_RTT_CONTROLLER_INVALID|
+ */
+ IWifiStaIface getBoundIface();
+
+ /**
+ * RTT capabilities of the device.
+ *
+ * @return Instance of |RttCapabilities|.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_RTT_CONTROLLER_INVALID|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ RttCapabilities getCapabilities();
+
+ /**
+ * Get RTT responder information (e.g. WiFi channel) to enable responder on.
+ *
+ * @return Instance of |RttResponderInfo|.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_RTT_CONTROLLER_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ RttResponder getResponderInfo();
+
+ /**
+ * API to cancel RTT measurements.
+ *
+ * @param cmdId Command Id corresponding to the original request.
+ * @param addrs Vector of addresses for which to cancel.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_RTT_CONTROLLER_INVALID|,
+ * |WifiStatusCode.ERROR_INVALID_ARGS|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ void rangeCancel(in int cmdId, in MacAddress[] addrs);
+
+ /**
+ * API to request RTT measurement.
+ *
+ * @param cmdId Command Id to use for this invocation.
+ * @param rttConfigs Vector of |RttConfig| parameters.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_RTT_CONTROLLER_INVALID|,
+ * |WifiStatusCode.ERROR_INVALID_ARGS|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ void rangeRequest(in int cmdId, in RttConfig[] rttConfigs);
+
+ /**
+ * Requests notifications of significant events on this RTT controller.
+ * Multiple calls to this must register multiple callbacks, each of which
+ * must receive all events.
+ *
+ * @param callback An instance of the |IWifiRttControllerEventCallback| AIDL
+ * interface object.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|
+ */
+ void registerEventCallback(in IWifiRttControllerEventCallback callback);
+
+ /**
+ * API to configure the LCI (Location civic information).
+ * Used in RTT Responder mode only.
+ *
+ * @param cmdId Command Id to use for this invocation.
+ * @param lci Instance of |RttLciInformation|.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_RTT_CONTROLLER_INVALID|,
+ * |WifiStatusCode.ERROR_INVALID_ARGS|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ void setLci(in int cmdId, in RttLciInformation lci);
+
+ /**
+ * API to configure the LCR (Location civic records).
+ * Used in RTT Responder mode only.
+ *
+ * @param cmdId Command Id to use for this invocation.
+ * @param lcr Instance of |RttLcrInformation|.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_RTT_CONTROLLER_INVALID|,
+ * |WifiStatusCode.ERROR_INVALID_ARGS|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ void setLcr(in int cmdId, in RttLcrInformation lcr);
+}
diff --git a/wifi/aidl/android/hardware/wifi/IWifiRttControllerEventCallback.aidl b/wifi/aidl/android/hardware/wifi/IWifiRttControllerEventCallback.aidl
new file mode 100644
index 0000000..89f0ed8
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/IWifiRttControllerEventCallback.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.RttResult;
+
+/**
+ * RTT Response and Event Callbacks.
+ */
+@VintfStability
+oneway interface IWifiRttControllerEventCallback {
+ /**
+ * Invoked when an RTT result is available.
+ *
+ * @param cmdId Command Id corresponding to the original request.
+ * @param results Vector of |RttResult| instances.
+ */
+ void onResults(in int cmdId, in RttResult[] results);
+}
diff --git a/wifi/aidl/android/hardware/wifi/IWifiStaIface.aidl b/wifi/aidl/android/hardware/wifi/IWifiStaIface.aidl
new file mode 100644
index 0000000..2dd57b2
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/IWifiStaIface.aidl
@@ -0,0 +1,555 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.IWifiStaIfaceEventCallback;
+import android.hardware.wifi.StaApfPacketFilterCapabilities;
+import android.hardware.wifi.StaBackgroundScanCapabilities;
+import android.hardware.wifi.StaBackgroundScanParameters;
+import android.hardware.wifi.StaLinkLayerStats;
+import android.hardware.wifi.StaRoamingCapabilities;
+import android.hardware.wifi.StaRoamingConfig;
+import android.hardware.wifi.StaRoamingState;
+import android.hardware.wifi.WifiBand;
+import android.hardware.wifi.WifiDebugRxPacketFateReport;
+import android.hardware.wifi.WifiDebugTxPacketFateReport;
+
+/**
+ * Interface used to represent a single STA iface.
+ */
+@VintfStability
+interface IWifiStaIface {
+ /**
+ * Mask of capabilities supported by this iface.
+ */
+ @VintfStability
+ @Backing(type="int")
+ enum StaIfaceCapabilityMask {
+ /**
+ * Support for APF APIs. APF (Android Packet Filter) is a
+ * BPF-like packet filtering bytecode executed by the firmware.
+ */
+ APF = 1 << 0,
+ /**
+ * Support for Background Scan APIs. Background scan allows the host
+ * to send a number of buckets down to the firmware. Each bucket
+ * contains a set of channels, a period, and some parameters about
+ * how and when to report results.
+ */
+ BACKGROUND_SCAN = 1 << 1,
+ /**
+ * Support for link layer stats APIs.
+ */
+ LINK_LAYER_STATS = 1 << 2,
+ /**
+ * Support for RSSI monitor APIs.
+ */
+ RSSI_MONITOR = 1 << 3,
+ /**
+ * Support for roaming APIs.
+ */
+ CONTROL_ROAMING = 1 << 4,
+ /**
+ * Support for Probe IE allow-listing.
+ */
+ PROBE_IE_ALLOWLIST = 1 << 5,
+ /**
+ * Support for MAC & Probe Sequence Number randomization.
+ */
+ SCAN_RAND = 1 << 6,
+ /**
+ * Support for 5 GHz Band.
+ */
+ STA_5G = 1 << 7,
+ /**
+ * Support for GAS/ANQP queries.
+ */
+ HOTSPOT = 1 << 8,
+ /**
+ * Support for Preferred Network Offload.
+ */
+ PNO = 1 << 9,
+ /**
+ * Support for Tunneled Direct Link Setup.
+ */
+ TDLS = 1 << 10,
+ /**
+ * Support for Tunneled Direct Link Setup off channel.
+ */
+ TDLS_OFFCHANNEL = 1 << 11,
+ /**
+ * Support for neighbour discovery offload.
+ */
+ ND_OFFLOAD = 1 << 12,
+ /**
+ * Support for keep alive packet offload.
+ */
+ KEEP_ALIVE = 1 << 13,
+ /**
+ * Support for tracking connection packets' fate.
+ */
+ DEBUG_PACKET_FATE = 1 << 14,
+ }
+
+ /**
+ * Get the name of this iface.
+ *
+ * @return Name of this iface.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|
+ */
+ String getName();
+
+ /**
+ * Configure roaming control parameters.
+ * Must fail if |StaIfaceCapabilityMask.CONTROL_ROAMING| is not set.
+ *
+ * @param config Instance of |StaRoamingConfig|.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ void configureRoaming(in StaRoamingConfig config);
+
+ /**
+ * Disable link layer stats collection.
+ * Must fail if |StaIfaceCapabilityMask.LINK_LAYER_STATS| is not set.
+ *
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.ERROR_NOT_STARTED|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ void disableLinkLayerStatsCollection();
+
+ /**
+ * Enable link layer stats collection.
+ * Must fail if |StaIfaceCapabilityMask.LINK_LAYER_STATS| is not set.
+ *
+ * Radio statistics (once started) must not stop until disabled.
+ * Iface statistics (once started) reset and start afresh after each
+ * connection until disabled.
+ *
+ * @param debug true to enable field debug mode, false to disable. Driver
+ * must collect all statistics regardless of performance impact.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ void enableLinkLayerStatsCollection(in boolean debug);
+
+ /**
+ * Enable/Disable neighbour discovery offload functionality in the firmware.
+ *
+ * @param enable true to enable, false to disable.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ void enableNdOffload(in boolean enable);
+
+ /**
+ * Used to query additional information about the chip's APF capabilities.
+ * Must fail if |StaIfaceCapabilityMask.APF| is not set.
+ *
+ * @return Instance of |StaApfPacketFilterCapabilities|.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ StaApfPacketFilterCapabilities getApfPacketFilterCapabilities();
+
+ /**
+ * Used to query additional information about the chip's Background Scan capabilities.
+ * Must fail if |StaIfaceCapabilityMask.BACKGROUND_SCAN| is not set.
+ *
+ * @return Instance of |StaBackgroundScanCapabilities|
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ StaBackgroundScanCapabilities getBackgroundScanCapabilities();
+
+ /**
+ * Get the capabilities supported by this STA iface.
+ *
+ * @return Bitset of |StaIfaceCapabilityMask| values.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ StaIfaceCapabilityMask getCapabilities();
+
+ /**
+ * API to retrieve the fates of inbound packets.
+ * - HAL implementation must return the fates of
+ * all the frames received for the most recent association.
+ * The fate reports must follow the same order as their respective
+ * packets.
+ * - HAL implementation may choose (but is not required) to include
+ * reports for management frames.
+ * - Packets reported by firmware, but not recognized by driver,
+ * must be included. However, the ordering of the corresponding
+ * reports is at the discretion of HAL implementation.
+ * - Framework must be able to call this API multiple times for the same
+ * association.
+ *
+ * @return Vector of |WifiDebugRxPacketFateReport| instances corresponding
+ * to the packet fates.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.ERROR_NOT_STARTED|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ WifiDebugRxPacketFateReport[] getDebugRxPacketFates();
+
+ /**
+ * API to retrieve fates of outbound packets.
+ * - HAL implementation must return the fates of
+ * all the frames transmitted for the most recent association.
+ * The fate reports must follow the same order as their respective
+ * packets.
+ * - HAL implementation may choose (but is not required) to include
+ * reports for management frames.
+ * - Packets reported by firmware, but not recognized by driver,
+ * must be included. However, the ordering of the corresponding
+ * reports is at the discretion of HAL implementation.
+ * - Framework must be able to call this API multiple times for the same
+ * association.
+ *
+ * @return Vector of |WifiDebugTxPacketFateReport| instances corresponding
+ * to the packet fates.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.ERROR_NOT_STARTED|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ WifiDebugTxPacketFateReport[] getDebugTxPacketFates();
+
+ /**
+ * Gets the factory MAC address of the STA interface.
+ *
+ * @return Factory MAC address of the STA interface.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ byte[6] getFactoryMacAddress();
+
+ /**
+ * Retrieve the latest link layer stats.
+ * Must fail if |StaIfaceCapabilityMask.LINK_LAYER_STATS| is not set or if
+ * link layer stats collection hasn't been explicitly enabled.
+ *
+ * @return Instance of |LinkLayerStats|.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.ERROR_NOT_STARTED|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ StaLinkLayerStats getLinkLayerStats();
+
+ /**
+ * Get roaming control capabilities.
+ * Must fail if |StaIfaceCapabilityMask.CONTROL_ROAMING| is not set.
+ *
+ * @return Instance of |StaRoamingCapabilities|.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ StaRoamingCapabilities getRoamingCapabilities();
+
+ /**
+ * Used to query the list of valid frequencies (depending on the country
+ * code set) for the provided band. These channels may be specified in the
+ * |BackgroundScanBucketParameters.frequenciesInMhz| for a background scan
+ * request.
+ *
+ * @param band Band for which the frequency list is being generated.
+ * @return Vector of valid frequencies for the provided band.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ int[] getValidFrequenciesForBand(in WifiBand band);
+
+ /**
+ * Installs an APF program on this iface, replacing an existing
+ * program if present.
+ * Must fail if |StaIfaceCapabilityMask.APF| is not set.
+ *
+ * APF docs
+ * ==========================================================================
+ * APF functionality, instructions and bytecode/binary format is described in:
+ * http://android.googlesource.com/platform/hardware/google/apf/
+ * +/b75c9f3714cfae3dad3d976958e063150781437e/apf.h
+ *
+ * The interpreter API is described here:
+ * http://android.googlesource.com/platform/hardware/google/apf/+/
+ * b75c9f3714cfae3dad3d976958e063150781437e/apf_interpreter.h#32
+ *
+ * The assembler/generator API is described in javadocs here:
+ * http://android.googlesource.com/platform/frameworks/base/+/
+ * 4456f33a958a7f09e608399da83c4d12b2e7d191/services/net/java/android/net/
+ * apf/ApfGenerator.java
+ *
+ * Disassembler usage is described here:
+ * http://android.googlesource.com/platform/hardware/google/apf/+/
+ * b75c9f3714cfae3dad3d976958e063150781437e/apf_disassembler.c#65
+ *
+ * The BPF to APF translator usage is described here:
+ * http://android.googlesource.com/platform/frameworks/base/+/
+ * 4456f33a958a7f09e608399da83c4d12b2e7d191/tests/net/java/android/net/
+ * apf/Bpf2Apf.java
+ * ==========================================================================
+ *
+ * @param program APF Program to be set.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_INVALID_ARGS|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ void installApfPacketFilter(in byte[] program);
+
+ /**
+ * Fetches a consistent snapshot of the entire APF program and working
+ * memory buffer and returns it to the host. The returned buffer contains
+ * both code and data. Its length must match the most recently returned
+ * |StaApfPacketFilterCapabilities.maxLength|.
+ *
+ * While the snapshot is being fetched, the APF interpreter must not execute
+ * and all incoming packets must be passed to the host as if there was no
+ * APF program installed.
+ *
+ * Must fail with |WifiStatusCode.ERROR_NOT_SUPPORTED| if
+ * |StaIfaceCapabilityMask.APF| is not set.
+ *
+ * @return The entire APF working memory buffer when status is
+ * |WifiStatusCode.SUCCESS|, empty otherwise.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ * @see getApfPacketFilterCapabilities()
+ * @see installApfPacketFilter()
+ */
+ byte[] readApfPacketFilterData();
+
+ /**
+ * Requests notifications of significant events on this iface. Multiple calls
+ * to this must register multiple callbacks, each of which must receive all
+ * events.
+ *
+ * @param callback An instance of the |IWifiStaIfaceEventCallback| AIDL
+ * interface object.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|
+ */
+ void registerEventCallback(in IWifiStaIfaceEventCallback callback);
+
+ /**
+ * Changes the MAC address of the STA Interface to the given
+ * MAC address.
+ *
+ * @param mac MAC address to change to.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ void setMacAddress(in byte[6] mac);
+
+ /**
+ * Set the roaming control state with the parameters configured
+ * using |configureRoaming|. Depending on the roaming state set, the
+ * driver/firmware would enable/disable control over roaming decisions.
+ * Must fail if |StaIfaceCapabilityMask.CONTROL_ROAMING| is not set.
+ *
+ * @param state State of the roaming control.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.ERROR_BUSY|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ void setRoamingState(in StaRoamingState state);
+
+ /**
+ * Turn on/off scan only mode for the interface.
+ *
+ * @param enable True to enable scan only mode, false to disable.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.FAILURE_UNKNOWN|
+ */
+ void setScanMode(in boolean enable);
+
+ /**
+ * Start a background scan using the given cmdId as an identifier. Only one
+ * active background scan need be supported.
+ * Must fail if |StaIfaceCapabilityMask.BACKGROUND_SCAN| is not set.
+ *
+ * When this is called all requested buckets must be scanned, starting the
+ * beginning of the cycle.
+ *
+ * For example:
+ * If there are two buckets specified
+ * - Bucket 1: period=10s
+ * - Bucket 2: period=20s
+ * - Bucket 3: period=30s
+ * Then the following scans must occur
+ * - t=0 buckets 1, 2, and 3 are scanned
+ * - t=10 bucket 1 is scanned
+ * - t=20 bucket 1 and 2 are scanned
+ * - t=30 bucket 1 and 3 are scanned
+ * - t=40 bucket 1 and 2 are scanned
+ * - t=50 bucket 1 is scanned
+ * - t=60 buckets 1, 2, and 3 are scanned
+ * - and the pattern repeats
+ *
+ * If any scan does not occur or is incomplete (error, interrupted, etc),
+ * then a cached scan result must still be recorded with the
+ * WIFI_SCAN_FLAG_INTERRUPTED flag set.
+ *
+ * @param cmdId Command Id to use for this invocation.
+ * @param params Background scan parameters.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_INVALID_ARGS|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ void startBackgroundScan(in int cmdId, in StaBackgroundScanParameters params);
+
+ /**
+ * API to start packet fate monitoring.
+ * - Once started, monitoring must remain active until HAL is stopped or the
+ * chip is reconfigured.
+ * - When HAL is unloaded, all packet fate buffers must be cleared.
+ * - The packet fates are used to monitor the state of packets transmitted/
+ * received during association.
+ *
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ void startDebugPacketFateMonitoring();
+
+ /**
+ * Start RSSI monitoring on the currently connected access point.
+ * Once the monitoring is enabled, the
+ * |IWifiStaIfaceEventCallback.onRssiThresholdBreached| callback must be
+ * invoked to indicate if the RSSI goes above |maxRssi| or below |minRssi|.
+ * Must fail if |StaIfaceCapabilityMask.RSSI_MONITOR| is not set.
+ *
+ * @param cmdId Command Id to use for this invocation.
+ * @param maxRssi Maximum RSSI threshold.
+ * @param minRssi Minimum RSSI threshold.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_ARGS_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ void startRssiMonitoring(in int cmdId, in int maxRssi, in int minRssi);
+
+ /**
+ * Start sending the specified keep alive packets periodically.
+ *
+ * @param cmdId Command Id to use for this invocation.
+ * @param ipPacketData IP packet contents to be transmitted.
+ * @param etherType 16 bit ether type to be set in the ethernet frame
+ * transmitted.
+ * @param srcAddress Source MAC address of the packet.
+ * @param dstAddress Destination MAC address of the packet.
+ * @param periodInMs Interval at which this packet must be transmitted.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ void startSendingKeepAlivePackets(in int cmdId, in byte[] ipPacketData, in char etherType,
+ in byte[6] srcAddress, in byte[6] dstAddress, in int periodInMs);
+
+ /**
+ * Stop the current background scan.
+ * Must fail if |StaIfaceCapabilityMask.BACKGROUND_SCAN| is not set.
+ *
+ * @param cmdId Command Id corresponding to the request.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.ERROR_NOT_STARTED|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ void stopBackgroundScan(in int cmdId);
+
+ /**
+ * Stop RSSI monitoring.
+ * Must fail if |StaIfaceCapabilityMask.RSSI_MONITOR| is not set.
+ *
+ * @param cmdId Command Id corresponding to the request.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.ERROR_NOT_STARTED|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ void stopRssiMonitoring(in int cmdId);
+
+ /**
+ * Stop sending the specified keep alive packets.
+ *
+ * @param cmdId Command Id corresponding to the request.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ void stopSendingKeepAlivePackets(in int cmdId);
+}
diff --git a/wifi/aidl/android/hardware/wifi/IWifiStaIfaceEventCallback.aidl b/wifi/aidl/android/hardware/wifi/IWifiStaIfaceEventCallback.aidl
new file mode 100644
index 0000000..93a255f
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/IWifiStaIfaceEventCallback.aidl
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.StaScanData;
+import android.hardware.wifi.StaScanResult;
+
+@VintfStability
+oneway interface IWifiStaIfaceEventCallback {
+ /**
+ * Called for each received beacon/probe response for a scan with the
+ * |REPORT_EVENTS_FULL_RESULTS| flag set in
+ * |StaBackgroundScanBucketParameters.eventReportScheme|.
+ *
+ * @param cmdId Command Id corresponding to the request.
+ * @param bucketsScanned Bitset where each bit indicates if the bucket with
+ * that index (starting at 0) was scanned.
+ * @param result Full scan result for an AP.
+ */
+ void onBackgroundFullScanResult(in int cmdId, in int bucketsScanned, in StaScanResult result);
+
+ /**
+ * Callback indicating that an ongoing background scan request has failed.
+ * The background scan needs to be restarted to continue scanning.
+ *
+ * @param cmdId Command Id corresponding to the request.
+ */
+ void onBackgroundScanFailure(in int cmdId);
+
+ /**
+ * Called when the |StaBackgroundScanBucketParameters.eventReportScheme| flags
+ * for at least one bucket that was just scanned was
+ * |REPORT_EVENTS_EACH_SCAN|, or one of the configured thresholds was
+ * breached.
+ *
+ * @param cmdId Command Id corresponding to the request.
+ * @param scanDatas List of scan result for all AP's seen since last callback.
+ */
+ void onBackgroundScanResults(in int cmdId, in StaScanData[] scanDatas);
+
+ /**
+ * Called when the RSSI of the currently connected access point goes beyond the
+ * thresholds set via |IWifiStaIface.startRssiMonitoring|.
+ *
+ * @param cmdId Command Id corresponding to the request.
+ * @param currBssid BSSID of the currently connected access point.
+ * @param currRssi RSSI of the currently connected access point.
+ */
+ void onRssiThresholdBreached(in int cmdId, in byte[6] currBssid, in int currRssi);
+}
diff --git a/wifi/aidl/android/hardware/wifi/IfaceConcurrencyType.aidl b/wifi/aidl/android/hardware/wifi/IfaceConcurrencyType.aidl
new file mode 100644
index 0000000..26c183c
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/IfaceConcurrencyType.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * List of interface concurrency types, used in reporting device concurrency capabilities.
+ */
+@VintfStability
+@Backing(type="int")
+enum IfaceConcurrencyType {
+ /**
+ * Concurrency type for station mode.
+ */
+ STA,
+ /**
+ * Concurrency type of single-port AP mode.
+ */
+ AP,
+ /**
+ * Concurrency type of two-port bridged AP mode.
+ */
+ AP_BRIDGED,
+ /**
+ * Concurrency type of peer-to-peer mode.
+ */
+ P2P,
+ /**
+ * Concurrency type of neighborhood area network mode.
+ */
+ NAN_IFACE,
+}
diff --git a/wifi/aidl/android/hardware/wifi/IfaceType.aidl b/wifi/aidl/android/hardware/wifi/IfaceType.aidl
new file mode 100644
index 0000000..c89d94b
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/IfaceType.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * List of supported interface types.
+ */
+@VintfStability
+@Backing(type="int")
+enum IfaceType {
+ STA,
+ AP,
+ P2P,
+ /**
+ * NAN control interface. Datapath support must be queried and created
+ * through this interface. Declared as 'NAN_IFACE' instead of 'NAN'
+ * because the compiler complains that NAN is already defined by math.h
+ */
+ NAN_IFACE,
+}
diff --git a/wifi/aidl/android/hardware/wifi/MacAddress.aidl b/wifi/aidl/android/hardware/wifi/MacAddress.aidl
new file mode 100644
index 0000000..d59dfe3
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/MacAddress.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Byte array representing a Mac Address. Use when we need to
+ * pass an array of Mac Addresses to a method, as variable-sized
+ * 2D arrays are not supported in AIDL.
+ *
+ * TODO (b/210705533): Replace this type with a 2D byte array.
+ */
+@VintfStability
+parcelable MacAddress {
+ byte[6] data;
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanBandIndex.aidl b/wifi/aidl/android/hardware/wifi/NanBandIndex.aidl
new file mode 100644
index 0000000..5da5869
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanBandIndex.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * The discovery bands supported by NAN.
+ */
+@VintfStability
+@Backing(type="int")
+enum NanBandIndex {
+ NAN_BAND_24GHZ = 0,
+ NAN_BAND_5GHZ,
+ /**
+ * Index for 6 GHz band.
+ */
+ NAN_BAND_6GHZ = 2,
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanBandSpecificConfig.aidl b/wifi/aidl/android/hardware/wifi/NanBandSpecificConfig.aidl
new file mode 100644
index 0000000..2e13486
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanBandSpecificConfig.aidl
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * NAN band-specific configuration.
+ */
+@VintfStability
+parcelable NanBandSpecificConfig {
+ /**
+ * RSSI values controlling clustering behavior per spec. RSSI values are specified without a
+ * sign, e.g. a value of -65dBm would be specified as 65.
+ */
+ byte rssiClose;
+ byte rssiMiddle;
+ /**
+ * RSSI value determining whether discovery is near (used if enabled in discovery by
+ * |NanDiscoveryCommonConfig.useRssiThreshold|).
+ * RSSI values are specified without a sign, e.g. a value of -65dBm would be specified as 65.
+ * NAN Spec: RSSI_close_proximity
+ */
+ byte rssiCloseProximity;
+ /**
+ * Dwell time of each discovery channel in milliseconds. If set to 0, then the firmware
+ * determines the dwell time to use.
+ */
+ char dwellTimeMs;
+ /**
+ * Scan period of each discovery channel in seconds. If set to 0, then the firmware determines
+ * the scan period to use.
+ */
+ char scanPeriodSec;
+ /**
+ * Specifies the discovery window interval for Sync beacons and SDF's.
+ * Valid values of DW Interval are: 1, 2, 3, 4 and 5 corresponding to 1, 2, 4, 8, and 16 DWs.
+ * Value of 0:
+ * - reserved in 2.4GHz band
+ * - no wakeup at all in 5GHz band
+ * The publish/subscribe period values don't override the device level configurations if
+ * they are specified.
+ * Configuration is only used only if |validDiscoveryWindowIntervalVal| is set to true.
+ * NAN Spec: Device Capability Attribute / 2.4 GHz DW, Device Capability Attribute / 5 GHz DW
+ */
+ boolean validDiscoveryWindowIntervalVal;
+ byte discoveryWindowIntervalVal;
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanCapabilities.aidl b/wifi/aidl/android/hardware/wifi/NanCapabilities.aidl
new file mode 100644
index 0000000..6042a05
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanCapabilities.aidl
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.NanCipherSuiteType;
+
+/**
+ * NDP Capabilities response.
+ */
+@VintfStability
+parcelable NanCapabilities {
+ /**
+ * Maximum number of clusters which the device can join concurrently.
+ */
+ int maxConcurrentClusters;
+ /**
+ * Maximum number of concurrent publish discovery sessions.
+ */
+ int maxPublishes;
+ /**
+ * Maximum number of concurrent subscribe discovery sessions.
+ */
+ int maxSubscribes;
+ /**
+ * Maximum length (in bytes) of service name.
+ */
+ int maxServiceNameLen;
+ /**
+ * Maximum length (in bytes) of individual match filters.
+ */
+ int maxMatchFilterLen;
+ /**
+ * Maximum length (in bytes) of aggregate match filters across all active sessions.
+ */
+ int maxTotalMatchFilterLen;
+ /**
+ * Maximum length (in bytes) of the service specific info field.
+ */
+ int maxServiceSpecificInfoLen;
+ /**
+ * Maximum length (in bytes) of the extended service specific info field.
+ */
+ int maxExtendedServiceSpecificInfoLen;
+ /**
+ * Maximum number of data interfaces (NDI) which can be created concurrently on the device.
+ */
+ int maxNdiInterfaces;
+ /**
+ * Maximum number of data paths (NDP) which can be created concurrently on the device, across
+ * all data interfaces (NDI).
+ */
+ int maxNdpSessions;
+ /**
+ * Maximum length (in bytes) of application info field (used in data-path negotiations).
+ */
+ int maxAppInfoLen;
+ /**
+ * Maximum number of transmitted followup messages which can be queued by the firmware.
+ */
+ int maxQueuedTransmitFollowupMsgs;
+ /**
+ * Maximum number MAC interface addresses which can be specified to a subscribe discovery
+ * session.
+ */
+ int maxSubscribeInterfaceAddresses;
+ /**
+ * The set of supported Cipher suites. The |NanCipherSuiteType| bit fields are used.
+ */
+ NanCipherSuiteType supportedCipherSuites;
+ /**
+ * Flag to indicate id instant communication mode is supported.
+ */
+ boolean instantCommunicationModeSupportFlag;
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanCipherSuiteType.aidl b/wifi/aidl/android/hardware/wifi/NanCipherSuiteType.aidl
new file mode 100644
index 0000000..9e3d684
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanCipherSuiteType.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Cipher suite flags.
+ */
+@VintfStability
+@Backing(type="int")
+enum NanCipherSuiteType {
+ NONE = 0,
+ SHARED_KEY_128_MASK = 1 << 0,
+ SHARED_KEY_256_MASK = 1 << 1,
+ /**
+ * NCS-PK-128
+ */
+ PUBLIC_KEY_128_MASK = 1 << 2,
+ /**
+ * NCS-PK-256
+ */
+ PUBLIC_KEY_256_MASK = 1 << 3,
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanClusterEventInd.aidl b/wifi/aidl/android/hardware/wifi/NanClusterEventInd.aidl
new file mode 100644
index 0000000..76a3034
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanClusterEventInd.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.NanClusterEventType;
+
+/**
+ * Cluster event indication structure. Triggered on events impacting how this device is
+ * visible to peers - cluster forming, joining a new cluster, or changing of the MAC address.
+ */
+@VintfStability
+parcelable NanClusterEventInd {
+ /**
+ * Event type causing the cluster event indication to be triggered.
+ */
+ NanClusterEventType eventType;
+ /**
+ * MAC Address associated with the corresponding event.
+ */
+ byte[6] addr;
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanClusterEventType.aidl b/wifi/aidl/android/hardware/wifi/NanClusterEventType.aidl
new file mode 100644
index 0000000..c07bf17
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanClusterEventType.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Event types for a cluster event indication.
+ */
+@VintfStability
+@Backing(type="int")
+enum NanClusterEventType {
+ /**
+ * Management/discovery interface MAC address has changed
+ * (e.g. due to randomization or at startup).
+ */
+ DISCOVERY_MAC_ADDRESS_CHANGED = 0,
+ /**
+ * A new cluster has been formed by this device.
+ */
+ STARTED_CLUSTER,
+ /**
+ * This device has joined an existing cluster.
+ */
+ JOINED_CLUSTER,
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanConfigRequest.aidl b/wifi/aidl/android/hardware/wifi/NanConfigRequest.aidl
new file mode 100644
index 0000000..82a7b6e
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanConfigRequest.aidl
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.NanBandSpecificConfig;
+
+/**
+ * Configuration parameters of NAN. Used when enabling and re-configuring a NAN cluster.
+ */
+@VintfStability
+parcelable NanConfigRequest {
+ /**
+ * Master preference of this device.
+ * NAN Spec: Master Indication Attribute / Master Preference
+ */
+ byte masterPref;
+ /**
+ * Controls whether or not the |IWifiNanIfaceEventCallback.eventClusterEvent| will be delivered
+ * for |NanClusterEventType.DISCOVERY_MAC_ADDRESS_CHANGED|.
+ */
+ boolean disableDiscoveryAddressChangeIndication;
+ /**
+ * Controls whether or not the |IWifiNanIfaceEventCallback.eventClusterEvent| will be delivered
+ * for |NanClusterEventType.STARTED_CLUSTER|.
+ */
+ boolean disableStartedClusterIndication;
+ /**
+ * Controls whether or not the |IWifiNanIfaceEventCallback.eventClusterEvent| will be delivered
+ * for |NanClusterEventType.JOINED_CLUSTER|.
+ */
+ boolean disableJoinedClusterIndication;
+ /**
+ * Control whether publish service IDs are included in Sync/Discovery beacons.
+ * NAN Spec: Service ID List Attribute
+ */
+ boolean includePublishServiceIdsInBeacon;
+ /**
+ * If |includePublishServiceIdsInBeacon| is true, then specifies the number of publish service
+ * IDs to include in the Sync/Discovery beacons. Value = 0: include as many service IDs as will
+ * fit into the maximum allowed beacon frame size. Value must fit within 7 bits - i.e. <= 127.
+ */
+ byte numberOfPublishServiceIdsInBeacon;
+ /**
+ * Control whether subscribe service IDs are included in Sync/Discovery beacons.
+ * Spec: Subscribe Service ID List Attribute
+ */
+ boolean includeSubscribeServiceIdsInBeacon;
+ /**
+ * If |includeSubscribeServiceIdsInBeacon| is true, then specifies the number of subscribe
+ * service IDs to include in the Sync/Discovery beacons. Value = 0: include as many service IDs
+ * as will fit into the maximum allowed beacon frame size. Value must fit within 7 bits - i.e.
+ * <= 127.
+ */
+ byte numberOfSubscribeServiceIdsInBeacon;
+ /**
+ * Number of samples used to calculate RSSI.
+ */
+ char rssiWindowSize;
+ /**
+ * Specifies the interval in seconds that the NAN management interface MAC address is
+ * randomized. A value of 0 is used to disable the MAC address randomization.
+ */
+ int macAddressRandomizationIntervalSec;
+ /**
+ * Additional configuration provided per band. Indexed by |NanBandIndex|.
+ */
+ NanBandSpecificConfig[3] bandSpecificConfig;
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanConfigRequestSupplemental.aidl b/wifi/aidl/android/hardware/wifi/NanConfigRequestSupplemental.aidl
new file mode 100644
index 0000000..eb01a9f
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanConfigRequestSupplemental.aidl
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Additional NAN configuration request parameters.
+ */
+@VintfStability
+parcelable NanConfigRequestSupplemental {
+ /**
+ * Specify the Discovery Beacon interval in ms. Specification only applicable if the device
+ * transmits Discovery Beacons (based on the Wi-Fi Aware protocol selection criteria). The value
+ * can be increased to reduce power consumption (on devices which would transmit Discovery
+ * Beacons). However, cluster synchronization time will likely increase.
+ * Values are:
+ * - A value of 0 indicates that the HAL sets the interval to a default (implementation
+ * specific).
+ * - A positive value.
+ */
+ int discoveryBeaconIntervalMs;
+ /**
+ * The number of spatial streams to be used for transmitting NAN management frames (does NOT
+ * apply to data-path packets). A small value may reduce power consumption for small discovery
+ * packets. Values are:
+ * - A value of 0 indicates that the HAL sets the number to a default (implementation
+ * specific).
+ * - A positive value.
+ */
+ int numberOfSpatialStreamsInDiscovery;
+ /**
+ * Controls whether the device may terminate listening on a Discovery Window (DW) earlier than
+ * the DW termination (16ms) if no information is received. Enabling the feature will result in
+ * lower power consumption, but may result in some missed messages and hence increased latency.
+ */
+ boolean enableDiscoveryWindowEarlyTermination;
+ /**
+ * Controls whether NAN RTT (ranging) is permitted. Global flag on any NAN RTT operations are
+ * allowed. Controls ranging in the context of discovery as well as direct RTT.
+ */
+ boolean enableRanging;
+ /**
+ * Controls whether NAN instant communication mode is enabled.
+ */
+ boolean enableInstantCommunicationMode;
+ /**
+ * Controls which channel NAN instant communication mode operates on.
+ */
+ int instantModeChannel;
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanDataPathChannelCfg.aidl b/wifi/aidl/android/hardware/wifi/NanDataPathChannelCfg.aidl
new file mode 100644
index 0000000..3aaea40
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanDataPathChannelCfg.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * NAN DP (data-path) channel config options.
+ */
+@VintfStability
+@Backing(type="int")
+enum NanDataPathChannelCfg {
+ CHANNEL_NOT_REQUESTED = 0,
+ REQUEST_CHANNEL_SETUP,
+ FORCE_CHANNEL_SETUP,
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanDataPathChannelInfo.aidl b/wifi/aidl/android/hardware/wifi/NanDataPathChannelInfo.aidl
new file mode 100644
index 0000000..e5c3538
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanDataPathChannelInfo.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.WifiChannelWidthInMhz;
+
+/**
+ * NAN data path channel information provided to the framework.
+ */
+@VintfStability
+parcelable NanDataPathChannelInfo {
+ /**
+ * Channel frequency in MHz.
+ */
+ int channelFreq;
+ /**
+ * Channel bandwidth in MHz.
+ */
+ WifiChannelWidthInMhz channelBandwidth;
+ /**
+ * Number of spatial streams used in the channel.
+ */
+ int numSpatialStreams;
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanDataPathConfirmInd.aidl b/wifi/aidl/android/hardware/wifi/NanDataPathConfirmInd.aidl
new file mode 100644
index 0000000..621f036
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanDataPathConfirmInd.aidl
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.NanDataPathChannelInfo;
+import android.hardware.wifi.NanStatus;
+
+/**
+ * NAN Data path confirmation indication structure. Event indication is
+ * received on both initiator and responder side when negotiation for a
+ * data-path finishes on success or failure.
+ */
+@VintfStability
+parcelable NanDataPathConfirmInd {
+ /**
+ * ID of the data-path.
+ */
+ int ndpInstanceId;
+ /**
+ * Indicates whether the data-path setup succeeded (true) or failed (false).
+ */
+ boolean dataPathSetupSuccess;
+ /**
+ * MAC address of the peer's data-interface (not its management/discovery interface).
+ */
+ byte[6] peerNdiMacAddr;
+ /**
+ * Arbitrary information communicated from the peer as part of the data-path setup process -
+ * there is no semantic meaning to these bytes. They are passed-through from sender to receiver
+ * as-is with no parsing. Max length: |NanCapabilities.maxAppInfoLen|. NAN Spec: Data Path
+ * Attributes / NDP Attribute / NDP Specific Info
+ */
+ byte[] appInfo;
+ /**
+ * Failure reason if |dataPathSetupSuccess| is false.
+ */
+ NanStatus status;
+ /**
+ * The channel(s) on which the NDP is scheduled to operate.
+ * Updates to the operational channels are provided using the |eventDataPathScheduleUpdate|
+ * event.
+ */
+ NanDataPathChannelInfo[] channelInfo;
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanDataPathRequestInd.aidl b/wifi/aidl/android/hardware/wifi/NanDataPathRequestInd.aidl
new file mode 100644
index 0000000..de9ee32
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanDataPathRequestInd.aidl
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * NAN Data path request indication message structure.
+ * Event indication received by an intended Responder when a NAN
+ * data request initiated by an Initiator.
+ */
+@VintfStability
+parcelable NanDataPathRequestInd {
+ /**
+ * ID of an active publish or subscribe discovery session. The data-path
+ * request is in the context of this discovery session.
+ * NAN Spec: Data Path Attributes / NDP Attribute / Publish ID
+ */
+ byte discoverySessionId;
+ /**
+ * MAC address of the Initiator peer. This is the MAC address of the peer's
+ * management/discovery NAN interface.
+ */
+ byte[6] peerDiscMacAddr;
+ /**
+ * ID of the data-path. Used to identify the data-path in further negotiation/APIs.
+ */
+ int ndpInstanceId;
+ /**
+ * Specifies whether or not security is required by the peer for the data-path being created.
+ * NAN Spec: Data Path Attributes / NDP Attribute / NDP Control / Security Present
+ */
+ boolean securityRequired;
+ /**
+ * Arbitrary information communicated from the peer as part of the data-path setup process.
+ * Therer is no semantic meaning to these bytes. They are passed-through from sender to
+ * receiver as-is with no parsing.
+ * Max length: |NanCapabilities.maxAppInfoLen|.
+ * NAN Spec: Data Path Attributes / NDP Attribute / NDP Specific Info
+ */
+ byte[] appInfo;
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanDataPathScheduleUpdateInd.aidl b/wifi/aidl/android/hardware/wifi/NanDataPathScheduleUpdateInd.aidl
new file mode 100644
index 0000000..0f41d8f
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanDataPathScheduleUpdateInd.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.NanDataPathChannelInfo;
+
+/**
+ * NAN data path channel information update indication structure.
+ * Event indication is received by all NDP owners whenever the channels on
+ * which the NDP operates are updated.
+ * Note: Multiple NDPs may share the same schedule. The indication specifies
+ * all NDPs to which it applies.
+ */
+@VintfStability
+parcelable NanDataPathScheduleUpdateInd {
+ /**
+ * The discovery address (NMI) of the peer to which the NDP is connected.
+ */
+ byte[6] peerDiscoveryAddress;
+ /**
+ * The updated channel(s) information.
+ */
+ NanDataPathChannelInfo[] channelInfo;
+ /**
+ * The list of NDPs to which this update applies.
+ */
+ int[] ndpInstanceIds;
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanDataPathSecurityConfig.aidl b/wifi/aidl/android/hardware/wifi/NanDataPathSecurityConfig.aidl
new file mode 100644
index 0000000..42a5616
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanDataPathSecurityConfig.aidl
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.NanCipherSuiteType;
+import android.hardware.wifi.NanDataPathSecurityType;
+
+/**
+ * Configuration of NAN data-path security.
+ */
+@VintfStability
+parcelable NanDataPathSecurityConfig {
+ /**
+ * Security configuration of the data-path (NDP). Security is enabled if not equal to
+ * |NanDataPathSecurityType.OPEN|.
+ * NAN Spec: Service Discovery Extension Attribute (SDEA) / Control / Security Required
+ */
+ NanDataPathSecurityType securityType;
+ /**
+ * Cipher type for data-paths. If |securityType| is |NanDataPathSecurityType.OPEN| then must
+ * be set to |NanCipherSuiteType.NONE|. Otherwise a non-|NanCipherSuiteType.NONE| cipher suite
+ * must be specified.
+ */
+ NanCipherSuiteType cipherType;
+ /**
+ * Optional Pairwise Master Key (PMK). Must be specified (and is only used) if |securityType| is
+ * set to |NanDataPathSecurityType.PMK|.
+ * Ref: IEEE 802.11i
+ */
+ byte[32] pmk;
+ /**
+ * Optional Passphrase. Must be specified (and is only used) if |securityType| is set to
+ * |NanDataPathSecurityType.PASSPHRASE|.
+ * Min length: |IWifiNanIface.MIN_DATA_PATH_CONFIG_PASSPHRASE_LENGTH|
+ * Max length: |IWifiNanIface.MAX_DATA_PATH_CONFIG_PASSPHRASE_LENGTH|
+ * NAN Spec: Appendix: Mapping passphrase to PMK for NCS-SK Cipher Suites
+ */
+ byte[] passphrase;
+ /**
+ * Security Context Identifier attribute contains PMKID. Shall be included in NDP setup and
+ * response messages. Security Context Identifier identifies the Security Context. When
+ * security is enabled this field contains the 16 octet PMKID identifying the PMK used for
+ * setting up the Secure Data Path.
+ */
+ byte[16] scid;
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanDataPathSecurityType.aidl b/wifi/aidl/android/hardware/wifi/NanDataPathSecurityType.aidl
new file mode 100644
index 0000000..da23ffa
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanDataPathSecurityType.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * NAN DP (data-path) security configuration options.
+ */
+@VintfStability
+@Backing(type="int")
+enum NanDataPathSecurityType {
+ OPEN,
+ PMK,
+ PASSPHRASE,
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanDebugConfig.aidl b/wifi/aidl/android/hardware/wifi/NanDebugConfig.aidl
new file mode 100644
index 0000000..d8fab0d
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanDebugConfig.aidl
@@ -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.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Debug configuration parameters. Many of these allow non-standard-compliant operation and are
+ * not intended for normal operational mode.
+ */
+@VintfStability
+parcelable NanDebugConfig {
+ /**
+ * Specification of the lower 2 bytes of the cluster ID. The cluster ID is 50-60-9a-01-00-00 to
+ * 50-60-9a-01-FF-FF. Configuration is of the bottom and top values of the range (which default
+ * to 0x0000 and 0xFFFF respectively).
+ * Configuration is only used if |validClusterIdVals| is set to true.
+ */
+ boolean validClusterIdVals;
+ char clusterIdBottomRangeVal;
+ char clusterIdTopRangeVal;
+ /**
+ * NAN management interface address. If specified (|validIntfAddrVal| is true), then overrides
+ * any other configuration (specifically the default randomization configured by
+ * |NanConfigRequest.macAddressRandomizationIntervalSec|).
+ */
+ boolean validIntfAddrVal;
+ byte[6] intfAddrVal;
+ /**
+ * Combination of the 24 bit Organizationally Unique ID (OUI) and the 8 bit OUI type.
+ * Used if |validOuiVal| is set to true.
+ */
+ boolean validOuiVal;
+ int ouiVal;
+ /**
+ * Force the Random Factor to the specified value for all transmitted Sync/Discovery beacons.
+ * Used if |validRandomFactorForceVal| is set to true.
+ * NAN Spec: Master Indication Attribute / Random Factor
+ */
+ boolean validRandomFactorForceVal;
+ byte randomFactorForceVal;
+ /**
+ * Forces the hop-count for all transmitted Sync and Discovery Beacons NO matter the real
+ * hop-count being received over the air. Used if the |validHopCountForceVal| flag is set to
+ * true.
+ * NAN Spec: Cluster Attribute / Anchor Master Information / Hop Count to Anchor Master
+ */
+ boolean validHopCountForceVal;
+ byte hopCountForceVal;
+ /**
+ * Frequency in MHz to of the discovery channel in the specified band. Indexed by
+ * |NanBandIndex|. Used if the |validDiscoveryChannelVal| is set to true.
+ */
+ boolean validDiscoveryChannelVal;
+ int[3] discoveryChannelMhzVal;
+ /**
+ * Specifies whether sync/discovery beacons are transmitted in the specified band. Indexed by
+ * |NanBandIndex|. Used if the |validUseBeaconsInBandVal| is set to true.
+ */
+ boolean validUseBeaconsInBandVal;
+ boolean[3] useBeaconsInBandVal;
+ /**
+ * Specifies whether SDF (service discovery frames) are transmitted in the specified band.
+ * Indexed by |NanBandIndex|. Used if the |validUseSdfInBandVal| is set to true.
+ */
+ boolean validUseSdfInBandVal;
+ boolean[3] useSdfInBandVal;
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanDiscoveryCommonConfig.aidl b/wifi/aidl/android/hardware/wifi/NanDiscoveryCommonConfig.aidl
new file mode 100644
index 0000000..ca1e016
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanDiscoveryCommonConfig.aidl
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.NanDataPathSecurityConfig;
+import android.hardware.wifi.NanMatchAlg;
+import android.hardware.wifi.NanRangingIndication;
+
+/**
+ * Configurations of NAN discovery sessions. Common to publish and subscribe discovery.
+ */
+@VintfStability
+parcelable NanDiscoveryCommonConfig {
+ /**
+ * The ID of the discovery session being configured. A value of 0 specifies a request to create
+ * a new discovery session. The new discovery session ID is returned with
+ * |IWifiNanIfaceEventCallback.notifyStartPublishResponse| or
+ * |IWifiNanIfaceEventCallback.notifyStartSubscribeResponse|.
+ * NAN Spec: Service Descriptor Attribute (SDA) / Instance ID
+ */
+ byte sessionId;
+ /**
+ * The lifetime of the discovery session in seconds. A value of 0 means run forever or until
+ * canceled using |IWifiIface.stopPublishRequest| or |IWifiIface.stopSubscribeRequest|.
+ */
+ char ttlSec;
+ /**
+ * Indicates the interval between two Discovery Windows in which the device supporting the
+ * service is awake to transmit or receive the Service Discovery frames. Valid values of Awake
+ * DW Interval are: 1, 2, 4, 8 and 16. A value of 0 will default to 1. Does not override
+ * |NanBandSpecificConfig.discoveryWindowIntervalVal| configurations if those are specified.
+ */
+ char discoveryWindowPeriod;
+ /**
+ * The lifetime of the discovery session in number of transmitted SDF discovery packets. A value
+ * of 0 means forever or until canceled using |IWifiIface.stopPublishRequest| or
+ * |IWifiIface.stopSubscribeRequest|.
+ */
+ byte discoveryCount;
+ /**
+ * UTF-8 encoded string identifying the service.
+ * Max length: |NanCapabilities.maxServiceNameLen|.
+ * NAN Spec: The only acceptable single-byte UTF-8 symbols for a Service Name are alphanumeric
+ * values (A-Z, a-z, 0-9), the hyphen ('-'), and the period ('.'). All valid multi-byte UTF-8
+ * characters are acceptable in a Service Name.
+ */
+ byte[] serviceName;
+ /**
+ * Specifies how often to trigger |IWifiNanIfaceEventCallback.eventMatch| when continuously
+ * discovering the same discovery session (with no changes).
+ */
+ NanMatchAlg discoveryMatchIndicator;
+ /**
+ * Arbitrary information communicated in discovery packets - there is no semantic meaning to
+ * these bytes. They are passed-through from publisher to subscriber as-is with no parsing. Max
+ * length: |NanCapabilities.maxServiceSpecificInfoLen|. NAN Spec: Service Descriptor Attribute
+ * (SDA) / Service Info
+ */
+ byte[] serviceSpecificInfo;
+ /**
+ * Arbitrary information communicated in discovery packets - there is no semantic meaning to
+ * these bytes. They are passed-through from publisher to subscriber as-is with no parsing. Max
+ * length: |NanCapabilities.maxExtendedServiceSpecificInfoLen|. Spec: Service Descriptor
+ * Extension Attribute (SDEA) / Service Info
+ */
+ byte[] extendedServiceSpecificInfo;
+ /**
+ * Ordered sequence of <length, value> pairs (|length| uses 1 byte and contains the number of
+ * bytes in the |value| field) which specify further match criteria (beyond the service name).
+ * The match behavior is specified in details in the NAN spec.
+ * Publisher: used in SOLICITED or SOLICITED_UNSOLICITED sessions.
+ * Subscriber: used in ACTIVE or PASSIVE sessions.
+ * Max length: |NanCapabilities.maxMatchFilterLen|.
+ * NAN Spec: matching_filter_rx
+ */
+ byte[] rxMatchFilter;
+ /**
+ * Ordered sequence of <length, value> pairs (|length| uses 1 byte and contains the number of
+ * bytes in the |value| field) which specify further match criteria (beyond the service name).
+ * The match behavior is specified in details in the NAN spec.
+ * Publisher: used if provided.
+ * Subscriber: used (if provided) only in ACTIVE sessions.
+ * Max length: |NanCapabilities.maxMatchFilterLen|.
+ * NAN Spec: matching_filter_tx and Service Descriptor Attribute (SDA) / Matching Filter
+ */
+ byte[] txMatchFilter;
+ /**
+ * Specifies whether or not the discovery session uses the
+ * |NanBandSpecificConfig.rssiCloseProximity| value (configured in enable/configure requests) to
+ * filter out matched discovered peers.
+ * NAN Spec: Service Descriptor Attribute / Service Control / Discovery Range Limited.
+ */
+ boolean useRssiThreshold;
+ /**
+ * Controls whether or not the |IWifiNanIfaceEventCallback.eventPublishTerminated| (for publish
+ * discovery sessions) or |IWifiNanIfaceEventCallback.eventSubscribeTerminated| (for subscribe
+ * discovery sessions) will be delivered.
+ */
+ boolean disableDiscoveryTerminationIndication;
+ /**
+ * Controls whether or not |IWifiNanIfaceEventCallback.eventMatchExpired| will be delivered.
+ */
+ boolean disableMatchExpirationIndication;
+ /**
+ * Controls whether or not |IWifiNanIfaceEventCallback.eventFollowupReceived| will be delivered.
+ */
+ boolean disableFollowupReceivedIndication;
+ /**
+ * Security configuration of data-paths created in the context of this discovery session.
+ * Security parameters can be overridden during the actual construction of the data-path -
+ * allowing individual data-paths to have unique PMKs or passphrases.
+ */
+ NanDataPathSecurityConfig securityConfig;
+ /**
+ * Specifies whether or not there is a ranging requirement in this discovery session.
+ * Ranging is only performed if all other match criteria with the peer are met. Ranging must
+ * be performed if both peers in the discovery session (publisher and subscriber) set this
+ * flag to true. Otherwise, if either peer sets this flag to false, ranging must not be
+ * performed and must not impact discovery decisions. Note: Specifying that ranging is required
+ * also implies that this device must automatically accept ranging requests from peers. NAN
+ * Spec: Service Discovery Extension Attribute (SDEA) / Control / Ranging Require.
+ */
+ boolean rangingRequired;
+ /**
+ * Interval in ms between two ranging measurements. Only relevant if |rangingRequired| is true.
+ * If the Awake DW interval specified either in |discoveryWindowPeriod| or in
+ * |NanBandSpecificConfig.discoveryWindowIntervalVal| is larger than the ranging interval then
+ * priority is given to Awake DW interval.
+ */
+ int rangingIntervalMs;
+ /**
+ * The type of ranging feedback to be provided by discovery session matches
+ * |IWifiNanIfaceEventCallback.eventMatch|. Only relevant if |rangingRequired| is true.
+ */
+ NanRangingIndication configRangingIndications;
+ /**
+ * The ingress and egress distance in cm. If ranging is enabled (|rangingEnabled| is true) then
+ * |configRangingIndications| is used to determine whether ingress and/or egress (or neither)
+ * are used to determine whether a match has occurred.
+ * NAN Spec: Service Discovery Extension Attribute (SDEA) / Ingress & Egress Range Limit
+ */
+ char distanceIngressCm;
+ char distanceEgressCm;
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanEnableRequest.aidl b/wifi/aidl/android/hardware/wifi/NanEnableRequest.aidl
new file mode 100644
index 0000000..8c28fe1
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanEnableRequest.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.NanConfigRequest;
+import android.hardware.wifi.NanDebugConfig;
+
+/**
+ * Enable requests for NAN. Start-up configuration for |IWifiNanIface.enableRequest|.
+ */
+@VintfStability
+parcelable NanEnableRequest {
+ /**
+ * Enable operation in a specific band. Indexed by |NanBandIndex|.
+ */
+ boolean[3] operateInBand;
+ /**
+ * Specify extent of cluster by specifying the max hop count.
+ */
+ byte hopCountMax;
+ /**
+ * Configurations of NAN cluster operation. Can also be modified at run-time using
+ * |IWifiNanIface.configRequest|.
+ */
+ NanConfigRequest configParams;
+ /**
+ * Non-standard configurations of NAN cluster operation. Useful for debugging operations.
+ */
+ NanDebugConfig debugConfigs;
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanFollowupReceivedInd.aidl b/wifi/aidl/android/hardware/wifi/NanFollowupReceivedInd.aidl
new file mode 100644
index 0000000..20bc9b1
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanFollowupReceivedInd.aidl
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Follow up message received from peer indication structure.
+ */
+@VintfStability
+parcelable NanFollowupReceivedInd {
+ /**
+ * Discovery session (publish or subscribe) ID of a previously created discovery session. The
+ * message is received in the context of this discovery session.
+ * NAN Spec: Service Descriptor Attribute (SDA) / Instance ID
+ */
+ byte discoverySessionId;
+ /**
+ * A unique ID of the peer. Can be subsequently used in |IWifiNanIface.transmitFollowupRequest|
+ * or to set up a data-path.
+ */
+ int peerId;
+ /**
+ * The NAN Discovery (management) MAC address of the peer.
+ */
+ byte[6] addr;
+ /**
+ * Indicates whether received in a further availability window (FAW) if true, or in a discovery
+ * window (DW) if false.
+ */
+ boolean receivedInFaw;
+ /**
+ * Received message from the peer. There is no semantic meaning to these bytes. They are
+ * passed-through from sender to receiver as-is with no parsing.
+ * Max length: |NanCapabilities.maxServiceSpecificInfoLen|.
+ * NAN Spec: Service Descriptor Attribute (SDA) / Service Info
+ */
+ byte[] serviceSpecificInfo;
+ /**
+ * Arbitrary information communicated in discovery packets. There is no semantic meaning to
+ * these bytes. They are passed-through from publisher to subscriber as-is with no parsing. Max
+ * length: |NanCapabilities.maxExtendedServiceSpecificInfoLen|. Spec: Service Descriptor
+ * Extension Attribute (SDEA) / Service Info
+ */
+ byte[] extendedServiceSpecificInfo;
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanInitiateDataPathRequest.aidl b/wifi/aidl/android/hardware/wifi/NanInitiateDataPathRequest.aidl
new file mode 100644
index 0000000..264a873
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanInitiateDataPathRequest.aidl
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.NanDataPathChannelCfg;
+import android.hardware.wifi.NanDataPathSecurityConfig;
+
+/**
+ * Data Path Initiator requesting a data-path.
+ */
+@VintfStability
+parcelable NanInitiateDataPathRequest {
+ /**
+ * ID of the peer. Obtained as part of an earlier |IWifiNanIfaceEventCallback.eventMatch| or
+ * |IWifiNanIfaceEventCallback.eventFollowupReceived|.
+ */
+ int peerId;
+ /**
+ * NAN management interface MAC address of the peer. Obtained as part of an earlier
+ * |IWifiNanIfaceEventCallback.eventMatch| or
+ * |IWifiNanIfaceEventCallback.eventFollowupReceived|.
+ */
+ byte[6] peerDiscMacAddr;
+ /**
+ * Config flag for channel request.
+ */
+ NanDataPathChannelCfg channelRequestType;
+ /**
+ * Channel frequency in MHz to start data-path. Not relevant if |channelRequestType| is
+ * |NanDataPathChannelCfg.CHANNEL_NOT_REQUESTED|.
+ */
+ int channel;
+ /**
+ * NAN data interface name on which this data-path session is to be initiated.
+ * This must be an interface created using |IWifiNanIface.createDataInterfaceRequest|.
+ */
+ String ifaceName;
+ /**
+ * Security configuration of the requested data-path.
+ */
+ NanDataPathSecurityConfig securityConfig;
+ /**
+ * Arbitrary information communicated to the peer as part of the data-path setup process. There
+ * is no semantic meaning to these bytes. They are passed-through from sender to receiver as-is
+ * with no parsing.
+ * Max length: |NanCapabilities.maxAppInfoLen|.
+ * NAN Spec: Data Path Attributes / NDP Attribute / NDP Specific Info
+ */
+ byte[] appInfo;
+ /**
+ * A service name to be used with |passphrase| to construct a Pairwise Master Key (PMK) for the
+ * data-path. Only relevant when a data-path is requested which is not associated with a NAN
+ * discovery session - e.g. using out-of-band discovery.
+ * Constraints: same as |NanDiscoveryCommonConfig.serviceName|
+ * NAN Spec: Appendix: Mapping pass-phrase to PMK for NCS-SK Cipher Suites
+ */
+ byte[] serviceNameOutOfBand;
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanMatchAlg.aidl b/wifi/aidl/android/hardware/wifi/NanMatchAlg.aidl
new file mode 100644
index 0000000..dc96a47
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanMatchAlg.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * NAN Match indication type. Controls how often to trigger |IWifiNanIfaceEventCallback.eventMatch|
+ * for a single discovery session - i.e. continuously discovering the same publisher with no new
+ * data.
+ */
+@VintfStability
+@Backing(type="int")
+enum NanMatchAlg {
+ MATCH_ONCE = 0,
+ MATCH_CONTINUOUS,
+ MATCH_NEVER,
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanMatchInd.aidl b/wifi/aidl/android/hardware/wifi/NanMatchInd.aidl
new file mode 100644
index 0000000..896cde0
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanMatchInd.aidl
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.NanCipherSuiteType;
+import android.hardware.wifi.NanRangingIndication;
+
+/**
+ * Match indication structure.
+ */
+@VintfStability
+parcelable NanMatchInd {
+ /**
+ * Publish or subscribe discovery session ID of an existing discovery session.
+ * NAN Spec: Service Descriptor Attribute (SDA) / Instance ID
+ */
+ byte discoverySessionId;
+ /**
+ * A unique ID of the peer. Can be subsequently used in |IWifiNanIface.transmitFollowupRequest|
+ * or to set up a data-path.
+ */
+ int peerId;
+ /**
+ * The NAN Discovery (management) MAC address of the peer.
+ */
+ byte[6] addr;
+ /**
+ * The arbitrary information contained in the |NanDiscoveryCommonConfig.serviceSpecificInfo| of
+ * the peer's discovery session configuration.
+ * Max length: |NanCapabilities.maxServiceSpecificInfoLen|.
+ * NAN Spec: Service Descriptor Attribute (SDA) / Service Info
+ */
+ byte[] serviceSpecificInfo;
+ /**
+ * Arbitrary information communicated in discovery packets. There is no semantic meaning to
+ * these bytes. They are passed-through from publisher to subscriber as-is with no parsing. Max
+ * length: |NanCapabilities.maxExtendedServiceSpecificInfoLen|. Spec: Service Descriptor
+ * Extension Attribute (SDEA) / Service Info
+ */
+ byte[] extendedServiceSpecificInfo;
+ /**
+ * The match filter from the discovery packet (publish or subscribe) which caused service
+ * discovery. Matches the |NanDiscoveryCommonConfig.txMatchFilter| of the peer's Unsolicited
+ * publish message or of the local device's Active subscribe message.
+ * Max length: |NanCapabilities.maxMatchFilterLen|.
+ * NAN Spec: Service Descriptor Attribute (SDA) / Matching Filter
+ */
+ byte[] matchFilter;
+ /**
+ * Indicates the type of discovery: true if match occurred on a Beacon frame, false if the match
+ * occurred on a Service Discovery Frame (SDF).
+ */
+ boolean matchOccurredInBeaconFlag;
+ /**
+ * Flag to indicate firmware is out of resources and that it can no longer track this Service
+ * Name. Indicates that while |IWifiNanIfaceEventCallback.eventMatch| will be received, the
+ * |NanDiscoveryCommonConfig.discoveryMatchIndicator| configuration will not be honored.
+ */
+ boolean outOfResourceFlag;
+ /**
+ * If RSSI filtering was enabled using |NanDiscoveryCommonConfig.useRssiThreshold| in discovery
+ * session setup, then this field contains the received RSSI value. It will contain 0 if RSSI
+ * filtering was not enabled.
+ * RSSI values are returned without sign, e.g. -70dBm will be returned as 70.
+ */
+ byte rssiValue;
+ /**
+ * Cipher type for data-paths constructed in the context of this discovery session. Valid if
+ * |peerRequiresSecurityEnabledInNdp| is true.
+ */
+ NanCipherSuiteType peerCipherType;
+ /**
+ * Indicates whether or not the peer requires security enabled in any data-path (NDP)
+ * constructed in the context of this discovery session. The |cipherType| specifies the cipher
+ * type for such data-paths. NAN Spec: Service Discovery Extension Attribute (SDEA) / Control /
+ * Security Required
+ */
+ boolean peerRequiresSecurityEnabledInNdp;
+ /**
+ * Indicates whether or not the peer requires (and hence allows) ranging in the context of this
+ * discovery session.
+ * Note that ranging is only performed if all other match criteria with the peer are met.
+ * NAN Spec: Service Discovery Extension Attribute (SDEA) / Control / Ranging Require.
+ */
+ boolean peerRequiresRanging;
+ /**
+ * Ranging indication supersedes the NanMatchAlg specification.
+ * Ex: If NanMatchAlg is MATCH_ONCE, but ranging indication is continuous, then continuous
+ * match notifications will be received (with ranging information).
+ * Ranging indication data is provided if Ranging required is enabled in the discovery
+ * specification and:
+ * 1) continuous ranging is specified.
+ * 2) ingress/egress is specified and:
+ * - notify once for ingress >= ingress_distance and egress <= egress_distance,
+ * - same for ingress_egress_both
+ * If the Awake DW intervals are larger than the ranging intervals, then priority is given
+ * to the device DW intervals.
+ *
+ * If ranging was required and executed, this contains the distance to the peer in mm. The
+ * |rangingIndicationType| field specifies the event which triggered ranging.
+ */
+ int rangingMeasurementInMm;
+ /**
+ * The ranging event(s) which triggered the ranging. e.g. can indicate that continuous ranging
+ * was requested, or else that an ingress event occurred.
+ */
+ NanRangingIndication rangingIndicationType;
+ /**
+ * Security Context Identifier attribute contains PMKID. Shall be included in NDP setup and
+ * response messages. Security Context Identifie identifies the Security Context. For NAN
+ * Shared Key Cipher Suite, this field contains the 16 octet PMKID identifying the PMK used for
+ * setting up the Secure Data Path.
+ */
+ byte[] scid;
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanPublishRequest.aidl b/wifi/aidl/android/hardware/wifi/NanPublishRequest.aidl
new file mode 100644
index 0000000..6dd079c
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanPublishRequest.aidl
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.NanDiscoveryCommonConfig;
+import android.hardware.wifi.NanPublishType;
+import android.hardware.wifi.NanTxType;
+
+/**
+ * Publish request. Specifies a publish discovery operation.
+ */
+@VintfStability
+parcelable NanPublishRequest {
+ /**
+ * Common configuration of discovery sessions.
+ */
+ NanDiscoveryCommonConfig baseConfigs;
+ /**
+ * Type of the publish discovery session.
+ */
+ NanPublishType publishType;
+ /**
+ * For publishType of |NanPublishType.SOLICITED| or |NanPublishType.UNSOLICITED_SOLICITED|,
+ * this specifies the type of transmission used for responding to the probing subscribe
+ * discovery peer.
+ */
+ NanTxType txType;
+ /**
+ * Specifies whether data-path requests |IWifiNanIfaceEventCallback.eventDataPathRequest| (in
+ * the context of this discovery session) are automatically accepted (if true) - in which case
+ * the Responder must not call the |IWifiNanIface.respondToDataPathIndicationRequest| method and
+ * the device must automatically accept the data-path request and complete the negotiation.
+ */
+ boolean autoAcceptDataPathRequests;
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanPublishType.aidl b/wifi/aidl/android/hardware/wifi/NanPublishType.aidl
new file mode 100644
index 0000000..a7a1c48
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanPublishType.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * NAN publish discovery session types.
+ */
+@VintfStability
+@Backing(type="int")
+enum NanPublishType {
+ UNSOLICITED = 0,
+ SOLICITED,
+ UNSOLICITED_SOLICITED,
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanRangingIndication.aidl b/wifi/aidl/android/hardware/wifi/NanRangingIndication.aidl
new file mode 100644
index 0000000..731cbfc
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanRangingIndication.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Ranging in the context of discovery session indication controls. Controls
+ * the frequency of ranging-driven |IWifiNanIfaceEventCallback.eventMatch|.
+ */
+@VintfStability
+@Backing(type="int")
+enum NanRangingIndication {
+ CONTINUOUS_INDICATION_MASK = 1 << 0,
+ INGRESS_MET_MASK = 1 << 1,
+ EGRESS_MET_MASK = 1 << 2,
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanRespondToDataPathIndicationRequest.aidl b/wifi/aidl/android/hardware/wifi/NanRespondToDataPathIndicationRequest.aidl
new file mode 100644
index 0000000..6960e71
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanRespondToDataPathIndicationRequest.aidl
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.NanDataPathSecurityConfig;
+
+/**
+ * Response to a data-path request from a peer.
+ */
+@VintfStability
+parcelable NanRespondToDataPathIndicationRequest {
+ /**
+ * Accept (true) or reject (false) the request.
+ * NAN Spec: Data Path Attributes / NDP Attribute / Type and Status
+ */
+ boolean acceptRequest;
+ /**
+ * ID of the data-path (NDP) for which we're responding. Obtained as part of the request in
+ * |IWifiNanIfaceEventCallback.eventDataPathRequest|.
+ */
+ int ndpInstanceId;
+ /**
+ * NAN data interface name on which this data-path session is to be started.
+ * This must be an interface created using |IWifiNanIface.createDataInterfaceRequest|.
+ */
+ String ifaceName;
+ /**
+ * Security configuration of the requested data-path.
+ */
+ NanDataPathSecurityConfig securityConfig;
+ /**
+ * Arbitrary information communicated to the peer as part of the data-path setup process. There
+ * is no semantic meaning to these bytes. They are passed-through from sender to receiver as-is
+ * with no parsing.
+ * Max length: |NanCapabilities.maxAppInfoLen|.
+ * NAN Spec: Data Path Attributes / NDP Attribute / NDP Specific Info
+ */
+ byte[] appInfo;
+ /**
+ * A service name to be used with |passphrase| to construct a Pairwise Master Key (PMK) for the
+ * data-path. Only relevant when a data-path is requested which is not associated with a NAN
+ * discovery session - e.g. using out-of-band discovery.
+ * Constraints: same as |NanDiscoveryCommonConfig.serviceName|
+ * NAN Spec: Appendix: Mapping pass-phrase to PMK for NCS-SK Cipher Suites
+ */
+ byte[] serviceNameOutOfBand;
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanSrfType.aidl b/wifi/aidl/android/hardware/wifi/NanSrfType.aidl
new file mode 100644
index 0000000..4063b17
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanSrfType.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * NAN Service Response Filter Attribute Bit.
+ */
+@VintfStability
+@Backing(type="int")
+enum NanSrfType {
+ BLOOM_FILTER = 0,
+ PARTIAL_MAC_ADDR,
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanStatus.aidl b/wifi/aidl/android/hardware/wifi/NanStatus.aidl
new file mode 100644
index 0000000..ad29e5b
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanStatus.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.NanStatusCode;
+
+/**
+ * Status information returned in NAN notifications.
+ */
+@VintfStability
+parcelable NanStatus {
+ /**
+ * Status of the command request.
+ */
+ NanStatusCode status;
+ /**
+ * Further description of the issue causing a failure.
+ */
+ String description;
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanStatusCode.aidl b/wifi/aidl/android/hardware/wifi/NanStatusCode.aidl
new file mode 100644
index 0000000..d63a50e
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanStatusCode.aidl
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * NAN API response codes used in request notifications and events.
+ */
+@VintfStability
+@Backing(type="int")
+enum NanStatusCode {
+ SUCCESS = 0,
+ /**
+ * NAN Discovery Engine/Host driver failures.
+ */
+ INTERNAL_FAILURE = 1,
+ /**
+ * NAN OTA failures.
+ */
+ PROTOCOL_FAILURE = 2,
+ /**
+ * The publish/subscribe discovery session id is invalid.
+ */
+ INVALID_SESSION_ID = 3,
+ /**
+ * Out of resources to fufill request.
+ */
+ NO_RESOURCES_AVAILABLE = 4,
+ /**
+ * Invalid arguments passed.
+ */
+ INVALID_ARGS = 5,
+ /**
+ * Invalid peer id.
+ */
+ INVALID_PEER_ID = 6,
+ /**
+ * Invalid NAN data-path (ndp) id.
+ */
+ INVALID_NDP_ID = 7,
+ /**
+ * Attempting to enable NAN when not available, e.g. wifi is disabled.
+ */
+ NAN_NOT_ALLOWED = 8,
+ /**
+ * Over the air ACK not received.
+ */
+ NO_OTA_ACK = 9,
+ /**
+ * Attempting to enable NAN when already enabled.
+ */
+ ALREADY_ENABLED = 10,
+ /**
+ * Can't queue tx followup message for transmission.
+ */
+ FOLLOWUP_TX_QUEUE_FULL = 11,
+ /**
+ * Unsupported concurrency of NAN and another feature - NAN disabled.
+ */
+ UNSUPPORTED_CONCURRENCY_NAN_DISABLED = 12,
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanSubscribeRequest.aidl b/wifi/aidl/android/hardware/wifi/NanSubscribeRequest.aidl
new file mode 100644
index 0000000..12c1170
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanSubscribeRequest.aidl
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.MacAddress;
+import android.hardware.wifi.NanDiscoveryCommonConfig;
+import android.hardware.wifi.NanSrfType;
+import android.hardware.wifi.NanSubscribeType;
+
+/**
+ * Subscribe request. Specifies a subscribe discovery operation.
+ */
+@VintfStability
+parcelable NanSubscribeRequest {
+ /**
+ * Common configuration of discovery sessions.
+ */
+ NanDiscoveryCommonConfig baseConfigs;
+ /**
+ * The type of the subscribe discovery session.
+ */
+ NanSubscribeType subscribeType;
+ /**
+ * For |NanSubscribeType.ACTIVE| subscribe discovery sessions, specifies how the Service
+ * Response Filter (SRF) attribute is populated. Relevant only if |shouldUseSrf| is set to true.
+ * NAN Spec: Service Descriptor Attribute (SDA) / Service Response Filter / SRF Control / SRF
+ * Type
+ */
+ NanSrfType srfType;
+ /**
+ * Configure whether inclusion of an address in |intfAddr| indicates that those devices should
+ * respond or the reverse. Relevant only if |shouldUseSrf| is set to true and |srfType| is set
+ * to |NanSrfType.PARTIAL_MAC_ADDR|. NAN Spec: Service Descriptor Attribute (SDA) / Service
+ * Response Filter / SRF Control / Include
+ */
+ boolean srfRespondIfInAddressSet;
+ /**
+ * Control whether the Service Response Filter (SRF) is used.
+ * NAN Spec: Service Descriptor Attribute (SDA) / Service Control /
+ * Service Response Filter Present
+ */
+ boolean shouldUseSrf;
+ /**
+ * Control whether the presence of |NanDiscoveryCommonConfig.serviceSpecificInfo| data is needed
+ * in the publisher in order to trigger service discovery, i.e. a
+ * |IWifiNanIfaceEventCallback.eventMatch|. The test is for presence of data - not for the
+ * specific contents of the data.
+ */
+ boolean isSsiRequiredForMatch;
+ /**
+ * NAN Interface Addresses constituting the Service Response Filter (SRF).
+ * Max length (number of addresses): |NanCapabilities.maxSubscribeInterfaceAddresses|.
+ * NAN Spec: Service Descriptor Attribute (SDA) / Service Response Filter / Address Set
+ */
+ MacAddress[] intfAddr;
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanSubscribeType.aidl b/wifi/aidl/android/hardware/wifi/NanSubscribeType.aidl
new file mode 100644
index 0000000..a5e8182
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanSubscribeType.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * NAN subscribe discovery session types.
+ */
+@VintfStability
+@Backing(type="int")
+enum NanSubscribeType {
+ PASSIVE = 0,
+ ACTIVE,
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanTransmitFollowupRequest.aidl b/wifi/aidl/android/hardware/wifi/NanTransmitFollowupRequest.aidl
new file mode 100644
index 0000000..c88b4ff
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanTransmitFollowupRequest.aidl
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Transmit follow up message request.
+ */
+@VintfStability
+parcelable NanTransmitFollowupRequest {
+ /**
+ * ID of an active publish or subscribe discovery session. Follow-up message is transmitted in
+ * the context of the discovery session. NAN Spec: Service Descriptor Attribute (SDA) / Instance
+ * ID
+ */
+ byte discoverySessionId;
+ /**
+ * ID of the peer. Obtained as part of an earlier |IWifiNanIfaceEventCallback.eventMatch| or
+ * |IWifiNanIfaceEventCallback.eventFollowupReceived|.
+ */
+ int peerId;
+ /**
+ * MAC address of the peer. Obtained as part of an earlier
+ * |IWifiNanIfaceEventCallback.eventMatch| or
+ * |IWifiNanIfaceEventCallback.eventFollowupReceived|.
+ */
+ byte[6] addr;
+ /**
+ * Whether the follow-up message should be transmitted with a high priority.
+ */
+ boolean isHighPriority;
+ /**
+ * Whether the follow-up message should be transmitted in a discovery window (true) or a further
+ * availability window (false).
+ */
+ boolean shouldUseDiscoveryWindow;
+ /**
+ * Arbitrary information communicated to the peer. There is no semantic meaning to these
+ * bytes. They are passed-through from sender to receiver as-is with no parsing.
+ * Max length: |NanCapabilities.maxServiceSpecificInfoLen|.
+ * NAN Spec: Service Descriptor Attribute (SDA) / Service Info
+ */
+ byte[] serviceSpecificInfo;
+ /**
+ * Arbitrary information communicated in discovery packets. There is no semantic meaning to
+ * these bytes. They are passed-through from publisher to subscriber as-is with no parsing. Max
+ * length: |NanCapabilities.maxExtendedServiceSpecificInfoLen|. Spec: Service Descriptor
+ * Extension Attribute (SDEA) / Service Info
+ */
+ byte[] extendedServiceSpecificInfo;
+ /**
+ * Disable |IWifiNanIfaceEventCallback.eventTransmitFollowup| - i.e. do not get indication on
+ * whether the follow-up was transmitted and received successfully.
+ */
+ boolean disableFollowupResultIndication;
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanTxType.aidl b/wifi/aidl/android/hardware/wifi/NanTxType.aidl
new file mode 100644
index 0000000..904a7f4
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanTxType.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * NAN transmit type used in |NanPublishType.SOLICITED| or |NanPublishType.UNSOLICITED_SOLICITED|
+ * publish discovery sessions. Describes the addressing of the packet responding to an ACTIVE
+ * subscribe query.
+ */
+@VintfStability
+@Backing(type="int")
+enum NanTxType {
+ BROADCAST = 0,
+ UNICAST,
+}
diff --git a/wifi/aidl/android/hardware/wifi/RttBw.aidl b/wifi/aidl/android/hardware/wifi/RttBw.aidl
new file mode 100644
index 0000000..9d42dc0
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/RttBw.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * RTT Measurement Bandwidth.
+ */
+@VintfStability
+@Backing(type="int")
+enum RttBw {
+ BW_5MHZ = 0x01,
+ BW_10MHZ = 0x02,
+ BW_20MHZ = 0x04,
+ BW_40MHZ = 0x08,
+ BW_80MHZ = 0x10,
+ BW_160MHZ = 0x20,
+ BW_320MHZ = 0x40,
+}
diff --git a/wifi/aidl/android/hardware/wifi/RttCapabilities.aidl b/wifi/aidl/android/hardware/wifi/RttCapabilities.aidl
new file mode 100644
index 0000000..7c47ed5
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/RttCapabilities.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.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.RttBw;
+import android.hardware.wifi.RttPreamble;
+
+/**
+ * RTT Capabilities.
+ */
+@VintfStability
+parcelable RttCapabilities {
+ /**
+ * Whether 1-sided rtt data collection is supported.
+ */
+ boolean rttOneSidedSupported;
+ /**
+ * Whether ftm rtt data collection is supported.
+ */
+ boolean rttFtmSupported;
+ /**
+ * Whether initiator supports LCI request. Applies to 2-sided RTT.
+ */
+ boolean lciSupported;
+ /**
+ * Whether initiator supports LCR request. Applies to 2-sided RTT.
+ */
+ boolean lcrSupported;
+ /**
+ * Whether 11mc responder mode is supported.
+ */
+ boolean responderSupported;
+ /**
+ * Bit mask indicating what preamble is supported by initiator.
+ * Combination of |RttPreamble| values.
+ */
+ RttPreamble preambleSupport;
+ /**
+ * Bit mask indicating what BW is supported by initiator.
+ * Combination of |RttBw| values.
+ */
+ RttBw bwSupport;
+ /**
+ * Draft 11mc spec version supported by chip.
+ * For instance, version 4.0 must be 40 and version 4.3 must be 43 etc.
+ */
+ byte mcVersion;
+}
diff --git a/wifi/aidl/android/hardware/wifi/RttConfig.aidl b/wifi/aidl/android/hardware/wifi/RttConfig.aidl
new file mode 100644
index 0000000..fc2c2e0
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/RttConfig.aidl
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.RttBw;
+import android.hardware.wifi.RttPeerType;
+import android.hardware.wifi.RttPreamble;
+import android.hardware.wifi.RttType;
+import android.hardware.wifi.WifiChannelInfo;
+
+/**
+ * RTT configuration.
+ */
+@VintfStability
+parcelable RttConfig {
+ /**
+ * Peer device mac address.
+ */
+ byte[6] addr;
+ /**
+ * 1-sided or 2-sided RTT.
+ */
+ RttType type;
+ /**
+ * Optional peer device hint (STA, P2P, AP).
+ */
+ RttPeerType peer;
+ /**
+ * Required for STA-AP mode, optional for P2P, NBD etc.
+ */
+ WifiChannelInfo channel;
+ /**
+ * Time interval between bursts (units: 100 ms).
+ * Applies to 1-sided and 2-sided RTT multi-burst requests.
+ * Range: 0-31, 0: no preference by initiator (2-sided RTT).
+ */
+ int burstPeriod;
+ /**
+ * Total number of RTT bursts to be executed. Will be
+ * specified in the same way as the parameter "Number of
+ * Burst Exponent" found in the FTM frame format. This
+ * applies to both 1-sided RTT and 2-sided RTT. Valid
+ * values are 0 to 15 as defined in 802.11mc std.
+ * 0 means single shot.
+ * The implication of this parameter on the maximum
+ * number of RTT results is the following:
+ * for 1-sided RTT: max num of RTT results = (2^num_burst)*(num_frames_per_burst)
+ * for 2-sided RTT: max num of RTT results = (2^num_burst)*(num_frames_per_burst - 1)
+ */
+ int numBurst;
+ /**
+ * Number of frames per burst.
+ * Minimum value = 1, Maximum value = 31
+ * For 2-sided, this equals the number of FTM frames
+ * to be attempted in a single burst. This also
+ * equals the number of FTM frames that the
+ * initiator will request that the responder sends
+ * in a single frame.
+ */
+ int numFramesPerBurst;
+ /**
+ * Number of retries for a failed RTT frame.
+ * Applies to 1-sided RTT only. Minimum value = 0, Maximum value = 3
+ */
+ int numRetriesPerRttFrame;
+ /**
+ * The following fields are only valid for 2-side RTT.
+ *
+ *
+ * Maximum number of retries that the initiator can
+ * retry an FTMR frame.
+ * Minimum value = 0, Maximum value = 3
+ */
+ int numRetriesPerFtmr;
+ /**
+ * Whether to request location civic info or not.
+ */
+ boolean mustRequestLci;
+ /**
+ * Whether to request location civic records or not.
+ */
+ boolean mustRequestLcr;
+ /**
+ * Applies to 1-sided and 2-sided RTT. Valid values will
+ * be 2-11 and 15 as specified by the 802.11mc std for
+ * the FTM parameter burst duration. In a multi-burst
+ * request, if responder overrides with larger value,
+ * the initiator will return failure. In a single-burst
+ * request, if responder overrides with larger value,
+ * the initiator will send TMR_STOP to terminate RTT
+ * at the end of the burst_duration it requested.
+ */
+ int burstDuration;
+ /**
+ * RTT preamble to be used in the RTT frames.
+ */
+ RttPreamble preamble;
+ /**
+ * RTT BW to be used in the RTT frames.
+ */
+ RttBw bw;
+}
diff --git a/wifi/aidl/android/hardware/wifi/RttLciInformation.aidl b/wifi/aidl/android/hardware/wifi/RttLciInformation.aidl
new file mode 100644
index 0000000..5a49de5
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/RttLciInformation.aidl
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.RttMotionPattern;
+
+/**
+ * Movement pattern unknown.
+ */
+@VintfStability
+parcelable RttLciInformation {
+ /**
+ * Latitude in degrees * 2^25 , 2's complement.
+ */
+ long latitude;
+ /**
+ * Longitude in degrees * 2^25 , 2's complement.
+ */
+ long longitude;
+ /**
+ * Altitude in units of 1/256 m.
+ */
+ int altitude;
+ /**
+ * As defined in Section 2.3.2 of IETF RFC 6225.
+ */
+ byte latitudeUnc;
+ /**
+ * As defined in Section 2.3.2 of IETF RFC 6225.
+ */
+ byte longitudeUnc;
+ /**
+ * As defined in Section 2.4.5 from IETF RFC 6225.
+ */
+ byte altitudeUnc;
+ /**
+ * The following elements are for configuring the Z subelement.
+ *
+ *
+ * Motion pattern type.
+ */
+ RttMotionPattern motionPattern;
+ /**
+ * Floor in units of 1/16th of floor. 0x80000000 if unknown.
+ */
+ int floor;
+ /**
+ * In units of 1/64 m.
+ */
+ int heightAboveFloor;
+ /**
+ * In units of 1/64 m. 0 if unknown.
+ */
+ int heightUnc;
+}
diff --git a/wifi/aidl/android/hardware/wifi/RttLcrInformation.aidl b/wifi/aidl/android/hardware/wifi/RttLcrInformation.aidl
new file mode 100644
index 0000000..b3bb13a
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/RttLcrInformation.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+@VintfStability
+parcelable RttLcrInformation {
+ /**
+ * Country code symbol.
+ */
+ byte[2] countryCode;
+ /**
+ * Civic info to be copied in FTM frame.
+ */
+ String civicInfo;
+}
diff --git a/wifi/aidl/android/hardware/wifi/RttMotionPattern.aidl b/wifi/aidl/android/hardware/wifi/RttMotionPattern.aidl
new file mode 100644
index 0000000..00517ac
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/RttMotionPattern.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+@VintfStability
+@Backing(type="int")
+enum RttMotionPattern {
+ /**
+ * Not expected to change location.
+ */
+ NOT_EXPECTED = 0,
+ /**
+ * Expected to change location.
+ */
+ EXPECTED = 1,
+ /**
+ * Movement pattern unknown.
+ */
+ UNKNOWN = 2,
+}
diff --git a/wifi/aidl/android/hardware/wifi/RttPeerType.aidl b/wifi/aidl/android/hardware/wifi/RttPeerType.aidl
new file mode 100644
index 0000000..148a8cc
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/RttPeerType.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * RTT peer types.
+ */
+@VintfStability
+@Backing(type="int")
+enum RttPeerType {
+ AP = 1,
+ STA = 2,
+ P2P_GO = 3,
+ P2P_CLIENT = 4,
+ NAN_TYPE = 5,
+}
diff --git a/wifi/aidl/android/hardware/wifi/RttPreamble.aidl b/wifi/aidl/android/hardware/wifi/RttPreamble.aidl
new file mode 100644
index 0000000..e460a94
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/RttPreamble.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * RTT Measurement Preamble.
+ */
+@VintfStability
+@Backing(type="int")
+enum RttPreamble {
+ LEGACY = 0x1,
+ HT = 0x2,
+ VHT = 0x4,
+ /**
+ * Preamble type for 11ax
+ */
+ HE = 0x8,
+ /**
+ * Preamble type for 11be
+ */
+ EHT = 0x10,
+}
diff --git a/wifi/aidl/android/hardware/wifi/RttResponder.aidl b/wifi/aidl/android/hardware/wifi/RttResponder.aidl
new file mode 100644
index 0000000..a16f274
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/RttResponder.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.RttPreamble;
+import android.hardware.wifi.WifiChannelInfo;
+
+/**
+ * RTT Responder information.
+ */
+@VintfStability
+parcelable RttResponder {
+ WifiChannelInfo channel;
+ RttPreamble preamble;
+}
diff --git a/wifi/aidl/android/hardware/wifi/RttResult.aidl b/wifi/aidl/android/hardware/wifi/RttResult.aidl
new file mode 100644
index 0000000..565cce7
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/RttResult.aidl
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.RttStatus;
+import android.hardware.wifi.RttType;
+import android.hardware.wifi.WifiInformationElement;
+import android.hardware.wifi.WifiRateInfo;
+
+/**
+ * RTT results.
+ */
+@VintfStability
+parcelable RttResult {
+ /**
+ * Peer device mac address.
+ */
+ byte[6] addr;
+ /**
+ * Burst number in a multi-burst request.
+ */
+ int burstNum;
+ /**
+ * Total RTT measurement frames attempted.
+ */
+ int measurementNumber;
+ /**
+ * Total successful RTT measurement frames.
+ */
+ int successNumber;
+ /**
+ * Maximum number of "FTM frames per burst" supported by
+ * the responder STA. Applies to 2-sided RTT only.
+ * If reponder overrides with larger value:
+ * - for single-burst request, initiator will truncate the
+ * larger value and send a TMR_STOP after receiving as
+ * many frames as originally requested.
+ * - for multi-burst request, initiator will return
+ * failure right away.
+ */
+ byte numberPerBurstPeer;
+ /**
+ * Ranging status.
+ */
+ RttStatus status;
+ /**
+ * If status is RTT_STATUS_FAIL_BUSY_TRY_LATER,
+ * this will be the time provided by the responder as to
+ * when the request can be tried again. Applies to 2-sided
+ * RTT only. In sec, 1-31 sec.
+ */
+ byte retryAfterDuration;
+ /**
+ * RTT type.
+ */
+ RttType type;
+ /**
+ * Average rssi in 0.5 dB steps (e.g. 143 implies -71.5 dB).
+ */
+ int rssi;
+ /**
+ * Rssi spread in 0.5 dB steps (e.g. 5 implies 2.5 dB spread) - optional.
+ */
+ int rssiSpread;
+ /**
+ * 1-sided RTT: TX rate of RTT frame.
+ * 2-sided RTT: TX rate of initiator's Ack in response to FTM frame.
+ */
+ WifiRateInfo txRate;
+ /**
+ * 1-sided RTT: TX rate of Ack from other side.
+ * 2-sided RTT: TX rate of FTM frame coming from responder.
+ */
+ WifiRateInfo rxRate;
+ /**
+ * Round trip time in picoseconds.
+ */
+ long rtt;
+ /**
+ * Rtt standard deviation in picoseconds.
+ */
+ long rttSd;
+ /**
+ * Difference between max and min rtt times recorded in picoseconds.
+ */
+ long rttSpread;
+ /**
+ * Distance in mm (optional).
+ */
+ int distanceInMm;
+ /**
+ * Standard deviation in mm (optional).
+ */
+ int distanceSdInMm;
+ /**
+ * Difference between max and min distance recorded in mm (optional).
+ */
+ int distanceSpreadInMm;
+ /**
+ * Time of the measurement (in microseconds since boot).
+ */
+ long timeStampInUs;
+ /**
+ * Actual time taken by the FW to finish one burst
+ * measurement (in ms). Applies to 1-sided and 2-sided RTT.
+ */
+ int burstDurationInMs;
+ /**
+ * Number of bursts allowed by the responder. Applies
+ * to 2-sided RTT only.
+ */
+ int negotiatedBurstNum;
+ /**
+ * For 11mc only.
+ */
+ WifiInformationElement lci;
+ /**
+ * For 11mc only.
+ */
+ WifiInformationElement lcr;
+}
diff --git a/wifi/aidl/android/hardware/wifi/RttStatus.aidl b/wifi/aidl/android/hardware/wifi/RttStatus.aidl
new file mode 100644
index 0000000..600165c
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/RttStatus.aidl
@@ -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.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Ranging status.
+ */
+@VintfStability
+@Backing(type="int")
+enum RttStatus {
+ SUCCESS = 0,
+ /**
+ * General failure status.
+ */
+ FAILURE = 1,
+ /**
+ * Target STA does not respond to request.
+ */
+ FAIL_NO_RSP = 2,
+ /**
+ * Request rejected. Applies to 2-sided RTT only.
+ */
+ FAIL_REJECTED = 3,
+ FAIL_NOT_SCHEDULED_YET = 4,
+ /**
+ * Timing measurement times out.
+ */
+ FAIL_TM_TIMEOUT = 5,
+ /**
+ * Target on different channel, cannot range.
+ */
+ FAIL_AP_ON_DIFF_CHANNEL = 6,
+ /**
+ * Ranging not supported.
+ */
+ FAIL_NO_CAPABILITY = 7,
+ /**
+ * Request aborted for an unknown reason.
+ */
+ ABORTED = 8,
+ /**
+ * Invalid T1-T4 timestamp.
+ */
+ FAIL_INVALID_TS = 9,
+ /**
+ * 11mc protocol failed.
+ */
+ FAIL_PROTOCOL = 10,
+ /**
+ * Request could not be scheduled.
+ */
+ FAIL_SCHEDULE = 11,
+ /**
+ * Responder cannot collaborate at time of request.
+ */
+ FAIL_BUSY_TRY_LATER = 12,
+ /**
+ * Bad request args.
+ */
+ INVALID_REQ = 13,
+ /**
+ * WiFi not enabled.
+ */
+ NO_WIFI = 14,
+ /**
+ * Responder overrides param info, cannot range with new params.
+ */
+ FAIL_FTM_PARAM_OVERRIDE = 15,
+ /**
+ * NAN ranging negotiation failure.
+ */
+ NAN_RANGING_PROTOCOL_FAILURE = 16,
+ /**
+ * NAN concurrency not supported (NDP + RTT).
+ */
+ NAN_RANGING_CONCURRENCY_NOT_SUPPORTED = 17,
+}
diff --git a/wifi/aidl/android/hardware/wifi/RttType.aidl b/wifi/aidl/android/hardware/wifi/RttType.aidl
new file mode 100644
index 0000000..e95a928
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/RttType.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * RTT Types.
+ */
+@VintfStability
+@Backing(type="int")
+enum RttType {
+ ONE_SIDED = 1,
+ TWO_SIDED = 2,
+}
diff --git a/wifi/aidl/android/hardware/wifi/Ssid.aidl b/wifi/aidl/android/hardware/wifi/Ssid.aidl
new file mode 100644
index 0000000..fd985a3
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/Ssid.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Byte array representing an Ssid. Use when we need to
+ * pass an array of Ssid's to a method, as variable-sized
+ * 2D arrays are not supported in AIDL.
+ *
+ * TODO (b/210705533): Replace this type with a 2D byte array.
+ */
+@VintfStability
+parcelable Ssid {
+ byte[32] data;
+}
diff --git a/wifi/aidl/android/hardware/wifi/StaApfPacketFilterCapabilities.aidl b/wifi/aidl/android/hardware/wifi/StaApfPacketFilterCapabilities.aidl
new file mode 100644
index 0000000..5063b49
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/StaApfPacketFilterCapabilities.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Parameters to specify the APF capabilities of this iface.
+ */
+@VintfStability
+parcelable StaApfPacketFilterCapabilities {
+ /**
+ * Version of the packet filter interpreter supported.
+ */
+ int version;
+ /**
+ * Maximum size of the filter bytecode in bytes for an iface.
+ */
+ int maxLength;
+}
diff --git a/wifi/aidl/android/hardware/wifi/StaBackgroundScanBucketEventReportSchemeMask.aidl b/wifi/aidl/android/hardware/wifi/StaBackgroundScanBucketEventReportSchemeMask.aidl
new file mode 100644
index 0000000..92e2928
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/StaBackgroundScanBucketEventReportSchemeMask.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Mask of event reporting schemes that can be specified in background scan
+ * requests.
+ */
+@VintfStability
+@Backing(type="int")
+enum StaBackgroundScanBucketEventReportSchemeMask {
+ /**
+ * Report a scan completion event after scan. If this is not set, then scan
+ * completion events must be reported if report_threshold_percent or
+ * report_threshold_num_scans is reached.
+ */
+ EACH_SCAN = 1 << 0,
+ /**
+ * Forward scan results (beacons/probe responses + IEs) in real time to HAL,
+ * in addition to completion events.
+ * Note: To keep backward compatibility, fire completion events regardless
+ * of REPORT_EVENTS_EACH_SCAN.
+ */
+ FULL_RESULTS = 1 << 1,
+ /**
+ * Controls if scans for this bucket must be placed in the results buffer.
+ */
+ NO_BATCH = 1 << 2,
+}
diff --git a/wifi/aidl/android/hardware/wifi/StaBackgroundScanBucketParameters.aidl b/wifi/aidl/android/hardware/wifi/StaBackgroundScanBucketParameters.aidl
new file mode 100644
index 0000000..7bd87b2
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/StaBackgroundScanBucketParameters.aidl
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.StaBackgroundScanBucketEventReportSchemeMask;
+import android.hardware.wifi.WifiBand;
+
+/**
+ * Background Scan parameters per bucket that can be specified in background
+ * scan requests.
+ */
+@VintfStability
+parcelable StaBackgroundScanBucketParameters {
+ /**
+ * Bucket index. This index is used to report results in
+ * |StaScanData.bucketsScanned|.
+ */
+ int bucketIdx;
+ /**
+ * Bands to scan or |BAND_UNSPECIFIED| if frequencies list must be used
+ * instead.
+ */
+ WifiBand band;
+ /**
+ * Channel frequencies (in Mhz) to scan if |band| is set to
+ * |BAND_UNSPECIFIED|.
+ * Max length: |StaBackgroundScanLimits.MAX_CHANNELS|.
+ */
+ int[] frequencies;
+ /**
+ * Period at which this bucket must be scanned (in milliseconds). Must be an integer
+ * multiple of the |basePeriodInMs| specified in the BackgroundScanParameters.
+ */
+ int periodInMs;
+ /**
+ * Bitset of |StaBackgroundScanBucketEventReportSchemeMask| values controlling
+ * when events for this bucket must be reported.
+ */
+ StaBackgroundScanBucketEventReportSchemeMask eventReportScheme;
+ /**
+ * For exponential back off. If |exponentialMaxPeriodInMs| is non-zero or
+ * different than period, then this bucket is an exponential backoff bucket
+ * and the scan period must grow exponentially as per formula:
+ * actual_period(N) = period * (base ^ (N/step_count))
+ * to this maximum period (in milliseconds).
+ */
+ int exponentialMaxPeriodInMs;
+ /**
+ * For exponential back off. Multiplier: new_period=old_period * base
+ */
+ int exponentialBase;
+ /**
+ * For exponential back off. Number of scans to perform for a given
+ * period.
+ */
+ int exponentialStepCount;
+}
diff --git a/wifi/aidl/android/hardware/wifi/StaBackgroundScanCapabilities.aidl b/wifi/aidl/android/hardware/wifi/StaBackgroundScanCapabilities.aidl
new file mode 100644
index 0000000..8dd9141
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/StaBackgroundScanCapabilities.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Parameters to specify the Background Scan capabilities of this iface.
+ */
+@VintfStability
+parcelable StaBackgroundScanCapabilities {
+ /**
+ * Maximum number of bytes available for cached scan results.
+ */
+ int maxCacheSize;
+ /**
+ * Maximum number of buckets that can be supplied for a scan.
+ */
+ int maxBuckets;
+ /**
+ * Maximum number of APs that must be stored for each scan.
+ */
+ int maxApCachePerScan;
+ /**
+ * Max reporting number of scans threshold that can be specified in the scan
+ * parameters.
+ */
+ int maxReportingThreshold;
+}
diff --git a/wifi/aidl/android/hardware/wifi/StaBackgroundScanLimits.aidl b/wifi/aidl/android/hardware/wifi/StaBackgroundScanLimits.aidl
new file mode 100644
index 0000000..b6fc44c
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/StaBackgroundScanLimits.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Max limits for background scan.
+ */
+@VintfStability
+@Backing(type="int")
+enum StaBackgroundScanLimits {
+ MAX_CHANNELS = 16,
+ MAX_BUCKETS = 16,
+ MAX_AP_CACHE_PER_SCAN = 32,
+}
diff --git a/wifi/aidl/android/hardware/wifi/StaBackgroundScanParameters.aidl b/wifi/aidl/android/hardware/wifi/StaBackgroundScanParameters.aidl
new file mode 100644
index 0000000..0b56069
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/StaBackgroundScanParameters.aidl
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.StaBackgroundScanBucketParameters;
+
+/**
+ * Background Scan parameters that can be specified in background scan
+ * requests.
+ */
+@VintfStability
+parcelable StaBackgroundScanParameters {
+ /**
+ * GCD of all bucket periods (in milliseconds).
+ */
+ int basePeriodInMs;
+ /**
+ * Maximum number of APs that must be stored for each scan. If the maximum
+ * is reached, then the highest RSSI results must be returned.
+ * Max length: |StaBackgroundScanLimits.MAX_AP_CACHE_PER_SCAN|.
+ */
+ int maxApPerScan;
+ /**
+ * % cache buffer filled threshold at which the host must be notified of
+ * batched scan results.
+ */
+ int reportThresholdPercent;
+ /**
+ * Threshold at which the AP must be woken up, in number of scans.
+ */
+ int reportThresholdNumScans;
+ /**
+ * List of buckets to be scheduled.
+ * Max length: |StaBackgroundScanLimits.MAX_BUCKETS|.
+ */
+ StaBackgroundScanBucketParameters[] buckets;
+}
diff --git a/wifi/aidl/android/hardware/wifi/StaLinkLayerIfaceContentionTimeStats.aidl b/wifi/aidl/android/hardware/wifi/StaLinkLayerIfaceContentionTimeStats.aidl
new file mode 100644
index 0000000..51f6916
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/StaLinkLayerIfaceContentionTimeStats.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Contention time statistics for different traffic categories.
+ */
+@VintfStability
+parcelable StaLinkLayerIfaceContentionTimeStats {
+ /**
+ * Data packet min contention time (usec). This includes both the internal contention time
+ * among different access categories within the chipset and the contention time for the medium.
+ */
+ int contentionTimeMinInUsec;
+ /**
+ * Data packet max contention time (usec). This includes both the internal contention time
+ * among different access categories within the chipset and the contention time for the medium.
+ */
+ int contentionTimeMaxInUsec;
+ /**
+ * Data packet average contention time (usec). This includes both the internal contention time
+ * among different access categories within the chipset and the contention time for the medium.
+ */
+ int contentionTimeAvgInUsec;
+ /**
+ * Number of data packets used for contention statistics.
+ */
+ int contentionNumSamples;
+}
diff --git a/wifi/aidl/android/hardware/wifi/StaLinkLayerIfacePacketStats.aidl b/wifi/aidl/android/hardware/wifi/StaLinkLayerIfacePacketStats.aidl
new file mode 100644
index 0000000..c0e2c7b
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/StaLinkLayerIfacePacketStats.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Packet stats for different traffic categories.
+ */
+@VintfStability
+parcelable StaLinkLayerIfacePacketStats {
+ /**
+ * Number of received unicast data packets.
+ */
+ long rxMpdu;
+ /**
+ * Number of successfully transmitted unicast data pkts (ACK rcvd).
+ */
+ long txMpdu;
+ /**
+ * Number of transmitted unicast data pkt losses (no ACK).
+ */
+ long lostMpdu;
+ /**
+ * Number of transmitted unicast data retry pkts.
+ */
+ long retries;
+}
diff --git a/wifi/aidl/android/hardware/wifi/StaLinkLayerIfaceStats.aidl b/wifi/aidl/android/hardware/wifi/StaLinkLayerIfaceStats.aidl
new file mode 100644
index 0000000..78f8caa
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/StaLinkLayerIfaceStats.aidl
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.StaLinkLayerIfaceContentionTimeStats;
+import android.hardware.wifi.StaLinkLayerIfacePacketStats;
+import android.hardware.wifi.StaPeerInfo;
+
+/**
+ * Iface statistics for the current connection.
+ */
+@VintfStability
+parcelable StaLinkLayerIfaceStats {
+ /**
+ * Number beacons received from the connected AP.
+ */
+ int beaconRx;
+ /**
+ * Access Point Beacon and Management frames RSSI (averaged).
+ */
+ int avgRssiMgmt;
+ /**
+ * WME Best Effort Access Category packet counters.
+ */
+ StaLinkLayerIfacePacketStats wmeBePktStats;
+ /**
+ * WME Background Access Category packet counters.
+ */
+ StaLinkLayerIfacePacketStats wmeBkPktStats;
+ /**
+ * WME Video Access Category packet counters.
+ */
+ StaLinkLayerIfacePacketStats wmeViPktStats;
+ /**
+ * WME Voice Access Category packet counters.
+ */
+ StaLinkLayerIfacePacketStats wmeVoPktStats;
+ /**
+ * Duty cycle for the iface.
+ * If this iface is being served using time slicing on a radio with one or more ifaces
+ * (i.e MCC), then the duty cycle assigned to this iface in %.
+ * If not using time slicing (i.e SCC or DBS), set to 100.
+ */
+ byte timeSliceDutyCycleInPercent;
+ /**
+ * WME Best Effort (BE) Access Category (AC) contention time statistics.
+ */
+ StaLinkLayerIfaceContentionTimeStats wmeBeContentionTimeStats;
+ /**
+ * WME Background (BK) Access Category (AC) contention time statistics.
+ */
+ StaLinkLayerIfaceContentionTimeStats wmeBkContentionTimeStats;
+ /**
+ * WME Video (VI) Access Category (AC) contention time statistics.
+ */
+ StaLinkLayerIfaceContentionTimeStats wmeViContentionTimeStats;
+ /**
+ * WME Voice (VO) Access Category (AC) contention time statistics.
+ */
+ StaLinkLayerIfaceContentionTimeStats wmeVoContentionTimeStats;
+ /**
+ * Per peer statistics.
+ */
+ StaPeerInfo[] peers;
+}
diff --git a/wifi/aidl/android/hardware/wifi/StaLinkLayerRadioStats.aidl b/wifi/aidl/android/hardware/wifi/StaLinkLayerRadioStats.aidl
new file mode 100644
index 0000000..6105172
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/StaLinkLayerRadioStats.aidl
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.WifiChannelStats;
+
+@VintfStability
+parcelable StaLinkLayerRadioStats {
+ /**
+ * Time for which the radio is awake.
+ */
+ int onTimeInMs;
+ /**
+ * Total time for which the radio is in active transmission.
+ */
+ int txTimeInMs;
+ /**
+ * Time for which the radio is in active tranmission per tx level.
+ */
+ int[] txTimeInMsPerLevel;
+ /**
+ * Time for which the radio is in active receive.
+ */
+ int rxTimeInMs;
+ /**
+ * Total time for which the radio is awake due to scan.
+ */
+ int onTimeInMsForScan;
+ /**
+ * Total time for which the radio is awake due to NAN scan since boot or crash.
+ */
+ int onTimeInMsForNanScan;
+ /**
+ * Total time for which the radio is awake due to background scan since boot or crash.
+ */
+ int onTimeInMsForBgScan;
+ /**
+ * Total time for which the radio is awake due to roam scan since boot or crash.
+ */
+ int onTimeInMsForRoamScan;
+ /**
+ * Total time for which the radio is awake due to PNO scan since boot or crash.
+ */
+ int onTimeInMsForPnoScan;
+ /**
+ * Total time for which the radio is awake due to Hotspot 2.0 scans and GAS exchange since boot
+ * or crash.
+ */
+ int onTimeInMsForHs20Scan;
+ /**
+ * List of channel stats associated with this radio.
+ */
+ WifiChannelStats[] channelStats;
+ /**
+ * Radio ID: An implementation specific value identifying the radio interface for which the
+ * stats are produced. Framework must not interpret this value. It must use this value for
+ * persistently identifying the statistics between calls,
+ * e.g. if the HAL provides them in different order.
+ */
+ int radioId;
+}
diff --git a/wifi/aidl/android/hardware/wifi/StaLinkLayerStats.aidl b/wifi/aidl/android/hardware/wifi/StaLinkLayerStats.aidl
new file mode 100644
index 0000000..32be121
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/StaLinkLayerStats.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.StaLinkLayerIfaceStats;
+import android.hardware.wifi.StaLinkLayerRadioStats;
+
+/**
+ * Link layer stats retrieved via |IWifiStaIface.getLinkLayerStats|.
+ */
+@VintfStability
+parcelable StaLinkLayerStats {
+ StaLinkLayerIfaceStats iface;
+ StaLinkLayerRadioStats[] radios;
+ /**
+ * Timestamp for each stats sample. This is the absolute milliseconds
+ * from boot when these stats were sampled.
+ */
+ long timeStampInMs;
+}
diff --git a/wifi/aidl/android/hardware/wifi/StaPeerInfo.aidl b/wifi/aidl/android/hardware/wifi/StaPeerInfo.aidl
new file mode 100644
index 0000000..2032802
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/StaPeerInfo.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.StaRateStat;
+
+/**
+ * Per peer statistics. Types of peers include the Access Point (AP), Tunneled Direct Link
+ * Setup (TDLS), Group Owner (GO), Neighbor Awareness Networking (NAN), etc.
+ */
+@VintfStability
+parcelable StaPeerInfo {
+ /**
+ * Station count: The total number of stations currently associated with the peer.
+ */
+ char staCount;
+ /**
+ * Channel utilization: The percentage of time (normalized to 255, i.e., x% corresponds to
+ * (int) x * 255 / 100) that the medium is sensed as busy measured by either physical or
+ * virtual carrier sense (CS) mechanism.
+ */
+ char chanUtil;
+ /**
+ * Per rate statistics.
+ */
+ StaRateStat[] rateStats;
+}
diff --git a/wifi/aidl/android/hardware/wifi/StaRateStat.aidl b/wifi/aidl/android/hardware/wifi/StaRateStat.aidl
new file mode 100644
index 0000000..8326884
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/StaRateStat.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.WifiRateInfo;
+
+/**
+ * Per rate statistics. The rate is characterized by the combination of preamble, number
+ * of spatial streams, transmission bandwidth, and modulation and coding scheme (MCS).
+ */
+@VintfStability
+parcelable StaRateStat {
+ /**
+ * Wifi rate information: preamble, number of spatial streams, bandwidth, MCS, etc.
+ */
+ WifiRateInfo rateInfo;
+ /**
+ * Number of successfully transmitted data packets (ACK received).
+ */
+ int txMpdu;
+ /**
+ * Number of received data packets.
+ */
+ int rxMpdu;
+ /**
+ * Number of data packet losses (no ACK).
+ */
+ int mpduLost;
+ /**
+ * Number of data packet retries.
+ */
+ int retries;
+}
diff --git a/wifi/aidl/android/hardware/wifi/StaRoamingCapabilities.aidl b/wifi/aidl/android/hardware/wifi/StaRoamingCapabilities.aidl
new file mode 100644
index 0000000..7642612
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/StaRoamingCapabilities.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Structure describing the roaming control capabilities supported.
+ */
+@VintfStability
+parcelable StaRoamingCapabilities {
+ /**
+ * Maximum number of BSSIDs that may be blocklisted.
+ */
+ int maxBlocklistSize;
+ /**
+ * Maximum number of SSIDs that may be allowlisted.
+ */
+ int maxAllowlistSize;
+}
diff --git a/wifi/aidl/android/hardware/wifi/StaRoamingConfig.aidl b/wifi/aidl/android/hardware/wifi/StaRoamingConfig.aidl
new file mode 100644
index 0000000..c59c531
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/StaRoamingConfig.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.MacAddress;
+import android.hardware.wifi.Ssid;
+
+/**
+ * Structure describing the roaming control configuration.
+ */
+@VintfStability
+parcelable StaRoamingConfig {
+ /**
+ * List of BSSIDs that are blocklisted for roaming.
+ */
+ MacAddress[] bssidBlocklist;
+ /**
+ * List of SSIDs that are allowlisted for roaming.
+ */
+ Ssid[] ssidAllowlist;
+}
diff --git a/wifi/aidl/android/hardware/wifi/StaRoamingState.aidl b/wifi/aidl/android/hardware/wifi/StaRoamingState.aidl
new file mode 100644
index 0000000..d75d323
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/StaRoamingState.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Enum describing the various states to set the roaming
+ * control to.
+ */
+@VintfStability
+@Backing(type="byte")
+enum StaRoamingState {
+ /**
+ * Driver/Firmware must not perform any roaming.
+ */
+ DISABLED = 0,
+ /**
+ * Driver/Firmware is allowed to perform roaming while respecting
+ * the |StaRoamingConfig| parameters set using |configureRoaming|.
+ */
+ ENABLED = 1,
+}
diff --git a/wifi/aidl/android/hardware/wifi/StaScanData.aidl b/wifi/aidl/android/hardware/wifi/StaScanData.aidl
new file mode 100644
index 0000000..9d6bd53
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/StaScanData.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.StaScanDataFlagMask;
+import android.hardware.wifi.StaScanResult;
+
+/**
+ * Structure describing all of the access points seen during
+ * the scan.
+ */
+@VintfStability
+parcelable StaScanData {
+ /**
+ * Bitset containing |ScanDataFlagMask| values.
+ */
+ StaScanDataFlagMask flags;
+ /**
+ * Bitset where each bit indicates if the bucket with that index (starting at
+ * 0) was scanned.
+ */
+ int bucketsScanned;
+ /**
+ * List of scan results.
+ */
+ StaScanResult[] results;
+}
diff --git a/wifi/aidl/android/hardware/wifi/StaScanDataFlagMask.aidl b/wifi/aidl/android/hardware/wifi/StaScanDataFlagMask.aidl
new file mode 100644
index 0000000..ea87df5
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/StaScanDataFlagMask.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Mask of flags set in the |ScanData| instance.
+ */
+@VintfStability
+@Backing(type="int")
+enum StaScanDataFlagMask {
+ /**
+ * Indicates that a scan was interrupted/did not occur, so results may be
+ * incomplete.
+ */
+ INTERRUPTED = 1 << 0,
+}
diff --git a/wifi/aidl/android/hardware/wifi/StaScanResult.aidl b/wifi/aidl/android/hardware/wifi/StaScanResult.aidl
new file mode 100644
index 0000000..9f6f415
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/StaScanResult.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.WifiInformationElement;
+
+/**
+ * Structure describing all the information about a single access point seen
+ * during the scan.
+ */
+@VintfStability
+parcelable StaScanResult {
+ long timeStampInUs;
+ byte[] ssid;
+ byte[6] bssid;
+ int rssi;
+ int frequency;
+ char beaconPeriodInMs;
+ char capability;
+ WifiInformationElement[] informationElements;
+}
diff --git a/wifi/aidl/android/hardware/wifi/WifiAntennaMode.aidl b/wifi/aidl/android/hardware/wifi/WifiAntennaMode.aidl
new file mode 100644
index 0000000..e21dd87
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/WifiAntennaMode.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Antenna configuration.
+ */
+@VintfStability
+@Backing(type="int")
+enum WifiAntennaMode {
+ WIFI_ANTENNA_MODE_UNSPECIFIED = 0,
+ WIFI_ANTENNA_MODE_1X1 = 1,
+ WIFI_ANTENNA_MODE_2X2 = 2,
+ WIFI_ANTENNA_MODE_3X3 = 3,
+ WIFI_ANTENNA_MODE_4X4 = 4,
+}
diff --git a/wifi/aidl/android/hardware/wifi/WifiBand.aidl b/wifi/aidl/android/hardware/wifi/WifiBand.aidl
new file mode 100644
index 0000000..cfdf944
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/WifiBand.aidl
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Wifi bands defined in the 80211 spec.
+ */
+@VintfStability
+@Backing(type="int")
+enum WifiBand {
+ BAND_UNSPECIFIED = 0,
+ /**
+ * 2.4 GHz.
+ */
+ BAND_24GHZ = 1,
+ /**
+ * 5 GHz without DFS.
+ */
+ BAND_5GHZ = 2,
+ /**
+ * 5 GHz DFS only.
+ */
+ BAND_5GHZ_DFS = 4,
+ /**
+ * 5 GHz with DFS.
+ */
+ BAND_5GHZ_WITH_DFS = 6,
+ /**
+ * 2.4 GHz + 5 GHz; no DFS.
+ */
+ BAND_24GHZ_5GHZ = 3,
+ /**
+ * 2.4 GHz + 5 GHz with DFS.
+ */
+ BAND_24GHZ_5GHZ_WITH_DFS = 7,
+ /**
+ * 6 GHz.
+ */
+ BAND_6GHZ = 8,
+ /**
+ * 5 GHz no DFS + 6 GHz.
+ */
+ BAND_5GHZ_6GHZ = 10,
+ /**
+ * 2.4 GHz + 5 GHz no DFS + 6 GHz.
+ */
+ BAND_24GHZ_5GHZ_6GHZ = 11,
+ /**
+ * 2.4 GHz + 5 GHz with DFS + 6 GHz.
+ */
+ BAND_24GHZ_5GHZ_WITH_DFS_6GHZ = 15,
+ /**
+ * 60 GHz.
+ */
+ BAND_60GHZ = 16,
+ /**
+ * 2.4 GHz + 5 GHz no DFS + 6 GHz + 60 GHz.
+ */
+ BAND_24GHZ_5GHZ_6GHZ_60GHZ = 27,
+ /**
+ * 2.4 GHz + 5 GHz with DFS + 6 GHz + 60 GHz.
+ */
+ BAND_24GHZ_5GHZ_WITH_DFS_6GHZ_60GHZ = 31,
+}
diff --git a/wifi/aidl/android/hardware/wifi/WifiChannelInfo.aidl b/wifi/aidl/android/hardware/wifi/WifiChannelInfo.aidl
new file mode 100644
index 0000000..8fee7eb
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/WifiChannelInfo.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.WifiChannelWidthInMhz;
+
+/**
+ * Channel information.
+ */
+@VintfStability
+parcelable WifiChannelInfo {
+ /**
+ * Channel width (20, 40, 80, 80+80, 160, 320).
+ */
+ WifiChannelWidthInMhz width;
+ /**
+ * Primary 20 MHz channel.
+ */
+ int centerFreq;
+ /**
+ * Center frequency (MHz) first segment.
+ */
+ int centerFreq0;
+ /**
+ * Center frequency (MHz) second segment.
+ */
+ int centerFreq1;
+}
diff --git a/wifi/aidl/android/hardware/wifi/WifiChannelStats.aidl b/wifi/aidl/android/hardware/wifi/WifiChannelStats.aidl
new file mode 100644
index 0000000..f77821b
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/WifiChannelStats.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.WifiChannelInfo;
+
+@VintfStability
+parcelable WifiChannelStats {
+ /**
+ * Channel information.
+ */
+ WifiChannelInfo channel;
+ /**
+ * Total time for which the radio is awake on this channel.
+ */
+ int onTimeInMs;
+ /**
+ * Total time for which CCA is held busy on this channel.
+ */
+ int ccaBusyTimeInMs;
+}
diff --git a/wifi/aidl/android/hardware/wifi/WifiChannelWidthInMhz.aidl b/wifi/aidl/android/hardware/wifi/WifiChannelWidthInMhz.aidl
new file mode 100644
index 0000000..e456530
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/WifiChannelWidthInMhz.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Channel operating width in Mhz.
+ */
+@VintfStability
+@Backing(type="int")
+enum WifiChannelWidthInMhz {
+ WIDTH_INVALID = -1,
+ WIDTH_20 = 0,
+ WIDTH_40 = 1,
+ WIDTH_80 = 2,
+ WIDTH_160 = 3,
+ WIDTH_80P80 = 4,
+ WIDTH_5 = 5,
+ WIDTH_10 = 6,
+ /**
+ * 320 MHz
+ */
+ WIDTH_320 = 7,
+}
diff --git a/wifi/aidl/android/hardware/wifi/WifiDebugHostWakeReasonRxIcmpPacketDetails.aidl b/wifi/aidl/android/hardware/wifi/WifiDebugHostWakeReasonRxIcmpPacketDetails.aidl
new file mode 100644
index 0000000..8cf4819
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/WifiDebugHostWakeReasonRxIcmpPacketDetails.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Struct capturing the count of all rx ICMP packets that caused
+ * host wakeup.
+ */
+@VintfStability
+parcelable WifiDebugHostWakeReasonRxIcmpPacketDetails {
+ /**
+ * Wake icmp packet count.
+ */
+ int icmpPkt;
+ /**
+ * Wake icmp6 packet count.
+ */
+ int icmp6Pkt;
+ /**
+ * Wake icmp6 RA packet count.
+ */
+ int icmp6Ra;
+ /**
+ * Wake icmp6 NA packet count.
+ */
+ int icmp6Na;
+ /**
+ * Wake icmp6 NS packet count.
+ */
+ int icmp6Ns;
+}
diff --git a/wifi/aidl/android/hardware/wifi/WifiDebugHostWakeReasonRxMulticastPacketDetails.aidl b/wifi/aidl/android/hardware/wifi/WifiDebugHostWakeReasonRxMulticastPacketDetails.aidl
new file mode 100644
index 0000000..51faf66
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/WifiDebugHostWakeReasonRxMulticastPacketDetails.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Struct capturing the count of all rx multicast packets that caused
+ * host wakeup.
+ */
+@VintfStability
+parcelable WifiDebugHostWakeReasonRxMulticastPacketDetails {
+ /**
+ * Rx wake packet was ipv4 multicast.
+ */
+ int ipv4RxMulticastAddrCnt;
+ /**
+ * Rx wake packet was ipv6 multicast.
+ */
+ int ipv6RxMulticastAddrCnt;
+ /**
+ * Rx wake packet was non-ipv4 and non-ipv6.
+ */
+ int otherRxMulticastAddrCnt;
+}
diff --git a/wifi/aidl/android/hardware/wifi/WifiDebugHostWakeReasonRxPacketDetails.aidl b/wifi/aidl/android/hardware/wifi/WifiDebugHostWakeReasonRxPacketDetails.aidl
new file mode 100644
index 0000000..b5c6a5e
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/WifiDebugHostWakeReasonRxPacketDetails.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Struct capturing the count of all rx packets that caused
+ * host wakeup.
+ */
+@VintfStability
+parcelable WifiDebugHostWakeReasonRxPacketDetails {
+ /**
+ * Total rx unicast packet which woke up host.
+ */
+ int rxUnicastCnt;
+ /**
+ * Total rx multicast packet which woke up host.
+ */
+ int rxMulticastCnt;
+ /**
+ * Total rx broadcast packet which woke up host.
+ */
+ int rxBroadcastCnt;
+}
diff --git a/wifi/aidl/android/hardware/wifi/WifiDebugHostWakeReasonStats.aidl b/wifi/aidl/android/hardware/wifi/WifiDebugHostWakeReasonStats.aidl
new file mode 100644
index 0000000..82d5d3e
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/WifiDebugHostWakeReasonStats.aidl
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.WifiDebugHostWakeReasonRxIcmpPacketDetails;
+import android.hardware.wifi.WifiDebugHostWakeReasonRxMulticastPacketDetails;
+import android.hardware.wifi.WifiDebugHostWakeReasonRxPacketDetails;
+
+/**
+ * Structure capturing the count of all the wireless related host wakeup.
+ * This is used to capture all the reasons why the host processor
+ * (WLAN driver) was woken up by the WLAN firmware.
+ * These stats may be used to debug any power issues caused due to frequent
+ * wakeup of the host processor by the WLAN firmware.
+ */
+@VintfStability
+parcelable WifiDebugHostWakeReasonStats {
+ /**
+ * Total count of cmd/event wakes.
+ * These must account for all wakeups due to WLAN management
+ * commands/events received over the air.
+ */
+ int totalCmdEventWakeCnt;
+ /**
+ * Vector of wake counts per cmd/event type.
+ * The number of command types and their meaning is only understood by the
+ * vendor.
+ */
+ int[] cmdEventWakeCntPerType;
+ /**
+ * Total count of driver/firmware wakes.
+ * These must account for all wakeups due to local driver/firmware
+ * interactions. These include all vendor implementation specific
+ * interactions like any heart-beat monitoring, bus management, etc.
+ */
+ int totalDriverFwLocalWakeCnt;
+ /**
+ * Vector of wake counts per driver/firmware interaction type.
+ * The number of command types and their meaning is only understood by the
+ * vendor.
+ */
+ int[] driverFwLocalWakeCntPerType;
+ /**
+ * Total data rx packets that woke up host.
+ */
+ int totalRxPacketWakeCnt;
+ WifiDebugHostWakeReasonRxPacketDetails rxPktWakeDetails;
+ WifiDebugHostWakeReasonRxMulticastPacketDetails rxMulticastPkWakeDetails;
+ WifiDebugHostWakeReasonRxIcmpPacketDetails rxIcmpPkWakeDetails;
+}
diff --git a/wifi/aidl/android/hardware/wifi/WifiDebugPacketFateFrameInfo.aidl b/wifi/aidl/android/hardware/wifi/WifiDebugPacketFateFrameInfo.aidl
new file mode 100644
index 0000000..7601bf2
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/WifiDebugPacketFateFrameInfo.aidl
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.WifiDebugPacketFateFrameType;
+
+/**
+ * Information regarding the frame transmitted/received.
+ */
+@VintfStability
+parcelable WifiDebugPacketFateFrameInfo {
+ /**
+ * The type of MAC-layer frame that this frame_info holds.
+ * - For data frames, use FRAME_TYPE_ETHERNET_II.
+ * - For management frames, use FRAME_TYPE_80211_MGMT.
+ * - If the type of the frame is unknown, use FRAME_TYPE_UNKNOWN.
+ */
+ WifiDebugPacketFateFrameType frameType;
+ /**
+ * The number of bytes included in |frameContent|.
+ * If the frame contents are missing (e.g. RX frame dropped in firmware),
+ * |frameLen| must be set to 0.
+ */
+ long frameLen;
+ /**
+ * Host clock when this frame was received by the driver (either outbound
+ * from the host network stack, or inbound from the firmware).
+ * - The timestamp must be taken from a clock which includes time the host
+ * spent suspended (e.g. ktime_get_boottime()).
+ * - If no host timestamp is available (e.g. RX frame was dropped in firmware),
+ * this field must be set to 0.
+ */
+ long driverTimestampUsec;
+ /**
+ * Firmware clock when this frame was received by the firmware
+ * (either outbound from the host, or inbound from a remote station).
+ * - The timestamp must be taken from a clock which includes time firmware
+ * spent suspended (if applicable).
+ * - If no firmware timestamp is available (e.g. TX frame was dropped by the
+ * driver), then this field must be set to 0.
+ * - Consumers of |frameInfo| must not assume any synchronization between
+ * the driver and firmware clocks.
+ */
+ long firmwareTimestampUsec;
+ /**
+ * Actual frame content. This is the raw bytes of the corresponding packet.
+ * - Should be provided for TX frames originated by the host.
+ * - Should be provided for RX frames received by the driver.
+ * - Optionally provided for TX frames originated by firmware.
+ * (At discretion of HAL implementation.)
+ * - Optionally provided for RX frames dropped in firmware.
+ * (At discretion of HAL implementation.)
+ * - If frame content is not provided, |frameLen| must be set to 0.
+ */
+ byte[] frameContent;
+}
diff --git a/wifi/aidl/android/hardware/wifi/WifiDebugPacketFateFrameType.aidl b/wifi/aidl/android/hardware/wifi/WifiDebugPacketFateFrameType.aidl
new file mode 100644
index 0000000..5c0d171
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/WifiDebugPacketFateFrameType.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Type of frame transmitted/received.
+ */
+@VintfStability
+@Backing(type="int")
+enum WifiDebugPacketFateFrameType {
+ UNKNOWN,
+ ETHERNET_II,
+ MGMT_80211,
+}
diff --git a/wifi/aidl/android/hardware/wifi/WifiDebugRingBufferFlags.aidl b/wifi/aidl/android/hardware/wifi/WifiDebugRingBufferFlags.aidl
new file mode 100644
index 0000000..0d1806e
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/WifiDebugRingBufferFlags.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Flags describing each debug ring buffer.
+ */
+@VintfStability
+@Backing(type="int")
+enum WifiDebugRingBufferFlags {
+ HAS_BINARY_ENTRIES = 1 << 0,
+ HAS_ASCII_ENTRIES = 1 << 1,
+ HAS_PER_PACKET_ENTRIES = 1 << 2,
+}
diff --git a/wifi/aidl/android/hardware/wifi/WifiDebugRingBufferStatus.aidl b/wifi/aidl/android/hardware/wifi/WifiDebugRingBufferStatus.aidl
new file mode 100644
index 0000000..2b0faa2
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/WifiDebugRingBufferStatus.aidl
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Struct describing each debug ring buffer supported by
+ * the device.
+ */
+@VintfStability
+parcelable WifiDebugRingBufferStatus {
+ /**
+ * Name of this debug ring buffer.
+ */
+ String ringName;
+ /**
+ * Combination of |WifiDebugRingBufferFlags| values.
+ */
+ int flags;
+ /**
+ * Unique integer representing the ring.
+ */
+ int ringId;
+ /**
+ * Total memory size allocated for the buffer.
+ */
+ int sizeInBytes;
+ /**
+ * Amount of free space in the buffer.
+ */
+ int freeSizeInBytes;
+ /**
+ * Verbose level for ring buffer.
+ */
+ int verboseLevel;
+}
diff --git a/wifi/aidl/android/hardware/wifi/WifiDebugRingBufferVerboseLevel.aidl b/wifi/aidl/android/hardware/wifi/WifiDebugRingBufferVerboseLevel.aidl
new file mode 100644
index 0000000..30778eb
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/WifiDebugRingBufferVerboseLevel.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Verbose logging level to set for each debug ring buffer supported
+ * by the device.
+ */
+@VintfStability
+@Backing(type="int")
+enum WifiDebugRingBufferVerboseLevel {
+ /**
+ * Level 0 corresponds to no collection, and it makes log handler
+ * stop by no more events from driver.
+ */
+ NONE = 0,
+ /**
+ * Level 1 corresponds to normal log level, with minimal user impact.
+ * This is the default value.
+ */
+ DEFAULT = 1,
+ /**
+ * Level 2 is enabled when user is lazily trying to reproduce a problem.
+ * Wifi performance and power can be impacted, but device should not
+ * otherwise be significantly impacted.
+ */
+ VERBOSE = 2,
+ /**
+ * Level 3 is used when trying to actively debug a problem.
+ * This will cause severe performance degradation.
+ */
+ EXCESSIVE = 3,
+}
diff --git a/wifi/aidl/android/hardware/wifi/WifiDebugRxPacketFate.aidl b/wifi/aidl/android/hardware/wifi/WifiDebugRxPacketFate.aidl
new file mode 100644
index 0000000..2983f81
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/WifiDebugRxPacketFate.aidl
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Enum describing the fate of the RX packets.
+ */
+@VintfStability
+@Backing(type="int")
+enum WifiDebugRxPacketFate {
+ /**
+ * Valid and delivered to network stack (e.g., netif_rx()).
+ */
+ SUCCESS,
+ /**
+ * Queued within firmware, but not yet sent to driver.
+ */
+ FW_QUEUED,
+ /**
+ * Dropped by firmware due to host-programmable filters.
+ */
+ FW_DROP_FILTER,
+ /**
+ * Dropped by firmware as invalid (e.g. bad checksum, decrypt failed,
+ * or invalid for current state).
+ */
+ FW_DROP_INVALID,
+ /**
+ * Dropped by firmware due to lack of buffer space.
+ */
+ FW_DROP_NOBUFS,
+ /**
+ * Dropped by firmware for any other reason.
+ */
+ FW_DROP_OTHER,
+ /**
+ * Queued within driver, not yet delivered to network stack.
+ */
+ DRV_QUEUED,
+ /**
+ * Dropped by driver due to filter rules.
+ */
+ DRV_DROP_FILTER,
+ /**
+ * Dropped by driver as invalid (e.g. not permitted in current state).
+ */
+ DRV_DROP_INVALID,
+ /**
+ * Dropped by driver due to lack of buffer space.
+ */
+ DRV_DROP_NOBUFS,
+ /**
+ * Dropped by driver for any other reason.
+ */
+ DRV_DROP_OTHER,
+}
diff --git a/wifi/aidl/android/hardware/wifi/WifiDebugRxPacketFateReport.aidl b/wifi/aidl/android/hardware/wifi/WifiDebugRxPacketFateReport.aidl
new file mode 100644
index 0000000..f4d709c
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/WifiDebugRxPacketFateReport.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.WifiDebugPacketFateFrameInfo;
+import android.hardware.wifi.WifiDebugRxPacketFate;
+
+/**
+ * Struct describing packet fate report for each Rx frame.
+ */
+@VintfStability
+parcelable WifiDebugRxPacketFateReport {
+ WifiDebugRxPacketFate fate;
+ WifiDebugPacketFateFrameInfo frameInfo;
+}
diff --git a/wifi/aidl/android/hardware/wifi/WifiDebugTxPacketFate.aidl b/wifi/aidl/android/hardware/wifi/WifiDebugTxPacketFate.aidl
new file mode 100644
index 0000000..717d62a
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/WifiDebugTxPacketFate.aidl
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Enum describing the fate of the TX packets.
+ */
+@VintfStability
+@Backing(type="int")
+enum WifiDebugTxPacketFate {
+ /**
+ * Sent over air and ACKed.
+ */
+ ACKED,
+ /**
+ * Sent over air but not ACKed (normal for broadcast/multicast).
+ */
+ SENT,
+ /**
+ * Queued within firmware, but not yet sent over air.
+ */
+ FW_QUEUED,
+ /**
+ * Dropped by firmware as invalid (e.g. bad source address, bad checksum,
+ * or invalid for current state).
+ */
+ FW_DROP_INVALID,
+ /**
+ * Dropped by firmware due to lack of buffer space.
+ */
+ FW_DROP_NOBUFS,
+ /**
+ * Dropped by firmware for any other reason. Includes frames that were sent
+ * by driver to the firmware, but unaccounted for by firmware.
+ */
+ FW_DROP_OTHER,
+ /**
+ * Queued within driver, not yet sent to firmware.
+ */
+ DRV_QUEUED,
+ /**
+ * Dropped by driver as invalid (e.g. bad source address, or invalid for
+ * current state).
+ */
+ DRV_DROP_INVALID,
+ /**
+ * Dropped by driver due to lack of buffer space.
+ */
+ DRV_DROP_NOBUFS,
+ /**
+ * Dropped by driver for any other reason.
+ */
+ DRV_DROP_OTHER,
+}
diff --git a/wifi/aidl/android/hardware/wifi/WifiDebugTxPacketFateReport.aidl b/wifi/aidl/android/hardware/wifi/WifiDebugTxPacketFateReport.aidl
new file mode 100644
index 0000000..b59b0a5
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/WifiDebugTxPacketFateReport.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.WifiDebugPacketFateFrameInfo;
+import android.hardware.wifi.WifiDebugTxPacketFate;
+
+/**
+ * Struct describing packet fate report for each Tx frame.
+ */
+@VintfStability
+parcelable WifiDebugTxPacketFateReport {
+ WifiDebugTxPacketFate fate;
+ WifiDebugPacketFateFrameInfo frameInfo;
+}
diff --git a/wifi/aidl/android/hardware/wifi/WifiIfaceMode.aidl b/wifi/aidl/android/hardware/wifi/WifiIfaceMode.aidl
new file mode 100644
index 0000000..f70c744
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/WifiIfaceMode.aidl
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Interface operating modes.
+ */
+@VintfStability
+@Backing(type="int")
+enum WifiIfaceMode {
+ /**
+ * Interface operation mode is client.
+ */
+ IFACE_MODE_STA = 1 << 0,
+ /**
+ * Interface operation mode is Hotspot.
+ */
+ IFACE_MODE_SOFTAP = 1 << 1,
+ /**
+ * Interface operation mode is Ad-Hoc network.
+ */
+ IFACE_MODE_IBSS = 1 << 2,
+ /**
+ * Interface operation mode is Wifi Direct Client.
+ */
+ IFACE_MODE_P2P_CLIENT = 1 << 3,
+ /**
+ * Interface operation mode is Wifi Direct Group Owner.
+ */
+ IFACE_MODE_P2P_GO = 1 << 4,
+ /**
+ * Interface operation mode is Aware.
+ */
+ IFACE_MODE_NAN = 1 << 5,
+ /**
+ * Interface operation mode is Mesh network.
+ */
+ IFACE_MODE_MESH = 1 << 6,
+ /**
+ * Interface operation mode is Tunneled Direct Link Setup.
+ */
+ IFACE_MODE_TDLS = 1 << 7,
+}
diff --git a/wifi/aidl/android/hardware/wifi/WifiInformationElement.aidl b/wifi/aidl/android/hardware/wifi/WifiInformationElement.aidl
new file mode 100644
index 0000000..f5f6de9
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/WifiInformationElement.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Information elements contained within the |ScanResult| structure.
+ * These elements correspond to the IEEE_802.11 standard.
+ */
+@VintfStability
+parcelable WifiInformationElement {
+ byte id;
+ byte[] data;
+}
diff --git a/wifi/aidl/android/hardware/wifi/WifiRadioCombination.aidl b/wifi/aidl/android/hardware/wifi/WifiRadioCombination.aidl
new file mode 100644
index 0000000..28b15ed
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/WifiRadioCombination.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.WifiRadioConfiguration;
+
+/**
+ * Wifi radio combination.
+ */
+@VintfStability
+parcelable WifiRadioCombination {
+ /**
+ * List of radio configurations in this combination.
+ */
+ WifiRadioConfiguration[] radioConfigurations;
+}
diff --git a/wifi/aidl/android/hardware/wifi/WifiRadioCombinationMatrix.aidl b/wifi/aidl/android/hardware/wifi/WifiRadioCombinationMatrix.aidl
new file mode 100644
index 0000000..b79a818
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/WifiRadioCombinationMatrix.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.WifiRadioCombination;
+
+/**
+ * Wifi radio combinations matrix retrieved via
+ * |IWifiChip.getSupportedRadioCombinationsMatrix|.
+ */
+@VintfStability
+parcelable WifiRadioCombinationMatrix {
+ /**
+ * List of all the possible radio combinations that the chip can operate.
+ */
+ WifiRadioCombination[] radioCombinations;
+}
diff --git a/wifi/aidl/android/hardware/wifi/WifiRadioConfiguration.aidl b/wifi/aidl/android/hardware/wifi/WifiRadioConfiguration.aidl
new file mode 100644
index 0000000..ae8eff3
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/WifiRadioConfiguration.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.WifiAntennaMode;
+import android.hardware.wifi.WifiBand;
+
+/**
+ * Wifi radio configuration.
+ */
+@VintfStability
+parcelable WifiRadioConfiguration {
+ /**
+ * Band on which this radio chain is operating.
+ * Valid values of bandInfo are: BAND_24GHZ, BAND_5GHZ, BAND_6GHZ and
+ * BAND_60GHZ.
+ *
+ */
+ WifiBand bandInfo;
+ /**
+ * Wifi Antenna configuration.
+ */
+ WifiAntennaMode antennaMode;
+}
diff --git a/wifi/aidl/android/hardware/wifi/WifiRateInfo.aidl b/wifi/aidl/android/hardware/wifi/WifiRateInfo.aidl
new file mode 100644
index 0000000..c4e285e
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/WifiRateInfo.aidl
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.WifiChannelWidthInMhz;
+import android.hardware.wifi.WifiRateNss;
+import android.hardware.wifi.WifiRatePreamble;
+
+/**
+ * Wifi rate info.
+ */
+@VintfStability
+parcelable WifiRateInfo {
+ /**
+ * Preamble used for RTT measurements.
+ */
+ WifiRatePreamble preamble;
+ /**
+ * Number of spatial streams.
+ */
+ WifiRateNss nss;
+ /**
+ * Bandwidth of channel.
+ */
+ WifiChannelWidthInMhz bw;
+ /**
+ * OFDM/CCK rate code as per IEEE std in units of 0.5mbps.
+ * HT/VHT/HE/EHT would be mcs index.
+ */
+ byte rateMcsIdx;
+ /**
+ * Bitrate in units of 100 Kbps.
+ */
+ int bitRateInKbps;
+}
diff --git a/wifi/aidl/android/hardware/wifi/WifiRateNss.aidl b/wifi/aidl/android/hardware/wifi/WifiRateNss.aidl
new file mode 100644
index 0000000..0c263a5
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/WifiRateNss.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Number of spatial streams in VHT/HT.
+ */
+@VintfStability
+@Backing(type="int")
+enum WifiRateNss {
+ NSS_1x1 = 0,
+ NSS_2x2 = 1,
+ NSS_3x3 = 2,
+ NSS_4x4 = 3,
+}
diff --git a/wifi/aidl/android/hardware/wifi/WifiRatePreamble.aidl b/wifi/aidl/android/hardware/wifi/WifiRatePreamble.aidl
new file mode 100644
index 0000000..116e46a
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/WifiRatePreamble.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Wifi Rate Preamble.
+ */
+@VintfStability
+@Backing(type="int")
+enum WifiRatePreamble {
+ OFDM = 0,
+ CCK = 1,
+ HT = 2,
+ VHT = 3,
+ RESERVED = 4,
+ /**
+ * Preamble type for 11ax.
+ */
+ HE = 5,
+ /**
+ * Preamble type for 11be.
+ */
+ EHT = 6,
+}
diff --git a/wifi/aidl/android/hardware/wifi/WifiStatusCode.aidl b/wifi/aidl/android/hardware/wifi/WifiStatusCode.aidl
new file mode 100644
index 0000000..30817f3
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/WifiStatusCode.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Enum values indicating the status of the WiFi operation.
+ */
+@VintfStability
+@Backing(type="int")
+enum WifiStatusCode {
+ /**
+ * No errors.
+ */
+ SUCCESS,
+ /**
+ * Method invoked on an invalid |IWifiChip| object.
+ */
+ ERROR_WIFI_CHIP_INVALID,
+ /**
+ * Method invoked on an invalid |IWifiIface| object.
+ */
+ ERROR_WIFI_IFACE_INVALID,
+ /**
+ * Method invoked on an invalid |IWifiRttController| object.
+ */
+ ERROR_WIFI_RTT_CONTROLLER_INVALID,
+ ERROR_NOT_SUPPORTED,
+ ERROR_NOT_AVAILABLE,
+ ERROR_NOT_STARTED,
+ ERROR_INVALID_ARGS,
+ ERROR_BUSY,
+ ERROR_UNKNOWN,
+}
diff --git a/wifi/aidl/android/hardware/wifi/WifiUsableChannel.aidl b/wifi/aidl/android/hardware/wifi/WifiUsableChannel.aidl
new file mode 100644
index 0000000..d92e4cc
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/WifiUsableChannel.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.WifiChannelWidthInMhz;
+import android.hardware.wifi.WifiIfaceMode;
+
+/**
+ * Wifi usable channel information.
+ */
+@VintfStability
+parcelable WifiUsableChannel {
+ /**
+ * Wifi channel freqeuncy in MHz.
+ */
+ int channel;
+ /**
+ * Wifi channel bandwidth in MHz.
+ */
+ WifiChannelWidthInMhz channelBandwidth;
+ /**
+ * Iface modes feasible on this channel.
+ */
+ WifiIfaceMode ifaceModeMask;
+}
diff --git a/wifi/apex/Android.bp b/wifi/apex/Android.bp
new file mode 100644
index 0000000..0afb96b
--- /dev/null
+++ b/wifi/apex/Android.bp
@@ -0,0 +1,55 @@
+package {
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+apex_key {
+ name: "com.android.hardware.wifi.key",
+ public_key: "com.android.hardware.wifi.avbpubkey",
+ private_key: "com.android.hardware.wifi.pem",
+}
+
+android_app_certificate {
+ name: "com.android.hardware.wifi.certificate",
+ certificate: "com.android.hardware.wifi",
+}
+
+genrule {
+ name: "gen-android.hardware.wifi.rc",
+ srcs: [":default-android.hardware.wifi@1.0-service.rc"],
+ out: ["com.android.hardware.wifi-service.rc"],
+ cmd: "sed -e 's@/vendor/bin/@/apex/com.android.hardware.wifi/bin/@' $(in) > $(out)",
+}
+
+prebuilt_etc {
+ name: "com.android.hardware.wifi.rc",
+ src: ":gen-android.hardware.wifi.rc",
+ installable: false,
+}
+
+prebuilt_etc {
+ name: "com.android.hardware.wifi.xml",
+ src: ":default-android.hardware.wifi@1.0-service.xml",
+ installable: false,
+}
+
+apex {
+ name: "com.android.hardware.wifi",
+ manifest: "apex_manifest.json",
+ key: "com.android.hardware.wifi.key",
+ certificate: ":com.android.hardware.wifi.certificate",
+ file_contexts: "file_contexts",
+ vintf_fragments: [":com.android.hardware.wifi.xml"],
+ use_vndk_as_stable: true,
+ updatable: false,
+ soc_specific: true,
+ binaries: [
+ "android.hardware.wifi@1.0-service",
+ ],
+ prebuilts: [
+ "com.android.hardware.wifi.rc",
+ "com.android.hardware.wifi.xml",
+ ],
+ overrides: [
+ "android.hardware.wifi@1.0-service",
+ ],
+}
diff --git a/wifi/apex/apex_manifest.json b/wifi/apex/apex_manifest.json
new file mode 100644
index 0000000..cab0814
--- /dev/null
+++ b/wifi/apex/apex_manifest.json
@@ -0,0 +1,4 @@
+{
+ "name": "com.android.hardware.wifi",
+ "version": 1
+}
diff --git a/wifi/apex/com.android.hardware.wifi.avbpubkey b/wifi/apex/com.android.hardware.wifi.avbpubkey
new file mode 100644
index 0000000..63fba77
--- /dev/null
+++ b/wifi/apex/com.android.hardware.wifi.avbpubkey
Binary files differ
diff --git a/wifi/apex/com.android.hardware.wifi.pem b/wifi/apex/com.android.hardware.wifi.pem
new file mode 100644
index 0000000..9e589ac
--- /dev/null
+++ b/wifi/apex/com.android.hardware.wifi.pem
@@ -0,0 +1,52 @@
+-----BEGIN PRIVATE KEY-----
+MIIJRAIBADANBgkqhkiG9w0BAQEFAASCCS4wggkqAgEAAoICAQCtT/vNnVVg2QVD
+eMdG+YZ8qYz/fbAQF9hnH8dE5RWHXzoYItBG7DSOuVT4T6POBVmFaVKlWDd7tDyw
+nFO3MmE2/FzhVSiBPwhMITa7UIERr3od3rWJ5g6oaTCOu4wa98L466Jp60f2fYSZ
+M9lGiKaDpLDSpxTU9hexjp7C4PfinnkYnlHBnrFXTmiO6f8AvOEwFFx73/rUNoe7
+F3TkGvjZDqHvE+pjz/nilkhXYuOl3zgSaeznJ9+TO5C/Z+Xr+zRhaJGI4v5Dkgmc
+jNy74+0hjwobXO3iWE44InQMvMh8zDKBx9l1oSsFoG3waj9ayqSYD7M74RX3PkUL
+QrhgAHZWi5iEnpu50xBzAqZB1ZDVkdZiKiGzweJ8OqltnVpvzlnW3rA3y3HtFyLm
+73C4ll9MdLaw266vBxgZfFOcjpphbbh9J9uGjOCJY1AxUzsqKygFD2CyOdb1jab3
+AC6VvRa+bLtv8fd2etp3atXv+Y9ACUX6zNK6Oa8Zktoo2Z//OLtcrk7xhgKKDkUF
+OPQrIjW9x0fdClDioIS+y7EHNUrfyRL7XPtUqGCszgz5jK2SMVGMpFaEtfbyNP1H
+BTGXdzcDP0RZdOOKTdBFgoRW5+6TH5CU9Nl4uevpxzwsTkXg0a+W1BGP+s9J7ssH
+rNPmHz+pbKZPDs/nxlpsKq+N+K8cCwIDAQABAoICAAJL943Lgnikl53DyXxGzUH0
+q0Itg7pK3prLQIRItubS2727JGB0O+QST650u7p8tql+clJvn1ib1FwQzkk0uTYV
+1RNFYiKIV89Od1+3GubFmQwxSd2Yd2RC9JpHoP0wgFx1HvNhY1RAaJPxLHVzVSWU
+dqVsAmoqErlPJwp1GcPejsNFQdcbh8Uc7GTMdA0p86AD/Q/FMZlDWbwgfPOS6e5S
+c9HrxSTqeijHDhFeZZ7qnN8dmT6c+CkG1o26zkC41QJfdOJIA8+YbVkuQrSYuilC
+MIOZUSu5ONwklL4geFWzDQ5MPDUDXEMYU6ymc817tv+u4ZSvEG/02sxh53iaOPc6
+C6im4nm6ZlRP9HzIvLAiRSbvwEb9cnLKgYpioSGXehDYg3zMPURwoqIxw+7IlIUh
+s+rhmCJV62PK1Z0nmo7m7S8r+z6j4G7aztGcbvdecocOJYOQB1VB8Zh4bNEIWp0a
+GDteG6aWXOCHoYRWAOluppDWa7Z+EgesU3Oj9Prn/ekUzzXx3V30zSTZYxRnQCO0
+vZIZ6hrlsNJcNrDpxmiWBaEOd4k5QI39pu6fDHc+UEEJMN+7eVk8d9QVA/LhrCjc
+JH1EVjtWosMUeMaMTpcmHTQKnEvmT2LO2fxGlF4JvjzDdVMloJrIP2LSQjovo2PX
+x9UXVu8Dt3kQRefZ42XxAoIBAQDkBoSYVajaFlyv9lW8oPmrQyzp93ite+TKVR8z
+PmcFQukjp5Gm8PGlGtGoH8aeE9Ev+R86aNPFy4n4ZJ7fmZYH1hxZ6dSc/56k6lLn
+uVKvTudYqwcRgBKuSZ8IDPFz3sHd+MnOBonDIri28fcBTDNv4LJP/6cAUoIOCCPm
+lQtJBfMNMDOXG4jv1Rv/1P5opGFATerRCubOxmeaFhZIDEjvN5WvLK5jmL7I8lX3
+X+gPiMHFWBQFmVTOHeVYEORDO5xFCOvHqCVB78b2xe1NkkrQ0CexpdflJVLE9IWt
+wWH43nhjxaK+eiBPrj37BliJvNaYfuxqcAj3p8c5KweFEtP7AoIBAQDCkx72K/Ja
+rFrrI0Avfo+3n6yoTMtMkiVhMuIKKPBJ2o4Opc/uixk+uLH5UH0X5GZsE51FAhUD
+L3bWMxV+vzVefWS8Iryo94ucvnfqhsN3KZXHDGoAuYv72jND8qPLKksM0dceMBfl
+aoyXSPAe8zAZeEx4iR2axgtnA0EbiXIaNVE/LF+WYdM74jvk/QtRzJ8IAAkSc5Rr
+GiTHeeP3nRnkjWjkmwKXYSJHcrEl26c/2ckeZORtblqxR9wMU5OgvJvMSzmOIpVH
+Y5lylZUOTuJCkApHFNKdRsawsSNKsy4yfY1byN/WkODb7le6Crt1gcwldMxDZAo9
+iB25FHq4zksxAoIBAQC+SBYkDO9PtnN4PycCto5B9VeokmN42bdthKT5nSxY/qIQ
+p8fquIvdzEiCdKnIxh69WrVNh6aZGyWySz0suDyzo1+bRH6w2LrpQcUXK9YtBroV
+ivrmBqsQF82G6U4f9BZxhifZLimN1g6wU7Bcu9r8lFQYX+1bXn66+N4EkAGP2VAe
+hEe45Dhccsjfrzzx06J4B81YzjEXAgf4VFAZpW7DeO4G9VE9OXyTsW49dSHwvJ1+
+ceabWX2kVtxIpiflVvwru6sNvGoC4PV2fmptXhPitqE5JHzJ8mBkjOx0t7hq9jMe
+hxEsxDrsYynDrWL65cNqFBhzJbTF/ZNJSHgI+1I7AoIBAQC7m0shJOJ61vCbA9Qh
+dzBvZn/9jn3/CHMOMxeLoEl/jEGokevZHzlqJn9D2n2jCdBPqOHc5dMIzT0R7xNs
+sERvJQx58ixh5r0wlt3cva++N9R4pdmXdVApuAvyGgQgIllWtQVr0AdaZs/EFsmf
+re/Uvw9MsThgQVBBNPwT5wSjjIEYHlrUDuKzPMFvWyUM6/Tyq8YTimmykvSfeUF7
+QHj0y/w1X9ixyTBaH5X64L10bTLkIXe2o87CXH0pTXRsaS73XhjSmTnCKaCMwPmF
+YD383BFs1AD3MITnXQSgQ//pIvGnbBmXMv38UOU5NpvlAw+pleJVoCHXjmTKTZq+
+kfohAoIBAQCrEecN8XEPjGdtY71rDYEwHGM6G4czHX0PNhlMjQos3aBVZ/YvVxPG
+pkXbms3GRXv4W92u7b2MwEKBPxcBepEdDZN9wSpe63bDFE6gpkipDhgj97JlLEUd
+s7h6oOoazdxmsRZyFho99SRQWrvyOiiKdLJCRZiqjUB4roOQmy7f9VAz6+OxyGV9
+XZigwW6bfUzMCmhx5Ss6zW8wZI+gINQh+2sDmiBiMQv14Ya5zlNYN+4/257Sk/jS
+o3QUDJITbReq/DNZ6UUzQS+AZ7ztc81rk5kRg0I33FZarRJ7TLAz+XmZZFoIOORz
+etEvMk8bJ4u7X89NWW/i2J+kQiDQg819
+-----END PRIVATE KEY-----
diff --git a/wifi/apex/com.android.hardware.wifi.pk8 b/wifi/apex/com.android.hardware.wifi.pk8
new file mode 100644
index 0000000..f4481bf
--- /dev/null
+++ b/wifi/apex/com.android.hardware.wifi.pk8
Binary files differ
diff --git a/wifi/apex/com.android.hardware.wifi.x509.pem b/wifi/apex/com.android.hardware.wifi.x509.pem
new file mode 100644
index 0000000..c942e71
--- /dev/null
+++ b/wifi/apex/com.android.hardware.wifi.x509.pem
@@ -0,0 +1,36 @@
+-----BEGIN CERTIFICATE-----
+MIIGOzCCBCOgAwIBAgIUIEueuBFEoCFmLyEvXDsKVuZeH0EwDQYJKoZIhvcNAQEL
+BQAwgasxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQH
+DA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAwDgYDVQQLDAdBbmRy
+b2lkMScwJQYDVQQDDB5jb20uYW5kcm9pZC5oYXJkd2FyZS53aWZpLmFwZXgxIjAg
+BgkqhkiG9w0BCQEWE2FuZHJvaWRAYW5kcm9pZC5jb20wIBcNMjIxMDA2MTY1MDQy
+WhgPNDc2MDA5MDExNjUwNDJaMIGrMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2Fs
+aWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEQMA4GA1UECgwHQW5kcm9p
+ZDEQMA4GA1UECwwHQW5kcm9pZDEnMCUGA1UEAwweY29tLmFuZHJvaWQuaGFyZHdh
+cmUud2lmaS5hcGV4MSIwIAYJKoZIhvcNAQkBFhNhbmRyb2lkQGFuZHJvaWQuY29t
+MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAo4N23iL0J42qG2lt4ysD
+t6XxAKdi4sTWB6ZjFWerBm11s3yLr1KBZV82z3j2o7+EOaWa/91Mgc+aoiGYUa1f
+IweugKTrnRmrzOvtq/Wp5PGqSxsmLPPvH3wyEB/CMgAn0pqDf0WyCWJ2kAlcCkmy
+qVNFupkGFyIE6gkoc+AmJGbSTquDlL07R/8XYDicqrcgeqy9ZaCJ5FLfmbnnRb2A
+vm4Un7e5dFz5+dPaOJXf4AOMUSPUd7fuBliGYFLzcZnYQbzMktXa4XnPuSlmerwy
+EwY767L2bjRjaSgPb0Js13gZ4S4ZHZe07AV7HPlt/EzbxV/jtMgHl4xn5p0WhVnK
+MPtLsO/e7FkDPAKpT02sgUK6pVKqgBGOWm27tmTB09lscMLQeVFqwpoFq2zMUrDn
+ipDFMWRBeLrEDKx41zF3gqdPmP+SMkQYJu4OATIXOndIeo7AN9iE+N6snHkckNyE
+saCwmnzyhVAbMn/epfIQZz3zcyljA9yfOpv5jctN4es+3i0htDnoNO9ij4M5fxuP
+jtNAP3EA61nKZ5+Js0/MMQKrfwCLogPl/4vCNuuGT2rhCkhq1CLYXmb9ghvVzcPe
+BOGXNDKdB+aUTxrQUOYlHf0cRDHdU6cchrz9+QhR7t9dlibtiyCZE34xgR3klmyz
+XJ3M1r/QRihjARH7exrrwiUCAwEAAaNTMFEwHQYDVR0OBBYEFGN9tMk+4SDk7twk
+MrLjM+nRxGDJMB8GA1UdIwQYMBaAFGN9tMk+4SDk7twkMrLjM+nRxGDJMA8GA1Ud
+EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIBAHoTfVBRG0rVE7gkV526gwR5
+/3mXyYA57lKJhZ21fu2qfTE6WYj4DsOTZKrPIAUFv/SnzZ6Rvv7W81XV5M/1m+5R
+/1wYvWwm3FBOvvt4VDUiel0Zfc9+nwynjz1seYdXU8fNIOzBcr9hutkYdRZDkNpc
+Zcl4NG04TzyedkQ/0SyHnygmq4ZY9OUEvrNaWBFHzw2SQhYvHh8jUrqpPvoJz0Px
+avKI8bOgXTJRJ+Pk7hjXDFQY/fbE0RGivorPMLs+XHaEIb+YPyXsX4OZwowG5KL8
+txyvUsH+qZToytdPk4LCuwYBobBlr+AAg7pxOtbDW1ITDhQ9n05UFK2iUwsJecgg
+VDA0K3GuCjmGVmkw7SFRYfToCyGWah8sQCUMCCcsof7gS+dMxuWeee+sRxRJcJY+
+xR2uySe8g4ohwNjQ0zLQv7PZOKQh91yEWxRXmhPYVpiVAjpSD2zH7Vd6CJ9xji//
+5S1UrxWwQ5igvu8v5veqNAW7uXGXADnxL69HVGTLm0XDIUUOAUIG8waiVkYUo3UU
+AzAFbF7ewYMKdg7ylUYcTaMRIsKYW/3/1t3NJv2z99W4V/p8e1kRCeWMPB5C+/Lo
+b/hSWj1NF9AJ30ukBndMh6bRprq+G5NLV6OaoCLp606CMdXdT8uw9lYCt7DbQHG9
+Hw3iw61svpUwcaWfN1hI
+-----END CERTIFICATE-----
diff --git a/wifi/apex/file_contexts b/wifi/apex/file_contexts
new file mode 100644
index 0000000..812d51d
--- /dev/null
+++ b/wifi/apex/file_contexts
@@ -0,0 +1,3 @@
+(/.*)? u:object_r:vendor_file:s0
+/bin/hw/android\.hardware\.wifi@1.0-service u:object_r:hal_wifi_default_exec:s0
+
diff --git a/wifi/hostapd/1.0/vts/OWNERS b/wifi/hostapd/1.0/vts/OWNERS
deleted file mode 100644
index 287152d..0000000
--- a/wifi/hostapd/1.0/vts/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 33618
-arabawy@google.com
-etancohen@google.com
diff --git a/wifi/hostapd/1.1/vts/OWNERS b/wifi/hostapd/1.1/vts/OWNERS
deleted file mode 100644
index 294fc82..0000000
--- a/wifi/hostapd/1.1/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 33618
-include ../../1.0/vts/OWNERS
diff --git a/wifi/hostapd/1.2/vts/OWNERS b/wifi/hostapd/1.2/vts/OWNERS
deleted file mode 100644
index 294fc82..0000000
--- a/wifi/hostapd/1.2/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 33618
-include ../../1.0/vts/OWNERS
diff --git a/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp b/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp
index 2fade4d..5c59819 100644
--- a/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp
+++ b/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp
@@ -122,7 +122,8 @@
IHostapd::IfaceParams getIfaceParamsWithAcs(std::string iface_name) {
// First get the settings for WithoutAcs and then make changes
- IHostapd::IfaceParams iface_params_1_2 = getIfaceParamsWithoutAcs(iface_name);
+ IHostapd::IfaceParams iface_params_1_2 =
+ getIfaceParamsWithoutAcs(iface_name);
iface_params_1_2.V1_1.V1_0.channelParams.enableAcs = true;
iface_params_1_2.V1_1.V1_0.channelParams.acsShouldExcludeDfs = true;
iface_params_1_2.V1_1.V1_0.channelParams.channel = 0;
@@ -132,8 +133,10 @@
return iface_params_1_2;
}
- IHostapd::IfaceParams getIfaceParamsWithAcsAndFreqRange(std::string iface_name) {
- IHostapd::IfaceParams iface_params_1_2 = getIfaceParamsWithAcs(iface_name);
+ IHostapd::IfaceParams getIfaceParamsWithAcsAndFreqRange(
+ std::string iface_name) {
+ IHostapd::IfaceParams iface_params_1_2 =
+ getIfaceParamsWithAcs(iface_name);
::android::hardware::wifi::hostapd::V1_2::IHostapd::AcsFrequencyRange
acsFrequencyRange;
acsFrequencyRange.start = 2412;
@@ -147,8 +150,10 @@
return iface_params_1_2;
}
- IHostapd::IfaceParams getIfaceParamsWithAcsAndInvalidFreqRange(std::string iface_name) {
- IHostapd::IfaceParams iface_params_1_2 = getIfaceParamsWithAcsAndFreqRange(iface_name);
+ IHostapd::IfaceParams getIfaceParamsWithAcsAndInvalidFreqRange(
+ std::string iface_name) {
+ IHostapd::IfaceParams iface_params_1_2 =
+ getIfaceParamsWithAcsAndFreqRange(iface_name);
iface_params_1_2.channelParams.acsChannelFreqRangesMhz[0].start = 222;
iface_params_1_2.channelParams.acsChannelFreqRangesMhz[0].end = 999;
return iface_params_1_2;
@@ -210,8 +215,10 @@
return nw_params_1_2;
}
- IHostapd::IfaceParams getIfaceParamsWithInvalidChannel(std::string iface_name) {
- IHostapd::IfaceParams iface_params_1_2 = getIfaceParamsWithoutAcs(iface_name);
+ IHostapd::IfaceParams getIfaceParamsWithInvalidChannel(
+ std::string iface_name) {
+ IHostapd::IfaceParams iface_params_1_2 =
+ getIfaceParamsWithoutAcs(iface_name);
iface_params_1_2.V1_1.V1_0.channelParams.channel = kIfaceInvalidChannel;
return iface_params_1_2;
}
@@ -237,8 +244,8 @@
if (is_1_3(hostapd_))
GTEST_SKIP() << "Ignore addAccessPoint_1_2 on hostapd 1_3";
std::string ifname = setupApIfaceIfNeededAndGetName();
- auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithAcs(ifname),
- getPskNwParams());
+ auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+ getIfaceParamsWithAcs(ifname), getPskNwParams());
EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
}
@@ -252,7 +259,8 @@
GTEST_SKIP() << "Ignore addAccessPoint_1_2 on hostapd 1_3";
std::string ifname = setupApIfaceIfNeededAndGetName();
auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
- getIfaceParamsWithAcsAndFreqRange(ifname), getPskNwParams());
+ getIfaceParamsWithAcsAndFreqRange(ifname),
+ getPskNwParams());
EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
}
@@ -266,7 +274,8 @@
GTEST_SKIP() << "Ignore addAccessPoint_1_2 on hostapd 1_3";
std::string ifname = setupApIfaceIfNeededAndGetName();
auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
- getIfaceParamsWithAcsAndInvalidFreqRange(ifname), getPskNwParams());
+ getIfaceParamsWithAcsAndInvalidFreqRange(ifname),
+ getPskNwParams());
EXPECT_NE(HostapdStatusCode::SUCCESS, status.code);
}
@@ -279,8 +288,8 @@
if (is_1_3(hostapd_))
GTEST_SKIP() << "Ignore addAccessPoint_1_2 on hostapd 1_3";
std::string ifname = setupApIfaceIfNeededAndGetName();
- auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithAcs(ifname),
- getOpenNwParams());
+ auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+ getIfaceParamsWithAcs(ifname), getOpenNwParams());
EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
}
@@ -292,8 +301,9 @@
if (is_1_3(hostapd_))
GTEST_SKIP() << "Ignore addAccessPoint_1_2 on hostapd 1_3";
std::string ifname = setupApIfaceIfNeededAndGetName();
- auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithoutAcs(ifname),
- getPskNwParams());
+ auto status =
+ HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+ getIfaceParamsWithoutAcs(ifname), getPskNwParams());
EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
}
@@ -305,8 +315,9 @@
if (is_1_3(hostapd_))
GTEST_SKIP() << "Ignore addAccessPoint_1_2 on hostapd 1_3";
std::string ifname = setupApIfaceIfNeededAndGetName();
- auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithoutAcs(ifname),
- getOpenNwParams());
+ auto status =
+ HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+ getIfaceParamsWithoutAcs(ifname), getOpenNwParams());
EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
}
@@ -319,7 +330,8 @@
if (is_1_3(hostapd_))
GTEST_SKIP() << "Ignore addAccessPoint_1_2 on hostapd 1_3";
std::string ifname = setupApIfaceIfNeededAndGetName();
- auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithoutAcs(ifname),
+ auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+ getIfaceParamsWithoutAcs(ifname),
getSaeTransitionNwParams());
EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
}
@@ -333,8 +345,9 @@
if (is_1_3(hostapd_))
GTEST_SKIP() << "Ignore addAccessPoint_1_2 on hostapd 1_3";
std::string ifname = setupApIfaceIfNeededAndGetName();
- auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithoutAcs(ifname),
- getSaeNwParams());
+ auto status =
+ HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+ getIfaceParamsWithoutAcs(ifname), getSaeNwParams());
EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
}
@@ -347,8 +360,9 @@
if (is_1_3(hostapd_))
GTEST_SKIP() << "Ignore addAccessPoint_1_2 on hostapd 1_3";
std::string ifname = setupApIfaceIfNeededAndGetName();
- auto status_1_2 = HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithAcs(ifname),
- getPskNwParams());
+ auto status_1_2 =
+ HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithAcs(ifname),
+ getPskNwParams());
EXPECT_EQ(HostapdStatusCode::SUCCESS, status_1_2.code);
auto status = HIDL_INVOKE(hostapd_, removeAccessPoint, ifname);
EXPECT_EQ(
@@ -364,8 +378,9 @@
if (is_1_3(hostapd_))
GTEST_SKIP() << "Ignore addAccessPoint_1_2 on hostapd 1_3";
std::string ifname = setupApIfaceIfNeededAndGetName();
- auto status_1_2 = HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithoutAcs(ifname),
- getPskNwParams());
+ auto status_1_2 =
+ HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+ getIfaceParamsWithoutAcs(ifname), getPskNwParams());
EXPECT_EQ(HostapdStatusCode::SUCCESS, status_1_2.code);
auto status = HIDL_INVOKE(hostapd_, removeAccessPoint, ifname);
EXPECT_EQ(
@@ -381,8 +396,9 @@
if (is_1_3(hostapd_))
GTEST_SKIP() << "Ignore addAccessPoint_1_2 on hostapd 1_3";
std::string ifname = setupApIfaceIfNeededAndGetName();
- auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
- getIfaceParamsWithInvalidChannel(ifname), getPskNwParams());
+ auto status =
+ HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+ getIfaceParamsWithInvalidChannel(ifname), getPskNwParams());
EXPECT_NE(HostapdStatusCode::SUCCESS, status.code);
}
@@ -394,8 +410,9 @@
if (is_1_3(hostapd_))
GTEST_SKIP() << "Ignore addAccessPoint_1_2 on hostapd 1_3";
std::string ifname = setupApIfaceIfNeededAndGetName();
- auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithoutAcs(ifname),
- getInvalidPskNwParams());
+ auto status =
+ HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+ getIfaceParamsWithoutAcs(ifname), getInvalidPskNwParams());
EXPECT_NE(HostapdStatusCode::SUCCESS, status.code);
}
@@ -408,7 +425,8 @@
if (is_1_3(hostapd_))
GTEST_SKIP() << "Ignore addAccessPoint_1_2 on hostapd 1_3";
std::string ifname = setupApIfaceIfNeededAndGetName();
- auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithoutAcs(ifname),
+ auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+ getIfaceParamsWithoutAcs(ifname),
getInvalidSaeTransitionNwParams());
EXPECT_NE(HostapdStatusCode::SUCCESS, status.code);
}
@@ -422,8 +440,9 @@
if (is_1_3(hostapd_))
GTEST_SKIP() << "Ignore addAccessPoint_1_2 on hostapd 1_3";
std::string ifname = setupApIfaceIfNeededAndGetName();
- auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithoutAcs(ifname),
- getInvalidSaeNwParams());
+ auto status =
+ HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+ getIfaceParamsWithoutAcs(ifname), getInvalidSaeNwParams());
EXPECT_NE(HostapdStatusCode::SUCCESS, status.code);
}
@@ -433,8 +452,8 @@
*/
TEST_P(HostapdHidlTest, DisconnectClientWhenIfaceNotAvailable) {
std::string ifname = setupApIfaceIfNeededAndGetName();
- auto status = HIDL_INVOKE(hostapd_, forceClientDisconnect, ifname, kTestZeroMacAddr,
- kTestDisconnectReasonCode);
+ auto status = HIDL_INVOKE(hostapd_, forceClientDisconnect, ifname,
+ kTestZeroMacAddr, kTestDisconnectReasonCode);
EXPECT_EQ(HostapdStatusCode::FAILURE_IFACE_UNKNOWN, status.code);
}
@@ -446,12 +465,13 @@
if (is_1_3(hostapd_))
GTEST_SKIP() << "Ignore addAccessPoint_1_2 on hostapd 1_3";
std::string ifname = setupApIfaceIfNeededAndGetName();
- auto status_1_2 = HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithoutAcs(ifname),
- getOpenNwParams());
+ auto status_1_2 =
+ HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+ getIfaceParamsWithoutAcs(ifname), getOpenNwParams());
EXPECT_EQ(HostapdStatusCode::SUCCESS, status_1_2.code);
- status_1_2 = HIDL_INVOKE(hostapd_, forceClientDisconnect, ifname, kTestZeroMacAddr,
- kTestDisconnectReasonCode);
+ status_1_2 = HIDL_INVOKE(hostapd_, forceClientDisconnect, ifname,
+ kTestZeroMacAddr, kTestDisconnectReasonCode);
EXPECT_EQ(HostapdStatusCode::FAILURE_CLIENT_UNKNOWN, status_1_2.code);
}
diff --git a/wifi/hostapd/1.3/vts/OWNERS b/wifi/hostapd/1.3/vts/OWNERS
deleted file mode 100644
index 294fc82..0000000
--- a/wifi/hostapd/1.3/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 33618
-include ../../1.0/vts/OWNERS
diff --git a/wifi/hostapd/aidl/Android.bp b/wifi/hostapd/aidl/Android.bp
index c97f8da..54895c1 100644
--- a/wifi/hostapd/aidl/Android.bp
+++ b/wifi/hostapd/aidl/Android.bp
@@ -38,9 +38,7 @@
min_sdk_version: "30",
},
ndk: {
- vndk: {
- enabled: true,
- },
+ gen_trace: true,
},
},
versions_with_info: [
diff --git a/wifi/hostapd/aidl/vts/OWNERS b/wifi/hostapd/aidl/vts/OWNERS
deleted file mode 100644
index 2a7a7b0..0000000
--- a/wifi/hostapd/aidl/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-etancohen@google.com
-lzye@google.com
diff --git a/wifi/netlinkinterceptor/aidl/default/OWNERS b/wifi/netlinkinterceptor/aidl/default/OWNERS
deleted file mode 100644
index b738dac..0000000
--- a/wifi/netlinkinterceptor/aidl/default/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-chrisweir@google.com
-twasilczyk@google.com
diff --git a/wifi/netlinkinterceptor/libnlinterceptor/Android.bp b/wifi/netlinkinterceptor/libnlinterceptor/Android.bp
index 00cae32..671cd85 100644
--- a/wifi/netlinkinterceptor/libnlinterceptor/Android.bp
+++ b/wifi/netlinkinterceptor/libnlinterceptor/Android.bp
@@ -37,10 +37,8 @@
"libutils",
],
sanitize: {
- address: true,
undefined: true,
all_undefined: true,
- fuzzer: true,
cfi: true,
integer_overflow: true,
scs: true,
diff --git a/wifi/netlinkinterceptor/vts/OWNERS b/wifi/netlinkinterceptor/vts/OWNERS
deleted file mode 100644
index b738dac..0000000
--- a/wifi/netlinkinterceptor/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-chrisweir@google.com
-twasilczyk@google.com
diff --git a/wifi/offload/1.0/vts/OWNERS b/wifi/offload/1.0/vts/OWNERS
deleted file mode 100644
index 287152d..0000000
--- a/wifi/offload/1.0/vts/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 33618
-arabawy@google.com
-etancohen@google.com
diff --git a/wifi/supplicant/1.0/vts/OWNERS b/wifi/supplicant/1.0/vts/OWNERS
deleted file mode 100644
index b16dc11..0000000
--- a/wifi/supplicant/1.0/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 33618
-include ../../1.3/vts/OWNERS
diff --git a/wifi/supplicant/1.1/vts/OWNERS b/wifi/supplicant/1.1/vts/OWNERS
deleted file mode 100644
index b16dc11..0000000
--- a/wifi/supplicant/1.1/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 33618
-include ../../1.3/vts/OWNERS
diff --git a/wifi/supplicant/1.2/vts/OWNERS b/wifi/supplicant/1.2/vts/OWNERS
deleted file mode 100644
index b16dc11..0000000
--- a/wifi/supplicant/1.2/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 33618
-include ../../1.3/vts/OWNERS
diff --git a/wifi/supplicant/1.4/vts/OWNERS b/wifi/supplicant/1.4/vts/OWNERS
deleted file mode 100644
index b16dc11..0000000
--- a/wifi/supplicant/1.4/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 33618
-include ../../1.3/vts/OWNERS
diff --git a/wifi/supplicant/OWNERS b/wifi/supplicant/OWNERS
deleted file mode 100644
index 7febd60..0000000
--- a/wifi/supplicant/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-# Bug component: 33618
-arabawy@google.com
-etancohen@google.com
-gbiren@google.com
-lzye@google.com
diff --git a/wifi/supplicant/aidl/Android.bp b/wifi/supplicant/aidl/Android.bp
index ca0785b..9cb4e51 100644
--- a/wifi/supplicant/aidl/Android.bp
+++ b/wifi/supplicant/aidl/Android.bp
@@ -38,9 +38,7 @@
min_sdk_version: "30",
},
ndk: {
- vndk: {
- enabled: true,
- },
+ gen_trace: true,
},
},
versions_with_info: [