Merge "Fingerprint virtual HAL checkin (part 1) - udfps and side fingerprint sensor instance - sensor location configuration - misc. fixes/workarounds"
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/README.md b/audio/README.md
index 1938ad4..3f40d72 100644
--- a/audio/README.md
+++ b/audio/README.md
@@ -2,10 +2,29 @@
Directory structure of the audio HAL related code.
-Run `common/all-versions/copyHAL.sh` to create a new version of the audio HAL
-based on an existing one.
+## Directory Structure for AIDL audio HAL
-## Directory Structure
+The AIDL version is located inside `aidl` directory. The tree below explains
+the role of each subdirectory:
+
+* `aidl_api` — snapshots of the API created each Android release. Every
+ release, the current version of the API becomes "frozen" and gets assigned
+ the next version number. If the API needs further modifications, they are
+ made on the "current" version. After making modifications, run
+ `m <package name>-update-api` to update the snapshot of the "current"
+ version.
+* `android/hardware/audio/common` — data structures and interfaces shared
+ between various HALs: BT HAL, core and effects audio HALs.
+* `android/hardware/audio/core` — data structures and interfaces of the
+ core audio HAL.
+* `default` — the default, reference implementation of the audio HAL service.
+* `vts` — VTS tests for the AIDL HAL.
+
+## Directory Structure for HIDL audio HAL
+
+Run `common/all-versions/copyHAL.sh` to create a new version of the HIDL audio
+HAL based on an existing one. Note that this isn't possible since Android T
+release. Android U and above uses AIDL audio HAL.
* `2.0` — version 2.0 of the core HIDL API. Note that `.hal` files
can not be moved into the `core` directory because that would change
diff --git a/audio/aidl/Android.bp b/audio/aidl/Android.bp
index 7db50d5..9c7a6a2 100644
--- a/audio/aidl/Android.bp
+++ b/audio/aidl/Android.bp
@@ -33,7 +33,7 @@
"android/hardware/audio/common/SourceMetadata.aidl",
],
imports: [
- "android.media.audio.common.types-V1",
+ "android.media.audio.common.types",
],
stability: "vintf",
backend: {
@@ -51,7 +51,7 @@
ndk: {
apex_available: [
"//apex_available:platform",
- "com.android.bluetooth",
+ "com.android.btservices",
],
min_sdk_version: "31",
},
@@ -61,10 +61,25 @@
version: "1",
imports: ["android.media.audio.common.types-V1"],
},
+ // 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-V2"
+
+// 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_ndk_static",
+ static_libs: [
+ latest_android_hardware_audio_common + "-ndk",
+ ],
+}
+
aidl_interface {
name: "android.hardware.audio.core",
vendor_available: true,
@@ -75,7 +90,58 @@
"android/hardware/audio/core/IModule.aidl",
"android/hardware/audio/core/IStreamIn.aidl",
"android/hardware/audio/core/IStreamOut.aidl",
+ "android/hardware/audio/core/MmapBufferDescriptor.aidl",
"android/hardware/audio/core/ModuleDebug.aidl",
+ "android/hardware/audio/core/StreamDescriptor.aidl",
+ ],
+ imports: [
+ "android.hardware.common-V2",
+ "android.hardware.common.fmq-V1",
+ "android.hardware.audio.common",
+ "android.media.audio.common.types",
+ ],
+ stability: "vintf",
+ 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",
+ vendor_available: true,
+ srcs: [
+ "android/hardware/audio/effect/Descriptor.aidl",
+ "android/hardware/audio/effect/IFactory.aidl",
],
imports: [
"android.hardware.audio.common-V1",
@@ -88,7 +154,7 @@
enabled: false,
},
java: {
- platform_apis: true,
+ sdk_version: "module_current",
},
},
}
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
index 1cef4cd..078b5ea 100644
--- 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
@@ -37,4 +37,6 @@
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/IModule.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IModule.aidl
index f8bc2c7..a8bbb15 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IModule.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IModule.aidl
@@ -43,10 +43,33 @@
android.media.audio.common.AudioPort[] getAudioPorts();
android.hardware.audio.core.AudioRoute[] getAudioRoutes();
android.hardware.audio.core.AudioRoute[] getAudioRoutesForAudioPort(int portId);
- android.hardware.audio.core.IStreamIn openInputStream(int portConfigId, in android.hardware.audio.common.SinkMetadata sinkMetadata);
- android.hardware.audio.core.IStreamOut openOutputStream(int portConfigId, in android.hardware.audio.common.SourceMetadata sourceMetadata, in @nullable android.media.audio.common.AudioOffloadInfo offloadInfo);
+ 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);
+ @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;
+ }
+ @VintfStability
+ parcelable OpenOutputStreamReturn {
+ android.hardware.audio.core.IStreamOut stream;
+ android.hardware.audio.core.StreamDescriptor desc;
+ }
}
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/StreamDescriptor.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/StreamDescriptor.aidl
new file mode 100644
index 0000000..db1ac22
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/StreamDescriptor.aidl
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.audio.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 COMMAND_BURST = 1;
+ @FixedSize @VintfStability
+ parcelable Position {
+ long frames;
+ long timeNs;
+ }
+ @FixedSize @VintfStability
+ parcelable Command {
+ int code;
+ int fmqByteCount;
+ }
+ @FixedSize @VintfStability
+ parcelable Reply {
+ int status;
+ int fmqByteCount;
+ android.hardware.audio.core.StreamDescriptor.Position observable;
+ android.hardware.audio.core.StreamDescriptor.Position hardware;
+ int latencyMs;
+ }
+ @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.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..94cacd9
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Descriptor.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.audio.effect;
+@VintfStability
+parcelable Descriptor {
+ android.hardware.audio.effect.Descriptor.Common common;
+ 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;
+ }
+ @VintfStability
+ parcelable Common {
+ android.hardware.audio.effect.Descriptor.Identity id;
+ }
+}
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..b6c9aab
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/IFactory.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
+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);
+}
diff --git a/audio/aidl/android/hardware/audio/core/AudioPatch.aidl b/audio/aidl/android/hardware/audio/core/AudioPatch.aidl
index 48ca214..005d4c0 100644
--- a/audio/aidl/android/hardware/audio/core/AudioPatch.aidl
+++ b/audio/aidl/android/hardware/audio/core/AudioPatch.aidl
@@ -37,4 +37,18 @@
* 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/IModule.aidl b/audio/aidl/android/hardware/audio/core/IModule.aidl
index 802cb2f..735f87f 100644
--- a/audio/aidl/android/hardware/audio/core/IModule.aidl
+++ b/audio/aidl/android/hardware/audio/core/IModule.aidl
@@ -23,6 +23,7 @@
import android.hardware.audio.core.IStreamIn;
import android.hardware.audio.core.IStreamOut;
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;
@@ -241,22 +242,54 @@
* '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.
*
- * @return An opened input stream.
- * @param portConfigId The ID of the audio mix port config.
- * @param sinkMetadata Description of the audio that will be recorded.
+ * 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.
+ *
+ * @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.
*/
- IStreamIn openInputStream(int portConfigId, in SinkMetadata sinkMetadata);
+ @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.
@@ -269,30 +302,62 @@
* the framework must provide additional information about the encoded
* audio stream in 'offloadInfo' 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.
*
- * @return An opened output stream.
- * @param portConfigId The ID of the audio mix port config.
- * @param sourceMetadata Description of the audio that will be played.
- * @param offloadInfo Additional information for offloaded playback.
+ * 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.
+ *
+ * @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.
* @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.
*/
- IStreamOut openOutputStream(int portConfigId, in SourceMetadata sourceMetadata,
- in @nullable AudioOffloadInfo offloadInfo);
+ @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;
+ }
+ @VintfStability
+ parcelable OpenOutputStreamReturn {
+ IStreamOut stream;
+ StreamDescriptor desc;
+ }
+ OpenOutputStreamReturn openOutputStream(in OpenOutputStreamArguments args);
/**
* Set an audio patch.
@@ -300,19 +365,27 @@
* 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. It is recommended that
- * updating of an existing audio patch should be performed by the HAL module
- * in a way that does not interrupt active audio streams involving audio
- * port configurations of the patch. If the HAL module is unable to avoid
- * interruption when updating a certain patch, it is permitted to allocate a
- * new patch ID for the result. The returned audio patch contains all the
- * information about the new or updated audio patch.
+ * 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.
- * An audio patch may be created before or after an audio steam is created
- * for this configuration.
+ *
+ * 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.
@@ -324,6 +397,9 @@
* @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
diff --git a/audio/aidl/android/hardware/audio/core/IStreamIn.aidl b/audio/aidl/android/hardware/audio/core/IStreamIn.aidl
index b770449..0c3e3d1 100644
--- a/audio/aidl/android/hardware/audio/core/IStreamIn.aidl
+++ b/audio/aidl/android/hardware/audio/core/IStreamIn.aidl
@@ -27,8 +27,12 @@
* Close the stream.
*
* Releases any resources allocated for this stream on the HAL module side.
- * The stream can not be operated after it has been closed. Methods of this
- * interface throw EX_ILLEGAL_STATE in for a closed stream.
+ * 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.
*/
diff --git a/audio/aidl/android/hardware/audio/core/IStreamOut.aidl b/audio/aidl/android/hardware/audio/core/IStreamOut.aidl
index 60212fc..9fdb37d 100644
--- a/audio/aidl/android/hardware/audio/core/IStreamOut.aidl
+++ b/audio/aidl/android/hardware/audio/core/IStreamOut.aidl
@@ -27,8 +27,12 @@
* Close the stream.
*
* Releases any resources allocated for this stream on the HAL module side.
- * The stream can not be operated after it has been closed. Methods of this
- * interface throw EX_ILLEGAL_STATE in for a closed stream.
+ * 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.
*/
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/StreamDescriptor.aidl b/audio/aidl/android/hardware/audio/core/StreamDescriptor.aidl
new file mode 100644
index 0000000..2b1ed8c
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/StreamDescriptor.aidl
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.core;
+
+import android.hardware.audio.core.MmapBufferDescriptor;
+import android.hardware.common.fmq.MQDescriptor;
+import android.hardware.common.fmq.SynchronizedReadWrite;
+
+/**
+ * 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.
+ */
+@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 {
+ /** Frame count. */
+ long frames;
+ /** Timestamp in nanoseconds. */
+ long timeNs;
+ }
+
+ /**
+ * The command used for audio I/O, see 'AudioBuffer'. For MMap No IRQ mode
+ * this command only provides updated positions and latency because actual
+ * audio I/O is done via the 'AudioBuffer.mmap' shared buffer.
+ */
+ const int COMMAND_BURST = 1;
+
+ /**
+ * 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.
+ */
+ @VintfStability
+ @FixedSize
+ parcelable Command {
+ /**
+ * One of COMMAND_* codes.
+ */
+ int code;
+ /**
+ * For output streams: the amount of bytes that the client requests the
+ * HAL module to read from the 'audio.fmq' queue.
+ * For input streams: the amount of bytes requested by the client to
+ * read from the hardware into the 'audio.fmq' queue.
+ *
+ * In both cases it is allowed for this field to contain any
+ * non-negative number. The value 0 can be used if the client only needs
+ * to retrieve current positions and latency. 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.
+ */
+ int fmqByteCount;
+ }
+ MQDescriptor<Command, SynchronizedReadWrite> command;
+
+ /**
+ * 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 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;
+ /**
+ * For output streams: the amount of bytes actually consumed by the HAL
+ * module from the 'audio.fmq' queue.
+ * For input streams: the amount of bytes actually provided by the HAL
+ * in the 'audio.fmq' queue.
+ *
+ * The returned value must not exceed the value passed in the
+ * 'fmqByteCount' field of the corresponding command or be negative.
+ */
+ int fmqByteCount;
+ /**
+ * 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).
+ */
+ 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.
+ */
+ int latencyMs;
+ }
+ 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 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.
+ *
+ * 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.
+ * 5. The HAL module writes the command status and current positions
+ * into 'reply' queue, and hangs on waiting on a read from
+ * the 'command' queue.
+ * 6. The client wakes up due to 5. and reads the reply.
+ *
+ * For input streams the following sequence of operations is used:
+ * 1. The client writes the 'BURST' command into the 'command' queue,
+ * 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.
+ * 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.
+ */
+ MQDescriptor<byte, SynchronizedReadWrite> fmq;
+ /**
+ * MMap buffers are shared directly with the DSP, which operates
+ * independently from the CPU. Writes and reads into these buffers
+ * are not synchronized with 'command' and 'reply' queues. However,
+ * the client still uses the 'BURST' command for obtaining current
+ * positions from the HAL module.
+ */
+ MmapBufferDescriptor mmap;
+ }
+ AudioBuffer audio;
+}
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..51b31c2
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/Descriptor.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.audio.effect;
+
+import android.media.audio.common.AudioUuid;
+
+/**
+ * Effect descriptor contains all information (capabilities, attributes, and ownership) for an
+ * effect implemented in the Audio Effect HAL. Framework uses this information to decide when and
+ * how to apply the effect.
+ */
+@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;
+ }
+
+ // Common attributes of all effect implementation.
+ @VintfStability
+ parcelable Common {
+ /**
+ * Identity of effect implementation.
+ */
+ Identity id;
+ }
+ Common common;
+}
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..99c2e6a
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/IFactory.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.effect;
+
+import android.hardware.audio.effect.Descriptor;
+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 type UUIDs.
+ * @return List of effect identities supported and filtered by type/implementation UUID.
+ */
+ Descriptor.Identity[] queryEffects(
+ in @nullable AudioUuid type, in @nullable AudioUuid implementation);
+}
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..9bca760
--- /dev/null
+++ b/audio/aidl/common/StreamWorker.cpp
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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;
+ mWorker = std::thread(&ThreadController::workerThread, this);
+ 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::RUNNING || !mError.empty();
+ });
+ mWorkerStateChangeRequest = false;
+ return mWorkerState == WorkerState::RUNNING;
+}
+
+void ThreadController::stop() {
+ {
+ std::lock_guard<std::mutex> lock(mWorkerLock);
+ if (mWorkerState != WorkerState::STOPPED) {
+ mWorkerState = WorkerState::STOPPED;
+ mWorkerStateChangeRequest = true;
+ }
+ }
+ 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 = mLogic->init();
+ if (error.empty() && !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));
+ }
+ }
+ {
+ 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..6260eca
--- /dev/null
+++ b/audio/aidl/common/include/StreamWorker.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 { STOPPED, RUNNING, PAUSE_REQUESTED, PAUSED, RESUME_REQUESTED };
+
+ public:
+ explicit ThreadController(StreamLogic* logic) : mLogic(logic) {}
+ ~ThreadController() { stop(); }
+
+ bool start(const std::string& name, int priority);
+ 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();
+ 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::STOPPED;
+ 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;
+};
+
+} // 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() { return mThread.stop(); }
+ 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..74549d4
--- /dev/null
+++ b/audio/aidl/common/include/Utils.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/media/audio/common/AudioChannelLayout.h>
+#include <aidl/android/media/audio/common/AudioFormatDescription.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;
+}
+
+} // 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..e3e484d
--- /dev/null
+++ b/audio/aidl/common/tests/streamworker_tests.cpp
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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, 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());
+}
+
+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
index ad1d9c7..6225fb3 100644
--- a/audio/aidl/default/Android.bp
+++ b/audio/aidl/default/Android.bp
@@ -7,15 +7,28 @@
default_applicable_licenses: ["hardware_interfaces_license"],
}
-cc_library_static {
- name: "libaudioserviceexampleimpl",
+cc_defaults {
+ name: "aidlaudioservice_defaults",
vendor: true,
shared_libs: [
+ "libaudioaidlcommon",
"libbase",
"libbinder_ndk",
+ "libcutils",
+ "libfmq",
"libstagefright_foundation",
- "android.media.audio.common.types-V1-ndk",
- "android.hardware.audio.core-V1-ndk",
+ "libutils",
+ "android.hardware.common-V2-ndk",
+ "android.hardware.common.fmq-V1-ndk",
+ ],
+}
+
+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: [
@@ -34,16 +47,54 @@
relative_install_path: "hw",
init_rc: ["android.hardware.audio.service-aidl.example.rc"],
vintf_fragments: ["android.hardware.audio.service-aidl.xml"],
- vendor: true,
- shared_libs: [
- "libbase",
- "libbinder_ndk",
- "libstagefright_foundation",
- "android.media.audio.common.types-V1-ndk",
- "android.hardware.audio.core-V1-ndk",
+ 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",
+ vendor: true,
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "android.media.audio.common.types-V1-ndk",
+ "android.hardware.audio.effect-V1-ndk",
+ ],
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-Wthread-safety",
+ ],
+}
+
+cc_library_static {
+ name: "libaudioeffectserviceexampleimpl",
+ defaults: ["aidlaudioeffectservice_defaults"],
+ export_include_dirs: ["include"],
+ srcs: [
+ "EffectFactory.cpp",
+ ],
+ visibility: [
+ ":__subpackages__",
+ ],
+}
+
+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"],
+ static_libs: [
+ "libaudioeffectserviceexampleimpl",
+ ],
+ srcs: ["EffectMain.cpp"],
+}
diff --git a/audio/aidl/default/EffectFactory.cpp b/audio/aidl/default/EffectFactory.cpp
new file mode 100644
index 0000000..a31e23f
--- /dev/null
+++ b/audio/aidl/default/EffectFactory.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AHAL_EffectFactory"
+#include <android-base/logging.h>
+
+#include "effectFactory-impl/EffectFactory.h"
+#include "equalizer-impl/Equalizer.h"
+#include "visualizer-impl/Visualizer.h"
+
+using aidl::android::media::audio::common::AudioUuid;
+
+namespace aidl::android::hardware::audio::effect {
+
+Factory::Factory() {
+ // TODO: implement this with xml parser on audio_effect.xml, and filter with optional
+ // parameters.
+ Descriptor::Identity id;
+ id.type = {static_cast<int32_t>(0x0bed4300),
+ 0xddd6,
+ 0x11db,
+ 0x8f34,
+ {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+ id.uuid = EqualizerUUID;
+ mIdentityList.push_back(id);
+ id.type = {static_cast<int32_t>(0xd3467faa),
+ 0xacc7,
+ 0x4d34,
+ 0xacaf,
+ {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+ id.uuid = VisualizerUUID;
+ mIdentityList.push_back(id);
+}
+
+ndk::ScopedAStatus Factory::queryEffects(const std::optional<AudioUuid>& in_type,
+ const std::optional<AudioUuid>& in_instance,
+ std::vector<Descriptor::Identity>* _aidl_return) {
+ std::copy_if(mIdentityList.begin(), mIdentityList.end(), std::back_inserter(*_aidl_return),
+ [&](auto& desc) {
+ return (!in_type.has_value() || in_type.value() == desc.type) &&
+ (!in_instance.has_value() || in_instance.value() == desc.uuid);
+ });
+ return ndk::ScopedAStatus::ok();
+}
+
+} // 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..3b3c39b
--- /dev/null
+++ b/audio/aidl/default/EffectMain.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 "effectFactory-impl/EffectFactory.h"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+int main() {
+ // This is a debug implementation, always enable debug logging.
+ android::base::SetMinimumLogSeverity(::android::base::DEBUG);
+ ABinderProcess_setThreadPoolMaxThreadCount(16);
+
+ auto effectFactory =
+ ndk::SharedRefBase::make<aidl::android::hardware::audio::effect::Factory>();
+ std::string serviceName = std::string() + effectFactory->descriptor + "/default";
+ binder_status_t status =
+ AServiceManager_addService(effectFactory->asBinder().get(), serviceName.c_str());
+ CHECK_EQ(STATUS_OK, status);
+ LOG(DEBUG) << __func__ << ": effectFactoryName:" << serviceName;
+
+ ABinderProcess_joinThreadPool();
+ return EXIT_FAILURE; // should not reach
+}
diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp
index 5b4d48a..af033d0 100644
--- a/audio/aidl/default/Module.cpp
+++ b/audio/aidl/default/Module.cpp
@@ -20,6 +20,8 @@
#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"
@@ -27,7 +29,10 @@
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;
@@ -36,6 +41,8 @@
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;
namespace aidl::android::hardware::audio::core {
@@ -87,28 +94,94 @@
erase_all_values(mPatches, std::set<int32_t>{patchId});
}
-void Module::cleanUpPatches(int32_t portConfigId) {
- auto& patches = getConfig().patches;
- if (patches.size() == 0) return;
- auto range = mPatches.equal_range(portConfigId);
- for (auto it = range.first; it != range.second; ++it) {
- auto patchIt = findById<AudioPatch>(patches, it->second);
- if (patchIt != patches.end()) {
- erase_if(patchIt->sourcePortConfigIds,
- [portConfigId](auto e) { return e == portConfigId; });
- erase_if(patchIt->sinkPortConfigIds,
- [portConfigId](auto e) { return e == portConfigId; });
- }
+ndk::ScopedAStatus Module::createStreamContext(int32_t in_portConfigId, int64_t in_bufferSizeFrames,
+ StreamContext* out_context) {
+ if (in_bufferSizeFrames <= 0) {
+ LOG(ERROR) << __func__ << ": non-positive buffer size " << in_bufferSizeFrames;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
- std::set<int32_t> erasedPatches;
- for (size_t i = patches.size() - 1; i != 0; --i) {
- const auto& patch = patches[i];
- if (patch.sourcePortConfigIds.empty() || patch.sinkPortConfigIds.empty()) {
- erasedPatches.insert(patch.id);
- patches.erase(patches.begin() + i);
- }
+ if (in_bufferSizeFrames < kMinimumStreamBufferSizeFrames) {
+ LOG(ERROR) << __func__ << ": insufficient buffer size " << in_bufferSizeFrames
+ << ", must be at least " << kMinimumStreamBufferSizeFrames;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
- erase_all_values(mPatches, erasedPatches);
+ 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 &&
+ (flags.get<AudioIoFlags::Tag::input>() &
+ 1 << static_cast<int32_t>(AudioInputFlags::MMAP_NOIRQ)) == 0) ||
+ (flags.getTag() == AudioIoFlags::Tag::output &&
+ (flags.get<AudioIoFlags::Tag::output>() &
+ 1 << static_cast<int32_t>(AudioOutputFlags::MMAP_NOIRQ)) == 0)) {
+ 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));
+ 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() {
@@ -135,6 +208,28 @@
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()
@@ -336,98 +431,78 @@
return ndk::ScopedAStatus::ok();
}
-ndk::ScopedAStatus Module::openInputStream(int32_t in_portConfigId,
- const SinkMetadata& in_sinkMetadata,
- std::shared_ptr<IStreamIn>* _aidl_return) {
- 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);
+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;
}
- 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 (portIt->flags.getTag() != AudioIoFlags::Tag::input ||
- portIt->ext.getTag() != AudioPortExt::Tag::mix) {
- LOG(ERROR) << __func__ << ": port config id " << in_portConfigId
+ 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);
}
- 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);
+ StreamContext context;
+ if (auto status = createStreamContext(in_args.portConfigId, in_args.bufferSizeFrames, &context);
+ !status.isOk()) {
+ return status;
}
- 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);
+ 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;
}
- auto stream = ndk::SharedRefBase::make<StreamIn>(in_sinkMetadata);
- mStreams.insert(portId, in_portConfigId, StreamWrapper(stream));
- *_aidl_return = std::move(stream);
+ 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(int32_t in_portConfigId,
- const SourceMetadata& in_sourceMetadata,
- const std::optional<AudioOffloadInfo>& in_offloadInfo,
- std::shared_ptr<IStreamOut>* _aidl_return) {
- 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);
+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;
}
- 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 (portIt->flags.getTag() != AudioIoFlags::Tag::output ||
- portIt->ext.getTag() != AudioPortExt::Tag::mix) {
- LOG(ERROR) << __func__ << ": port config id " << in_portConfigId
+ 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);
}
- if (portConfigIt->flags.has_value() &&
- ((portConfigIt->flags.value().get<AudioIoFlags::Tag::output>() &
- 1 << static_cast<int32_t>(AudioOutputFlags::COMPRESS_OFFLOAD)) != 0) &&
- !in_offloadInfo.has_value()) {
- LOG(ERROR) << __func__ << ": port config id " << in_portConfigId
+ if ((port->flags.get<AudioIoFlags::Tag::output>() &
+ 1 << static_cast<int32_t>(AudioOutputFlags::COMPRESS_OFFLOAD)) != 0 &&
+ !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);
}
- 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);
+ StreamContext context;
+ if (auto status = createStreamContext(in_args.portConfigId, in_args.bufferSizeFrames, &context);
+ !status.isOk()) {
+ return status;
}
- 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);
+ 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;
}
- auto stream = ndk::SharedRefBase::make<StreamOut>(in_sourceMetadata, in_offloadInfo);
- mStreams.insert(portId, in_portConfigId, StreamWrapper(stream));
- *_aidl_return = std::move(stream);
+ 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();
}
@@ -512,15 +587,24 @@
}
}
*_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);
- LOG(DEBUG) << __func__ << ": created or updated patch id " << _aidl_return->id;
+ updateStreamsConnectedState(oldPatch, *_aidl_return);
+
+ LOG(DEBUG) << __func__ << ": " << (oldPatch.id == 0 ? "created" : "updated") << " patch "
+ << _aidl_return->toString();
return ndk::ScopedAStatus::ok();
}
@@ -655,6 +739,7 @@
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();
diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp
index e16b2c6..312df72 100644
--- a/audio/aidl/default/Stream.cpp
+++ b/audio/aidl/default/Stream.cpp
@@ -15,9 +15,10 @@
*/
#define LOG_TAG "AHAL_Stream"
-#define LOG_NDEBUG 0
#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;
@@ -26,11 +27,199 @@
namespace aidl::android::hardware::audio::core {
-StreamIn::StreamIn(const SinkMetadata& sinkMetadata) : mMetadata(sinkMetadata) {}
+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());
+ }
+}
-ndk::ScopedAStatus StreamIn::close() {
+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 "";
+}
+
+const std::string StreamInWorkerLogic::kThreadName = "reader";
+
+StreamInWorkerLogic::Status StreamInWorkerLogic::cycle() {
+ StreamDescriptor::Command command{};
+ if (!mCommandMQ->readBlocking(&command, 1)) {
+ LOG(ERROR) << __func__ << ": reading of command from MQ failed";
+ return Status::ABORT;
+ }
+ StreamDescriptor::Reply reply{};
+ if (command.code == StreamContext::COMMAND_EXIT &&
+ command.fmqByteCount == mInternalCommandCookie) {
+ LOG(DEBUG) << __func__ << ": received EXIT command";
+ // This is an internal command, no need to reply.
+ return Status::EXIT;
+ } else if (command.code == StreamDescriptor::COMMAND_BURST && command.fmqByteCount >= 0) {
+ LOG(DEBUG) << __func__ << ": received BURST read command for " << command.fmqByteCount
+ << " bytes";
+ usleep(3000); // Simulate a blocking call into the driver.
+ const size_t byteCount = std::min({static_cast<size_t>(command.fmqByteCount),
+ mDataMQ->availableToWrite(), mDataBufferSize});
+ const bool isConnected = mIsConnected;
+ // Simulate reading of data, or provide zeroes if the stream is not connected.
+ for (size_t i = 0; i < byteCount; ++i) {
+ using buffer_type = decltype(mDataBuffer)::element_type;
+ constexpr int kBufferValueRange = std::numeric_limits<buffer_type>::max() -
+ std::numeric_limits<buffer_type>::min() + 1;
+ mDataBuffer[i] = isConnected ? (std::rand() % kBufferValueRange) +
+ std::numeric_limits<buffer_type>::min()
+ : 0;
+ }
+ bool success = byteCount > 0 ? mDataMQ->write(&mDataBuffer[0], byteCount) : true;
+ if (success) {
+ LOG(DEBUG) << __func__ << ": writing of " << byteCount << " bytes into data MQ"
+ << " succeeded; connected? " << isConnected;
+ // Frames are provided and counted regardless of connection status.
+ reply.fmqByteCount = byteCount;
+ mFrameCount += byteCount / mFrameSize;
+ if (isConnected) {
+ reply.status = STATUS_OK;
+ reply.observable.frames = mFrameCount;
+ reply.observable.timeNs = ::android::elapsedRealtimeNano();
+ } else {
+ reply.status = STATUS_INVALID_OPERATION;
+ }
+ } else {
+ LOG(WARNING) << __func__ << ": writing of " << byteCount
+ << " bytes of data to MQ failed";
+ reply.status = STATUS_NOT_ENOUGH_DATA;
+ }
+ reply.latencyMs = Module::kLatencyMs;
+ } else {
+ LOG(WARNING) << __func__ << ": invalid command (" << command.toString()
+ << ") or count: " << command.fmqByteCount;
+ reply.status = STATUS_BAD_VALUE;
+ }
+ LOG(DEBUG) << __func__ << ": writing reply " << reply.toString();
+ if (!mReplyMQ->writeBlocking(&reply, 1)) {
+ LOG(ERROR) << __func__ << ": writing of reply " << reply.toString() << " to MQ failed";
+ return Status::ABORT;
+ }
+ return Status::CONTINUE;
+}
+
+const std::string StreamOutWorkerLogic::kThreadName = "writer";
+
+StreamOutWorkerLogic::Status StreamOutWorkerLogic::cycle() {
+ StreamDescriptor::Command command{};
+ if (!mCommandMQ->readBlocking(&command, 1)) {
+ LOG(ERROR) << __func__ << ": reading of command from MQ failed";
+ return Status::ABORT;
+ }
+ StreamDescriptor::Reply reply{};
+ if (command.code == StreamContext::COMMAND_EXIT &&
+ command.fmqByteCount == mInternalCommandCookie) {
+ LOG(DEBUG) << __func__ << ": received EXIT command";
+ // This is an internal command, no need to reply.
+ return Status::EXIT;
+ } else if (command.code == StreamDescriptor::COMMAND_BURST && command.fmqByteCount >= 0) {
+ LOG(DEBUG) << __func__ << ": received BURST write command for " << command.fmqByteCount
+ << " bytes";
+ const size_t byteCount = std::min({static_cast<size_t>(command.fmqByteCount),
+ mDataMQ->availableToRead(), mDataBufferSize});
+ bool success = byteCount > 0 ? mDataMQ->read(&mDataBuffer[0], byteCount) : true;
+ if (success) {
+ const bool isConnected = mIsConnected;
+ LOG(DEBUG) << __func__ << ": reading of " << byteCount << " bytes from data MQ"
+ << " succeeded; connected? " << isConnected;
+ // Frames are consumed and counted regardless of connection status.
+ reply.fmqByteCount = byteCount;
+ mFrameCount += byteCount / mFrameSize;
+ if (isConnected) {
+ reply.status = STATUS_OK;
+ reply.observable.frames = mFrameCount;
+ reply.observable.timeNs = ::android::elapsedRealtimeNano();
+ } else {
+ reply.status = STATUS_INVALID_OPERATION;
+ }
+ usleep(3000); // Simulate a blocking call into the driver.
+ } else {
+ LOG(WARNING) << __func__ << ": reading of " << byteCount
+ << " bytes of data from MQ failed";
+ reply.status = STATUS_NOT_ENOUGH_DATA;
+ }
+ reply.latencyMs = Module::kLatencyMs;
+ } else {
+ LOG(WARNING) << __func__ << ": invalid command (" << command.toString()
+ << ") or count: " << command.fmqByteCount;
+ reply.status = STATUS_BAD_VALUE;
+ }
+ LOG(DEBUG) << __func__ << ": writing reply " << reply.toString();
+ if (!mReplyMQ->writeBlocking(&reply, 1)) {
+ LOG(ERROR) << __func__ << ": writing of reply " << reply.toString() << " to MQ failed";
+ return Status::ABORT;
+ }
+ return Status::CONTINUE;
+}
+
+template <class Metadata, class StreamWorker>
+StreamCommon<Metadata, StreamWorker>::~StreamCommon() {
+ if (!mIsClosed) {
+ 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 (!mIsClosed) {
+ stopWorker();
+ LOG(DEBUG) << __func__ << ": joining the worker thread...";
+ mWorker.stop();
+ LOG(DEBUG) << __func__ << ": worker thread joined";
+ mContext.reset();
mIsClosed = true;
return ndk::ScopedAStatus::ok();
} else {
@@ -39,38 +228,44 @@
}
}
-ndk::ScopedAStatus StreamIn::updateMetadata(const SinkMetadata& in_sinkMetadata) {
+template <class Metadata, class StreamWorker>
+void StreamCommon<Metadata, StreamWorker>::stopWorker() {
+ if (auto commandMQ = mContext.getCommandMQ(); commandMQ != nullptr) {
+ LOG(DEBUG) << __func__ << ": asking the worker to stop...";
+ StreamDescriptor::Command cmd;
+ cmd.code = StreamContext::COMMAND_EXIT;
+ cmd.fmqByteCount = mContext.getInternalCommandCookie();
+ // FIXME: This can block in the case when the client wrote a command
+ // while the stream worker's cycle is not running. Need to revisit
+ // when implementing standby and pause/resume.
+ 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 (!mIsClosed) {
- mMetadata = in_sinkMetadata;
+ mMetadata = metadata;
return ndk::ScopedAStatus::ok();
}
LOG(ERROR) << __func__ << ": stream was closed";
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}
-StreamOut::StreamOut(const SourceMetadata& sourceMetadata,
+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)
- : mMetadata(sourceMetadata), mOffloadInfo(offloadInfo) {}
-
-ndk::ScopedAStatus StreamOut::close() {
+ : StreamCommon<SourceMetadata, StreamOutWorker>(sourceMetadata, std::move(context)),
+ mOffloadInfo(offloadInfo) {
LOG(DEBUG) << __func__;
- if (!mIsClosed) {
- mIsClosed = true;
- return ndk::ScopedAStatus::ok();
- }
- LOG(ERROR) << __func__ << ": stream was already closed";
- return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
-}
-
-ndk::ScopedAStatus StreamOut::updateMetadata(const SourceMetadata& in_sourceMetadata) {
- LOG(DEBUG) << __func__;
- if (!mIsClosed) {
- mMetadata = in_sourceMetadata;
- return ndk::ScopedAStatus::ok();
- }
- LOG(ERROR) << __func__ << ": stream was closed";
- return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}
} // 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..01c0e6e
--- /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 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.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/include/core-impl/Module.h b/audio/aidl/default/include/core-impl/Module.h
index 81a02ba..61516b2 100644
--- a/audio/aidl/default/include/core-impl/Module.h
+++ b/audio/aidl/default/include/core-impl/Module.h
@@ -28,6 +28,11 @@
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 connectExternalDevice(
@@ -48,15 +53,15 @@
int32_t in_portId,
std::vector<::aidl::android::hardware::audio::core::AudioRoute>* _aidl_return) override;
ndk::ScopedAStatus openInputStream(
- int32_t in_portConfigId,
- const ::aidl::android::hardware::audio::common::SinkMetadata& in_sinkMetadata,
- std::shared_ptr<IStreamIn>* _aidl_return) override;
+ const ::aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments&
+ in_args,
+ ::aidl::android::hardware::audio::core::IModule::OpenInputStreamReturn* _aidl_return)
+ override;
ndk::ScopedAStatus openOutputStream(
- int32_t in_portConfigId,
- const ::aidl::android::hardware::audio::common::SourceMetadata& in_sourceMetadata,
- const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
- in_offloadInfo,
- std::shared_ptr<IStreamOut>* _aidl_return) override;
+ 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(
@@ -66,11 +71,20 @@
ndk::ScopedAStatus resetAudioPatch(int32_t in_patchId) override;
ndk::ScopedAStatus resetAudioPortConfig(int32_t in_portConfigId) override;
- private:
void cleanUpPatch(int32_t patchId);
- void cleanUpPatches(int32_t portConfigId);
+ ndk::ScopedAStatus createStreamContext(
+ int32_t in_portConfigId, int64_t in_bufferSizeFrames,
+ ::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;
diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h
index 87104dd..816cdb1 100644
--- a/audio/aidl/default/include/core-impl/Stream.h
+++ b/audio/aidl/default/include/core-impl/Stream.h
@@ -16,50 +16,203 @@
#pragma once
+#include <atomic>
+#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/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 {
-class StreamIn : public BnStreamIn {
- ndk::ScopedAStatus close() override;
- ndk::ScopedAStatus updateMetadata(
- const ::aidl::android::hardware::audio::common::SinkMetadata& in_sinkMetadata) override;
-
+// 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:
- explicit StreamIn(const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata);
- bool isClosed() const { return mIsClosed; }
+ 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.COMMAND_*
+ static constexpr int COMMAND_EXIT = -1;
+
+ StreamContext() = default;
+ StreamContext(std::unique_ptr<CommandMQ> commandMQ, std::unique_ptr<ReplyMQ> replyMQ,
+ size_t frameSize, std::unique_ptr<DataMQ> dataMQ)
+ : mCommandMQ(std::move(commandMQ)),
+ mInternalCommandCookie(std::rand()),
+ mReplyMQ(std::move(replyMQ)),
+ mFrameSize(frameSize),
+ mDataMQ(std::move(dataMQ)) {}
+ StreamContext(StreamContext&& other)
+ : mCommandMQ(std::move(other.mCommandMQ)),
+ mInternalCommandCookie(other.mInternalCommandCookie),
+ mReplyMQ(std::move(other.mReplyMQ)),
+ mFrameSize(other.mFrameSize),
+ mDataMQ(std::move(other.mDataMQ)) {}
+ 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);
+ return *this;
+ }
+
+ void fillDescriptor(StreamDescriptor* desc);
+ 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(); }
+ bool isValid() const;
+ void reset();
private:
- ::aidl::android::hardware::audio::common::SinkMetadata mMetadata;
- bool mIsClosed = false;
+ 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;
};
-class StreamOut : public BnStreamOut {
- ndk::ScopedAStatus close() override;
+class StreamWorkerCommonLogic : public ::android::hardware::audio::common::StreamLogic {
+ public:
+ 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()) {}
+ std::string init() override;
+
+ // Used both by the main and worker threads.
+ std::atomic<bool> mIsConnected = false;
+ // 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;
+ // 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;
+};
+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;
+};
+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 mIsClosed; }
+ 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;
+ // This variable is checked in the destructor which can be called on an arbitrary Binder thread,
+ // thus we need to ensure that any changes made by other threads are sequentially consistent.
+ std::atomic<bool> mIsClosed = false;
+};
+
+class StreamIn
+ : 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;
+ 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);
- bool isClosed() const { return mIsClosed; }
private:
- ::aidl::android::hardware::audio::common::SourceMetadata mMetadata;
std::optional<::aidl::android::media::audio::common::AudioOffloadInfo> mOffloadInfo;
- bool mIsClosed = false;
};
class StreamWrapper {
@@ -74,6 +227,15 @@
},
mStream);
}
+ void setStreamIsConnected(bool connected) {
+ std::visit(
+ [&](auto&& ws) -> bool {
+ auto s = ws.lock();
+ if (s) s->setIsConnected(connected);
+ return !!s;
+ },
+ mStream);
+ }
private:
std::variant<std::weak_ptr<StreamIn>, std::weak_ptr<StreamOut>> mStream;
@@ -93,6 +255,11 @@
mStreams.insert(std::pair{portConfigId, sw});
mStreams.insert(std::pair{portId, 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
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..7670250
--- /dev/null
+++ b/audio/aidl/default/include/effectFactory-impl/EffectFactory.h
@@ -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.
+ */
+
+#pragma once
+
+#include <optional>
+#include <vector>
+
+#include <aidl/android/hardware/audio/effect/BnFactory.h>
+
+namespace aidl::android::hardware::audio::effect {
+
+class Factory : public BnFactory {
+ public:
+ Factory();
+ /**
+ * @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 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,
+ std::vector<Descriptor::Identity>* out_descriptor) override;
+
+ private:
+ // List of effect descriptors supported by the devices.
+ std::vector<Descriptor::Identity> mIdentityList;
+};
+} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/equalizer-impl/Equalizer.h b/audio/aidl/default/include/equalizer-impl/Equalizer.h
new file mode 100644
index 0000000..86f8c3a
--- /dev/null
+++ b/audio/aidl/default/include/equalizer-impl/Equalizer.h
@@ -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.
+ */
+
+#pragma once
+
+#include <cstdlib>
+
+namespace aidl::android::hardware::audio::effect {
+
+// Equalizer implementation UUID.
+static const ::aidl::android::media::audio::common::AudioUuid EqualizerUUID = {
+ static_cast<int32_t>(0xce772f20),
+ 0x847d,
+ 0x11df,
+ 0xbb17,
+ {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+
+} // namespace aidl::android::hardware::audio::effect
\ No newline at end of file
diff --git a/audio/aidl/default/include/visualizer-impl/Visualizer.h b/audio/aidl/default/include/visualizer-impl/Visualizer.h
new file mode 100644
index 0000000..4b82dd0
--- /dev/null
+++ b/audio/aidl/default/include/visualizer-impl/Visualizer.h
@@ -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.
+ */
+
+#pragma once
+
+#include <cstdlib>
+
+namespace aidl::android::hardware::audio::effect {
+
+// Visualizer implementation UUID.
+static const ::aidl::android::media::audio::common::AudioUuid VisualizerUUID = {
+ static_cast<int32_t>(0x1d4033c0),
+ 0x8557,
+ 0x11df,
+ 0x9f2d,
+ {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+
+} // namespace aidl::android::hardware::audio::effect
\ No newline at end of file
diff --git a/audio/aidl/default/main.cpp b/audio/aidl/default/main.cpp
index aeb9983..15874a0 100644
--- a/audio/aidl/default/main.cpp
+++ b/audio/aidl/default/main.cpp
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+#include <cstdlib>
+#include <ctime>
+
#include "core-impl/Config.h"
#include "core-impl/Module.h"
@@ -25,6 +28,9 @@
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);
diff --git a/audio/aidl/vts/Android.bp b/audio/aidl/vts/Android.bp
index cd5915b..2e12e7e 100644
--- a/audio/aidl/vts/Android.bp
+++ b/audio/aidl/vts/Android.bp
@@ -12,18 +12,57 @@
defaults: [
"VtsHalTargetTestDefaults",
"use_libaidlvintf_gtest_helper_static",
+ "latest_android_hardware_audio_common_ndk_static",
+ "latest_android_hardware_audio_core_ndk_static",
+ "latest_android_media_audio_common_types_ndk_static",
+ ],
+ shared_libs: [
+ "libbinder_ndk",
+ "libcutils",
+ "libfmq",
+ ],
+ static_libs: [
+ "android.hardware.common-V2-ndk",
+ "android.hardware.common.fmq-V1-ndk",
+ "libaudioaidlcommon",
+ ],
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-Wthread-safety",
],
srcs: [
"ModuleConfig.cpp",
"VtsHalAudioCoreTargetTest.cpp",
],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+}
+
+cc_test {
+ name: "VtsHalAudioEffectTargetTest",
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "use_libaidlvintf_gtest_helper_static",
+ ],
+ srcs: [
+ "VtsHalAudioEffectTargetTest.cpp",
+ ],
shared_libs: [
"libbinder_ndk",
],
static_libs: [
- "android.hardware.audio.common-V1-ndk",
- "android.hardware.audio.core-V1-ndk",
"android.media.audio.common.types-V1-ndk",
+ "android.hardware.audio.effect-V1-ndk",
+ ],
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-Wthread-safety",
],
test_suites: [
"general-tests",
diff --git a/audio/aidl/vts/AudioHalBinderServiceUtil.h b/audio/aidl/vts/AudioHalBinderServiceUtil.h
new file mode 100644
index 0000000..e928286
--- /dev/null
+++ b/audio/aidl/vts/AudioHalBinderServiceUtil.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+
+#include <android-base/properties.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) << "succeed 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/ModuleConfig.cpp b/audio/aidl/vts/ModuleConfig.cpp
index 969b0e9..e36ab4a 100644
--- a/audio/aidl/vts/ModuleConfig.cpp
+++ b/audio/aidl/vts/ModuleConfig.cpp
@@ -123,6 +123,15 @@
return result;
}
+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;
diff --git a/audio/aidl/vts/ModuleConfig.h b/audio/aidl/vts/ModuleConfig.h
index df13430..552f971 100644
--- a/audio/aidl/vts/ModuleConfig.h
+++ b/audio/aidl/vts/ModuleConfig.h
@@ -54,6 +54,9 @@
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;
diff --git a/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp
index bb24365..ab70ec4 100644
--- a/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp
@@ -15,26 +15,27 @@
*/
#include <algorithm>
-#include <condition_variable>
+#include <limits>
#include <memory>
-#include <mutex>
#include <optional>
#include <set>
#include <string>
+#include <vector>
#define LOG_TAG "VtsHalAudioCore"
#include <android-base/logging.h>
+#include <StreamWorker.h>
#include <aidl/Gtest.h>
#include <aidl/Vintf.h>
#include <aidl/android/hardware/audio/core/IConfig.h>
#include <aidl/android/hardware/audio/core/IModule.h>
#include <aidl/android/media/audio/common/AudioIoFlags.h>
#include <aidl/android/media/audio/common/AudioOutputFlags.h>
-#include <android-base/properties.h>
-#include <android/binder_manager.h>
-#include <android/binder_process.h>
+#include <android-base/chrono_utils.h>
+#include <fmq/AidlMessageQueue.h>
+#include "AudioHalBinderServiceUtil.h"
#include "ModuleConfig.h"
using namespace android;
@@ -48,6 +49,8 @@
using aidl::android::hardware::audio::core::IStreamIn;
using aidl::android::hardware::audio::core::IStreamOut;
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;
@@ -61,6 +64,8 @@
using aidl::android::media::audio::common::AudioPortExt;
using aidl::android::media::audio::common::AudioSource;
using aidl::android::media::audio::common::AudioUsage;
+using android::hardware::audio::common::StreamLogic;
+using android::hardware::audio::common::StreamWorker;
using ndk::ScopedAStatus;
namespace ndk {
@@ -92,38 +97,6 @@
return AudioDeviceAddress::make<AudioDeviceAddress::Tag::id>(std::to_string(++nextId));
}
-struct AidlDeathRecipient {
- const ndk::SpAIBinder binder;
- const ndk::ScopedAIBinder_DeathRecipient recipient;
- std::mutex mutex;
- std::condition_variable condition;
- bool fired = false;
-
- 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);
- }
-
- void binderDied() {
- std::unique_lock<std::mutex> lock(mutex);
- fired = true;
- condition.notify_one();
- };
-
- bool waitForFired(int timeoutMs) {
- std::unique_lock<std::mutex> lock(mutex);
- condition.wait_for(lock, std::chrono::milliseconds(timeoutMs), [this]() { return fired; });
- return fired;
- }
-
- static void binderDiedCallbackAidl(void* cookie) {
- AidlDeathRecipient* self = static_cast<AidlDeathRecipient*>(cookie);
- self->binderDied();
- }
-};
-
template <typename T>
struct IsInput {
constexpr operator bool() const;
@@ -225,6 +198,9 @@
class AudioCoreModule : public testing::TestWithParam<std::string> {
public:
+ // The default buffer size is used mostly for negative tests.
+ static constexpr int kDefaultBufferSizeFrames = 256;
+
void SetUp() override {
ASSERT_NO_FATAL_FAILURE(ConnectToService());
debug.flags().simulateDeviceConnections = true;
@@ -240,20 +216,15 @@
}
void ConnectToService() {
- module = IModule::fromBinder(
- ndk::SpAIBinder(AServiceManager_getService(GetParam().c_str())));
+ module = IModule::fromBinder(binderUtil.connectToService(GetParam()));
ASSERT_NE(module, nullptr);
}
void RestartService() {
ASSERT_NE(module, nullptr);
moduleConfig.reset();
- deathHandler.reset(new AidlDeathRecipient(module->asBinder()));
- ASSERT_EQ(STATUS_OK, deathHandler->linkToDeath());
- ASSERT_TRUE(base::SetProperty("sys.audio.restart.hal", "1"));
- EXPECT_TRUE(deathHandler->waitForFired(3000));
- deathHandler.reset();
- ASSERT_NO_FATAL_FAILURE(ConnectToService());
+ module = IModule::fromBinder(binderUtil.restartService());
+ ASSERT_NE(module, nullptr);
}
void ApplyEveryConfig(const std::vector<AudioPortConfig>& configs) {
@@ -324,8 +295,8 @@
}
std::shared_ptr<IModule> module;
- std::unique_ptr<AidlDeathRecipient> deathHandler;
std::unique_ptr<ModuleConfig> moduleConfig;
+ AudioHalBinderServiceUtil binderUtil;
WithDebugFlags debug;
};
@@ -367,6 +338,214 @@
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;
+};
+
+class StreamCommonLogic : public StreamLogic {
+ public:
+ StreamDescriptor::Position getLastObservablePosition() {
+ std::lock_guard<std::mutex> lock(mLock);
+ return mLastReply.observable;
+ }
+
+ protected:
+ explicit StreamCommonLogic(const StreamContext& context)
+ : mCommandMQ(context.getCommandMQ()),
+ mReplyMQ(context.getReplyMQ()),
+ mDataMQ(context.getDataMQ()),
+ mData(context.getBufferSizeBytes()) {}
+ StreamContext::CommandMQ* getCommandMQ() const { return mCommandMQ; }
+ StreamContext::ReplyMQ* getReplyMQ() const { return mReplyMQ; }
+
+ std::string init() override { return ""; }
+
+ StreamContext::CommandMQ* mCommandMQ;
+ StreamContext::ReplyMQ* mReplyMQ;
+ StreamContext::DataMQ* mDataMQ;
+ std::vector<int8_t> mData;
+ std::mutex mLock;
+ StreamDescriptor::Reply mLastReply GUARDED_BY(mLock);
+};
+
+class StreamReaderLogic : public StreamCommonLogic {
+ public:
+ explicit StreamReaderLogic(const StreamContext& context) : StreamCommonLogic(context) {}
+
+ protected:
+ Status cycle() override {
+ StreamDescriptor::Command command{};
+ command.code = StreamDescriptor::COMMAND_BURST;
+ command.fmqByteCount = mData.size();
+ if (!mCommandMQ->writeBlocking(&command, 1)) {
+ LOG(ERROR) << __func__ << ": writing of command into MQ failed";
+ return Status::ABORT;
+ }
+ StreamDescriptor::Reply reply{};
+ if (!mReplyMQ->readBlocking(&reply, 1)) {
+ LOG(ERROR) << __func__ << ": reading of reply from MQ failed";
+ return Status::ABORT;
+ }
+ if (reply.status != STATUS_OK) {
+ LOG(ERROR) << __func__ << ": received error status: " << statusToString(reply.status);
+ return Status::ABORT;
+ }
+ if (reply.fmqByteCount < 0 || reply.fmqByteCount > command.fmqByteCount) {
+ LOG(ERROR) << __func__
+ << ": received invalid byte count in the reply: " << reply.fmqByteCount;
+ return Status::ABORT;
+ }
+ {
+ std::lock_guard<std::mutex> lock(mLock);
+ mLastReply = reply;
+ }
+ const size_t readCount = std::min({mDataMQ->availableToRead(),
+ static_cast<size_t>(reply.fmqByteCount), mData.size()});
+ if (readCount == 0 || mDataMQ->read(mData.data(), readCount)) {
+ return Status::CONTINUE;
+ }
+ LOG(ERROR) << __func__ << ": reading of " << readCount << " data bytes from MQ failed";
+ return Status::ABORT;
+ }
+};
+using StreamReader = StreamWorker<StreamReaderLogic>;
+
+class StreamWriterLogic : public StreamCommonLogic {
+ public:
+ explicit StreamWriterLogic(const StreamContext& context) : StreamCommonLogic(context) {}
+
+ protected:
+ Status cycle() override {
+ if (!mDataMQ->write(mData.data(), mData.size())) {
+ LOG(ERROR) << __func__ << ": writing of " << mData.size() << " bytes to MQ failed";
+ return Status::ABORT;
+ }
+ StreamDescriptor::Command command{};
+ command.code = StreamDescriptor::COMMAND_BURST;
+ command.fmqByteCount = mData.size();
+ if (!mCommandMQ->writeBlocking(&command, 1)) {
+ LOG(ERROR) << __func__ << ": writing of command into MQ failed";
+ return Status::ABORT;
+ }
+ StreamDescriptor::Reply reply{};
+ if (!mReplyMQ->readBlocking(&reply, 1)) {
+ LOG(ERROR) << __func__ << ": reading of reply from MQ failed";
+ return Status::ABORT;
+ }
+ if (reply.status != STATUS_OK) {
+ LOG(ERROR) << __func__ << ": received error status: " << statusToString(reply.status);
+ return Status::ABORT;
+ }
+ if (reply.fmqByteCount < 0 || reply.fmqByteCount > command.fmqByteCount) {
+ LOG(ERROR) << __func__
+ << ": received invalid byte count in the reply: " << reply.fmqByteCount;
+ return Status::ABORT;
+ }
+ {
+ std::lock_guard<std::mutex> lock(mLock);
+ mLastReply = reply;
+ }
+ return Status::CONTINUE;
+ }
+};
+using StreamWriter = StreamWorker<StreamWriterLogic>;
+
+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>;
+};
+
+// A dedicated version to test replies to invalid commands.
+class StreamInvalidCommandLogic : public StreamCommonLogic {
+ public:
+ StreamInvalidCommandLogic(const StreamContext& context,
+ const std::vector<StreamDescriptor::Command>& commands)
+ : StreamCommonLogic(context), mCommands(commands) {}
+
+ std::vector<std::string> getUnexpectedStatuses() {
+ std::lock_guard<std::mutex> lock(mLock);
+ return mUnexpectedStatuses;
+ }
+
+ protected:
+ Status cycle() override {
+ // Send all commands in one cycle to simplify testing.
+ // Extra logging helps to sort out issues with unexpected HAL behavior.
+ for (const auto& command : mCommands) {
+ LOG(INFO) << __func__ << ": writing command " << command.toString() << " into MQ...";
+ if (!getCommandMQ()->writeBlocking(&command, 1)) {
+ LOG(ERROR) << __func__ << ": writing of command into MQ failed";
+ return Status::ABORT;
+ }
+ StreamDescriptor::Reply reply{};
+ LOG(INFO) << __func__ << ": reading reply for command " << command.toString() << "...";
+ if (!getReplyMQ()->readBlocking(&reply, 1)) {
+ LOG(ERROR) << __func__ << ": reading of reply from MQ failed";
+ return Status::ABORT;
+ }
+ LOG(INFO) << __func__ << ": received status " << statusToString(reply.status)
+ << " for command " << command.toString();
+ if (reply.status != STATUS_BAD_VALUE) {
+ std::string s = command.toString();
+ s.append(", ").append(statusToString(reply.status));
+ std::lock_guard<std::mutex> lock(mLock);
+ mUnexpectedStatuses.push_back(std::move(s));
+ }
+ };
+ return Status::EXIT;
+ }
+
+ private:
+ const std::vector<StreamDescriptor::Command> mCommands;
+ std::mutex mLock;
+ std::vector<std::string> mUnexpectedStatuses GUARDED_BY(mLock);
+};
+
template <typename Stream>
class WithStream {
public:
@@ -376,24 +555,31 @@
WithStream& operator=(const WithStream&) = delete;
~WithStream() {
if (mStream != nullptr) {
+ mContext.reset();
ScopedAStatus status = mStream->close();
EXPECT_EQ(EX_NONE, status.getExceptionCode())
<< status << "; port config id " << getPortId();
}
}
void SetUpPortConfig(IModule* module) { ASSERT_NO_FATAL_FAILURE(mPortConfig.SetUp(module)); }
- ScopedAStatus SetUpNoChecks(IModule* module) {
- return SetUpNoChecks(module, mPortConfig.get());
+ ScopedAStatus SetUpNoChecks(IModule* module, long bufferSizeFrames) {
+ return SetUpNoChecks(module, mPortConfig.get(), bufferSizeFrames);
}
- ScopedAStatus SetUpNoChecks(IModule* module, const AudioPortConfig& portConfig);
- void SetUp(IModule* module) {
+ ScopedAStatus SetUpNoChecks(IModule* module, const AudioPortConfig& portConfig,
+ long bufferSizeFrames);
+ void SetUp(IModule* module, long bufferSizeFrames) {
ASSERT_NO_FATAL_FAILURE(SetUpPortConfig(module));
- ScopedAStatus status = SetUpNoChecks(module);
+ ScopedAStatus status = SetUpNoChecks(module, bufferSizeFrames);
ASSERT_EQ(EX_NONE, status.getExceptionCode())
<< status << "; 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; }
std::shared_ptr<Stream> getSharedPointer() const { return mStream; }
const AudioPortConfig& getPortConfig() const { return mPortConfig.get(); }
int32_t getPortId() const { return mPortConfig.getId(); }
@@ -401,6 +587,8 @@
private:
WithAudioPortConfig mPortConfig;
std::shared_ptr<Stream> mStream;
+ StreamDescriptor mDescriptor;
+ std::optional<StreamContext> mContext;
};
SinkMetadata GenerateSinkMetadata(const AudioPortConfig& portConfig) {
@@ -415,8 +603,19 @@
template <>
ScopedAStatus WithStream<IStreamIn>::SetUpNoChecks(IModule* module,
- const AudioPortConfig& portConfig) {
- return module->openInputStream(portConfig.id, GenerateSinkMetadata(portConfig), &mStream);
+ const AudioPortConfig& portConfig,
+ long bufferSizeFrames) {
+ aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments args;
+ args.portConfigId = portConfig.id;
+ args.sinkMetadata = GenerateSinkMetadata(portConfig);
+ args.bufferSizeFrames = bufferSizeFrames;
+ 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);
+ }
+ return status;
}
SourceMetadata GenerateSourceMetadata(const AudioPortConfig& portConfig) {
@@ -432,10 +631,20 @@
template <>
ScopedAStatus WithStream<IStreamOut>::SetUpNoChecks(IModule* module,
- const AudioPortConfig& portConfig) {
- return module->openOutputStream(portConfig.id, GenerateSourceMetadata(portConfig),
- ModuleConfig::generateOffloadInfoIfNeeded(portConfig),
- &mStream);
+ 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;
+ 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);
+ }
+ return status;
}
class WithAudioPatch {
@@ -443,6 +652,10 @@
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() {
@@ -467,9 +680,18 @@
ASSERT_EQ(EX_NONE, status.getExceptionCode())
<< status << "; 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;
@@ -535,7 +757,7 @@
}
for (const auto& route : routes) {
std::set<int32_t> sources(route.sourcePortIds.begin(), route.sourcePortIds.end());
- EXPECT_NE(0, sources.size())
+ 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: "
@@ -552,10 +774,10 @@
ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
}
for (const auto& route : routes) {
- EXPECT_EQ(1, portIds.count(route.sinkPortId))
+ EXPECT_EQ(1UL, portIds.count(route.sinkPortId))
<< route.sinkPortId << " sink port id is unknown";
for (const auto& source : route.sourcePortIds) {
- EXPECT_EQ(1, portIds.count(source)) << source << " source port id is unknown";
+ EXPECT_EQ(1UL, portIds.count(source)) << source << " source port id is unknown";
}
}
}
@@ -617,7 +839,7 @@
<< "At least two output device ports are declared as default: "
<< defaultOutput.value() << " and " << port.id;
defaultOutput = port.id;
- EXPECT_EQ(0, outputs.count(devicePort.device))
+ 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) {
@@ -625,7 +847,7 @@
<< "At least two input device ports are declared as default: "
<< defaultInput.value() << " and " << port.id;
defaultInput = port.id;
- EXPECT_EQ(0, inputs.count(devicePort.device))
+ EXPECT_EQ(0UL, inputs.count(devicePort.device))
<< "Non-unique input device: " << devicePort.device.toString();
inputs.insert(devicePort.device);
} else {
@@ -712,7 +934,7 @@
<< status << " returned for getAudioPort port ID " << connectedPortId;
EXPECT_EQ(portConnected.get(), connectedPort);
const auto& portProfiles = connectedPort.profiles;
- EXPECT_NE(0, portProfiles.size())
+ 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) {
@@ -739,18 +961,24 @@
ASSERT_NO_FATAL_FAILURE(GetAllPortConfigIds(&portConfigIds));
for (const auto portConfigId : GetNonExistentIds(portConfigIds)) {
{
- std::shared_ptr<IStreamIn> stream;
- ScopedAStatus status = module->openInputStream(portConfigId, {}, &stream);
+ aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments args;
+ args.portConfigId = portConfigId;
+ args.bufferSizeFrames = kDefaultBufferSizeFrames;
+ aidl::android::hardware::audio::core::IModule::OpenInputStreamReturn ret;
+ ScopedAStatus status = module->openInputStream(args, &ret);
EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
<< status << " openInputStream returned for port config ID " << portConfigId;
- EXPECT_EQ(nullptr, stream);
+ EXPECT_EQ(nullptr, ret.stream);
}
{
- std::shared_ptr<IStreamOut> stream;
- ScopedAStatus status = module->openOutputStream(portConfigId, {}, {}, &stream);
+ aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
+ args.portConfigId = portConfigId;
+ args.bufferSizeFrames = kDefaultBufferSizeFrames;
+ aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
+ ScopedAStatus status = module->openOutputStream(args, &ret);
EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
<< status << " openOutputStream returned for port config ID " << portConfigId;
- EXPECT_EQ(nullptr, stream);
+ EXPECT_EQ(nullptr, ret.stream);
}
}
}
@@ -769,7 +997,7 @@
ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
}
for (const auto& config : portConfigs) {
- EXPECT_EQ(1, portIds.count(config.portId))
+ EXPECT_EQ(1UL, portIds.count(config.portId))
<< config.portId << " port id is unknown, config id " << config.id;
}
}
@@ -1113,14 +1341,14 @@
}
void CloseTwice() {
- const auto portConfig = moduleConfig->getSingleConfigForMixPort(IsInput<Stream>());
+ 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()));
+ ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
heldStream = stream.getSharedPointer();
}
ScopedAStatus status = heldStream->close();
@@ -1129,15 +1357,50 @@
}
void OpenAllConfigs() {
- const auto allPortConfigs = moduleConfig->getPortConfigsForMixPorts(IsInput<Stream>());
+ 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()));
+ 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()}) {
+ ScopedAStatus status = stream.SetUpNoChecks(module.get(), bufferSize);
+ EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
+ << status << " open" << direction(true) << "Stream returned for " << bufferSize
+ << " buffer size";
+ 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()));
+ ScopedAStatus status = stream.SetUpNoChecks(module.get(), kDefaultBufferSizeFrames);
+ EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
+ << status << " open" << direction(true) << "Stream returned for port config ID "
+ << stream.getPortId();
+ EXPECT_EQ(nullptr, stream.get());
+ }
+
void OpenOverMaxCount() {
- constexpr bool isInput = IsInput<Stream>();
+ constexpr bool isInput = IOTraits<Stream>::is_input;
auto ports = moduleConfig->getMixPorts(isInput);
bool hasSingleRun = false;
for (const auto& port : ports) {
@@ -1158,10 +1421,11 @@
streamWraps[i].emplace(portConfigs[i]);
WithStream<Stream>& stream = streamWraps[i].value();
if (i < maxStreamCount) {
- ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get()));
+ ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
} else {
ASSERT_NO_FATAL_FAILURE(stream.SetUpPortConfig(module.get()));
- ScopedAStatus status = stream.SetUpNoChecks(module.get());
+ ScopedAStatus status =
+ stream.SetUpNoChecks(module.get(), kDefaultBufferSizeFrames);
EXPECT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode())
<< status << " open" << direction(true)
<< "Stream returned for port config ID " << stream.getPortId()
@@ -1175,50 +1439,146 @@
}
}
- void OpenInvalidDirection() {
- // Important! The direction of the port config must be reversed.
- const auto portConfig = moduleConfig->getSingleConfigForMixPort(!IsInput<Stream>());
- 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()));
- ScopedAStatus status = stream.SetUpNoChecks(module.get());
- EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
- << status << " open" << direction(true) << "Stream returned for port config ID "
- << stream.getPortId();
- EXPECT_EQ(nullptr, stream.get());
- }
-
void OpenTwiceSamePortConfig() {
- const auto portConfig = moduleConfig->getSingleConfigForMixPort(IsInput<Stream>());
+ 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 ReadOrWrite(bool useImpl2, bool testObservablePosition) {
+ const auto allPortConfigs =
+ moduleConfig->getPortConfigsForMixPorts(IOTraits<Stream>::is_input);
+ if (allPortConfigs.empty()) {
+ GTEST_SKIP() << "No mix ports have attached devices";
+ }
+ for (const auto& portConfig : allPortConfigs) {
+ EXPECT_NO_FATAL_FAILURE(ReadOrWriteImpl(portConfig, useImpl2, testObservablePosition))
+ << portConfig.toString();
+ }
+ }
+
void ResetPortConfigWithOpenStream() {
- const auto portConfig = moduleConfig->getSingleConfigForMixPort(IsInput<Stream>());
+ 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()));
+ ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
ScopedAStatus status = module->resetAudioPortConfig(stream.getPortId());
EXPECT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode())
<< status << " returned for 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()));
+ ASSERT_NO_FATAL_FAILURE(stream1.SetUp(module.get(), kDefaultBufferSizeFrames));
WithStream<Stream> stream2;
- ScopedAStatus status = stream2.SetUpNoChecks(module.get(), stream1.getPortConfig());
+ ScopedAStatus status = stream2.SetUpNoChecks(module.get(), stream1.getPortConfig(),
+ kDefaultBufferSizeFrames);
EXPECT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode())
<< status << " when opening " << direction(false)
<< " stream twice for the same port config ID " << stream1.getPortId();
}
+
+ template <class Worker>
+ void WaitForObservablePositionAdvance(Worker& worker) {
+ static constexpr int kWriteDurationUs = 50 * 1000;
+ static constexpr std::chrono::milliseconds kPositionChangeTimeout{10000};
+ int64_t framesInitial;
+ framesInitial = worker.getLastObservablePosition().frames;
+ ASSERT_FALSE(worker.hasError());
+ bool timedOut = false;
+ int64_t frames = framesInitial;
+ for (android::base::Timer elapsed;
+ frames <= framesInitial && !worker.hasError() &&
+ !(timedOut = (elapsed.duration() >= kPositionChangeTimeout));) {
+ usleep(kWriteDurationUs);
+ frames = worker.getLastObservablePosition().frames;
+ }
+ EXPECT_FALSE(timedOut);
+ EXPECT_FALSE(worker.hasError()) << worker.getError();
+ EXPECT_GT(frames, framesInitial);
+ }
+
+ void ReadOrWriteImpl(const AudioPortConfig& portConfig, bool useImpl2,
+ bool testObservablePosition) {
+ if (!useImpl2) {
+ ASSERT_NO_FATAL_FAILURE(ReadOrWriteImpl1(portConfig, testObservablePosition));
+ } else {
+ ASSERT_NO_FATAL_FAILURE(ReadOrWriteImpl2(portConfig, testObservablePosition));
+ }
+ }
+
+ // Set up a patch first, then open a stream.
+ void ReadOrWriteImpl1(const AudioPortConfig& portConfig, bool testObservablePosition) {
+ auto devicePorts = moduleConfig->getAttachedDevicesPortsForMixPort(
+ IOTraits<Stream>::is_input, portConfig);
+ ASSERT_FALSE(devicePorts.empty());
+ auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(devicePorts[0]);
+ WithAudioPatch patch(IOTraits<Stream>::is_input, portConfig, devicePortConfig);
+ ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
+
+ WithStream<Stream> stream(patch.getPortConfig(IOTraits<Stream>::is_input));
+ ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+ typename IOTraits<Stream>::Worker worker(*stream.getContext());
+
+ ASSERT_TRUE(worker.start());
+ ASSERT_TRUE(worker.waitForAtLeastOneCycle());
+ if (testObservablePosition) {
+ ASSERT_NO_FATAL_FAILURE(WaitForObservablePositionAdvance(worker));
+ }
+ }
+
+ // Open a stream, then set up a patch for it.
+ void ReadOrWriteImpl2(const AudioPortConfig& portConfig, bool testObservablePosition) {
+ WithStream<Stream> stream(portConfig);
+ ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+ typename IOTraits<Stream>::Worker worker(*stream.getContext());
+
+ auto devicePorts = moduleConfig->getAttachedDevicesPortsForMixPort(
+ IOTraits<Stream>::is_input, portConfig);
+ ASSERT_FALSE(devicePorts.empty());
+ auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(devicePorts[0]);
+ WithAudioPatch patch(IOTraits<Stream>::is_input, stream.getPortConfig(), devicePortConfig);
+ ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
+
+ ASSERT_TRUE(worker.start());
+ ASSERT_TRUE(worker.waitForAtLeastOneCycle());
+ if (testObservablePosition) {
+ ASSERT_NO_FATAL_FAILURE(WaitForObservablePositionAdvance(worker));
+ }
+ }
+
+ void SendInvalidCommandImpl(const AudioPortConfig& portConfig) {
+ std::vector<StreamDescriptor::Command> commands(6);
+ commands[0].code = -1;
+ commands[1].code = StreamDescriptor::COMMAND_BURST - 1;
+ commands[2].code = std::numeric_limits<int32_t>::min();
+ commands[3].code = std::numeric_limits<int32_t>::max();
+ commands[4].code = StreamDescriptor::COMMAND_BURST;
+ commands[4].fmqByteCount = -1;
+ commands[5].code = StreamDescriptor::COMMAND_BURST;
+ commands[5].fmqByteCount = std::numeric_limits<int32_t>::min();
+ WithStream<Stream> stream(portConfig);
+ ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+ StreamWorker<StreamInvalidCommandLogic> writer(*stream.getContext(), commands);
+ ASSERT_TRUE(writer.start());
+ writer.waitForAtLeastOneCycle();
+ auto unexpectedStatuses = writer.getUnexpectedStatuses();
+ EXPECT_EQ(0UL, unexpectedStatuses.size())
+ << "Pairs of (command, actual status): "
+ << android::internal::ToString(unexpectedStatuses);
+ }
};
using AudioStreamIn = AudioStream<IStreamIn>;
using AudioStreamOut = AudioStream<IStreamOut>;
@@ -1235,13 +1595,26 @@
#define TEST_IO_STREAM(method_name) \
TEST_P(AudioStreamIn, method_name) { ASSERT_NO_FATAL_FAILURE(method_name()); } \
TEST_P(AudioStreamOut, method_name) { ASSERT_NO_FATAL_FAILURE(method_name()); }
+#define TEST_IO_STREAM_2(method_name, arg1, arg2) \
+ TEST_P(AudioStreamIn, method_name##_##arg1##_##arg2) { \
+ ASSERT_NO_FATAL_FAILURE(method_name(arg1, arg2)); \
+ } \
+ TEST_P(AudioStreamOut, method_name##_##arg1##_##arg2) { \
+ ASSERT_NO_FATAL_FAILURE(method_name(arg1, arg2)); \
+ }
TEST_IO_STREAM(CloseTwice);
TEST_IO_STREAM(OpenAllConfigs);
+TEST_IO_STREAM(OpenInvalidBufferSize);
TEST_IO_STREAM(OpenInvalidDirection);
TEST_IO_STREAM(OpenOverMaxCount);
TEST_IO_STREAM(OpenTwiceSamePortConfig);
+TEST_IO_STREAM_2(ReadOrWrite, false, false);
+TEST_IO_STREAM_2(ReadOrWrite, true, false);
+TEST_IO_STREAM_2(ReadOrWrite, false, true);
+TEST_IO_STREAM_2(ReadOrWrite, true, true);
TEST_IO_STREAM(ResetPortConfigWithOpenStream);
+TEST_IO_STREAM(SendInvalidCommand);
TEST_P(AudioStreamOut, OpenTwicePrimary) {
const auto mixPorts = moduleConfig->getMixPorts(false);
@@ -1277,10 +1650,14 @@
const auto portConfig = moduleConfig->getSingleConfigForMixPort(false, *offloadPortIt);
ASSERT_TRUE(portConfig.has_value())
<< "No profiles specified for the compressed offload mix port";
+ StreamDescriptor descriptor;
std::shared_ptr<IStreamOut> ignored;
- ScopedAStatus status = module->openOutputStream(portConfig.value().id,
- GenerateSourceMetadata(portConfig.value()),
- {} /* offloadInfo */, &ignored);
+ aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
+ args.portConfigId = portConfig.value().id;
+ args.sourceMetadata = GenerateSourceMetadata(portConfig.value());
+ args.bufferSizeFrames = kDefaultBufferSizeFrames;
+ aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
+ ScopedAStatus status = module->openOutputStream(args, &ret);
EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
<< status
<< " returned when no offload info is provided for a compressed offload mix port";
diff --git a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
new file mode 100644
index 0000000..f70948c
--- /dev/null
+++ b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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>
+
+#define LOG_TAG "VtsHalAudioEffect"
+
+#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"
+
+using namespace android;
+
+using ndk::ScopedAStatus;
+
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::media::audio::common::AudioUuid;
+
+namespace ndk {
+std::ostream& operator<<(std::ostream& str, const ScopedAStatus& status) {
+ str << status.getDescription();
+ return str;
+}
+} // namespace ndk
+
+class EffectFactory : public testing::TestWithParam<std::string> {
+ public:
+ void SetUp() override { ASSERT_NO_FATAL_FAILURE(ConnectToService()); }
+
+ void TearDown() override {}
+
+ void ConnectToService() {
+ serviceName = GetParam();
+ factory = IFactory::fromBinder(binderUtil.connectToService(serviceName));
+ ASSERT_NE(factory, nullptr);
+ }
+
+ void RestartService() {
+ ASSERT_NE(factory, nullptr);
+ factory = IFactory::fromBinder(binderUtil.restartService());
+ ASSERT_NE(factory, nullptr);
+ }
+
+ std::shared_ptr<IFactory> factory;
+ std::string serviceName;
+ AudioHalBinderServiceUtil binderUtil;
+ // TODO: these UUID can get from config file
+ // ec7178ec-e5e1-4432-a3f4-4657e6795210
+ const AudioUuid nullUuid = {static_cast<int32_t>(0xec7178ec),
+ 0xe5e1,
+ 0x4432,
+ 0xa3f4,
+ {0x46, 0x57, 0xe6, 0x79, 0x52, 0x10}};
+ const AudioUuid zeroUuid = {
+ static_cast<int32_t>(0x0), 0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
+};
+
+TEST_P(EffectFactory, SetupAndTearDown) {
+ // Intentionally empty test body.
+}
+
+TEST_P(EffectFactory, CanBeRestarted) {
+ ASSERT_NO_FATAL_FAILURE(RestartService());
+}
+
+TEST_P(EffectFactory, QueriedDescriptorList) {
+ std::vector<Descriptor::Identity> descriptors;
+ ScopedAStatus status = factory->queryEffects(std::nullopt, std::nullopt, &descriptors);
+ EXPECT_EQ(EX_NONE, status.getExceptionCode());
+ EXPECT_NE(static_cast<int>(descriptors.size()), 0);
+}
+
+TEST_P(EffectFactory, DescriptorUUIDNotNull) {
+ std::vector<Descriptor::Identity> descriptors;
+ ScopedAStatus status = factory->queryEffects(std::nullopt, std::nullopt, &descriptors);
+ EXPECT_EQ(EX_NONE, status.getExceptionCode());
+ // TODO: Factory eventually need to return the full list of MUST supported AOSP effects.
+ for (auto& desc : descriptors) {
+ EXPECT_NE(desc.type, zeroUuid);
+ EXPECT_NE(desc.uuid, zeroUuid);
+ }
+}
+
+TEST_P(EffectFactory, QueriedDescriptorNotExistType) {
+ std::vector<Descriptor::Identity> descriptors;
+ ScopedAStatus status = factory->queryEffects(nullUuid, std::nullopt, &descriptors);
+ EXPECT_EQ(EX_NONE, status.getExceptionCode());
+ EXPECT_EQ(static_cast<int>(descriptors.size()), 0);
+}
+
+TEST_P(EffectFactory, QueriedDescriptorNotExistInstance) {
+ std::vector<Descriptor::Identity> descriptors;
+ ScopedAStatus status = factory->queryEffects(std::nullopt, nullUuid, &descriptors);
+ EXPECT_EQ(EX_NONE, status.getExceptionCode());
+ EXPECT_EQ(static_cast<int>(descriptors.size()), 0);
+}
+
+INSTANTIATE_TEST_SUITE_P(EffectFactoryTest, EffectFactory,
+ testing::ValuesIn(android::getAidlHalInstanceNames(IFactory::descriptor)),
+ android::PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EffectFactory);
+
+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/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/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp
index ffa4c56..c808ff6 100644
--- a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp
+++ b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp
@@ -35,6 +35,7 @@
#include <common/all-versions/VersionUtils.h>
+#include <cutils/properties.h>
#include <gtest/gtest.h>
#include <hidl/GtestPrinter.h>
#include <hidl/ServiceManagement.h>
@@ -625,6 +626,10 @@
TEST_P(AudioEffectHidlTest, GetParameterInvalidMaxReplySize) {
description("Verify that GetParameter caps the maximum reply size");
+ const bool isNewDeviceLaunchingOnTPlus = property_get_int32("ro.vendor.api_level", 0) >= 33;
+ if (!isNewDeviceLaunchingOnTPlus) {
+ GTEST_SKIP() << "The test only applies to devices launching on T or later";
+ }
// Use a non-empty parameter to avoid being rejected by any earlier checks.
hidl_vec<uint8_t> parameter;
parameter.resize(16);
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/android/hardware/automotive/evs/EvsEventDesc.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/EvsEventDesc.aidl
index ebff98f..3abdb54 100644
--- a/automotive/evs/aidl/android/hardware/automotive/evs/EvsEventDesc.aidl
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/EvsEventDesc.aidl
@@ -33,7 +33,9 @@
@utf8InCpp
String deviceId;
/**
- * Possible additional vendor information that is opaque to the EvsManager
+ * Possible additional vendor information that is opaque to the EvsManager.
+ * The size of the payload must not exceed 16-byte if the HIDL recipients are
+ * expected to exist.
*/
int[] payload;
}
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/IEvsCameraStream.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/IEvsCameraStream.aidl
index 2c2b44c..c599d58 100644
--- a/automotive/evs/aidl/android/hardware/automotive/evs/IEvsCameraStream.aidl
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/IEvsCameraStream.aidl
@@ -47,7 +47,10 @@
/**
* Receives calls from the HAL each time an event happens.
*
- * @param in event EVS event with possible event information.
+ * @param in event EVS event with possible event information. If ths HIDL
+ * recipients are expected to exist, the size of the event
+ * payload must not exceed 16 bytes; otherwise, a notification
+ * will not reach them.
*/
void notify(in EvsEventDesc event);
}
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/default/Android.bp b/automotive/occupant_awareness/aidl/default/Android.bp
index 3dc7e0d..1b760a5 100644
--- a/automotive/occupant_awareness/aidl/default/Android.bp
+++ b/automotive/occupant_awareness/aidl/default/Android.bp
@@ -42,18 +42,11 @@
cc_fuzz {
name: "android.hardware.automotive.occupant_awareness-service.fuzzer",
+ defaults: ["service_fuzzer_defaults"],
static_libs: [
"android.hardware.automotive.occupant_awareness-V1-ndk",
- "libbase",
- "libbinder_random_parcel",
- "libcutils",
"liblog",
],
- shared_libs: [
- "libbinder_ndk",
- "libbinder",
- "libutils",
- ],
srcs: [
"fuzzer.cpp",
"OccupantAwareness.cpp",
diff --git a/automotive/vehicle/TEST_MAPPING b/automotive/vehicle/TEST_MAPPING
index fa0b791..da8416c 100644
--- a/automotive/vehicle/TEST_MAPPING
+++ b/automotive/vehicle/TEST_MAPPING
@@ -7,6 +7,15 @@
"name": "VehicleHalDefaultConfigTest"
},
{
+ "name": "VehicleHalDefaultConfigTestEnableTestProperties"
+ },
+ {
+ "name": "JsonConfigLoaderUnitTest"
+ },
+ {
+ "name": "JsonConfigLoaderUnitTestEnableTestProperties"
+ },
+ {
"name": "VehicleHalVehicleUtilsTest"
},
{
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/GsrComplianceRequirementType.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/GsrComplianceRequirementType.aidl
index 0d3a061..9c565ee 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/GsrComplianceRequirementType.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/GsrComplianceRequirementType.aidl
@@ -35,5 +35,5 @@
@Backing(type="int") @VintfStability
enum GsrComplianceRequirementType {
GSR_COMPLIANCE_NOT_REQUIRED = 0,
- GSR_COMPLIANCE_REQUIRED_THROUGH_SYSTEM_IMAGE = 1,
+ GSR_COMPLIANCE_REQUIRED_V1 = 1,
}
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/GsrComplianceRequirementType.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/GsrComplianceRequirementType.aidl
index e0609d5..fb3ca9f 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/GsrComplianceRequirementType.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/GsrComplianceRequirementType.aidl
@@ -27,8 +27,9 @@
* GSR compliance is not required.
*/
GSR_COMPLIANCE_NOT_REQUIRED = 0,
+
/**
- * GSR compliance is required through system image.
+ * GSR compliance is required and the requirement solution version is 1.
*/
- GSR_COMPLIANCE_REQUIRED_THROUGH_SYSTEM_IMAGE = 1,
+ GSR_COMPLIANCE_REQUIRED_V1 = 1,
}
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl
index e8a6c85..1cf8aff 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl
@@ -542,7 +542,7 @@
*/
TRACTION_CONTROL_ACTIVE = 0x040B + 0x10000000 + 0x01000000
+ 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BOOLEAN
- /*
+ /**
* HVAC Properties
*
* Additional rules for mapping a zoned HVAC property (except
diff --git a/automotive/vehicle/aidl/impl/default_config/Android.bp b/automotive/vehicle/aidl/impl/default_config/Android.bp
deleted file mode 100644
index 0feaf23..0000000
--- a/automotive/vehicle/aidl/impl/default_config/Android.bp
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package {
- default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-cc_library_headers {
- name: "VehicleHalDefaultConfig",
- vendor: true,
- local_include_dirs: ["include"],
- export_include_dirs: ["include"],
- defaults: ["VehicleHalDefaults"],
- static_libs: ["VehicleHalUtils"],
- header_libs: ["VehicleHalTestUtilHeaders"],
- export_static_lib_headers: ["VehicleHalUtils"],
- export_header_lib_headers: ["VehicleHalTestUtilHeaders"],
-}
diff --git a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/Android.bp b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/Android.bp
new file mode 100644
index 0000000..6984d5e
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/Android.bp
@@ -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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_library {
+ name: "VehicleHalJsonConfigLoader",
+ vendor: true,
+ srcs: ["src/*.cpp"],
+ local_include_dirs: ["include"],
+ export_include_dirs: ["include"],
+ defaults: ["VehicleHalDefaults"],
+ static_libs: ["VehicleHalUtils"],
+ header_libs: [
+ "IVehicleGeneratedHeaders",
+ ],
+ shared_libs: ["libjsoncpp"],
+}
+
+cc_library {
+ name: "VehicleHalJsonConfigLoaderEnableTestProperties",
+ vendor: true,
+ srcs: ["src/*.cpp"],
+ local_include_dirs: ["include"],
+ export_include_dirs: ["include"],
+ defaults: ["VehicleHalDefaults"],
+ static_libs: ["VehicleHalUtils"],
+ header_libs: [
+ "VehicleHalTestUtilHeaders",
+ "IVehicleGeneratedHeaders",
+ ],
+ cflags: ["-DENABLE_VEHICLE_HAL_TEST_PROPERTIES"],
+ shared_libs: ["libjsoncpp"],
+}
+
+cc_library_headers {
+ name: "VehicleHalJsonConfigLoaderHeaders",
+ vendor: true,
+ local_include_dirs: ["include"],
+ export_include_dirs: ["include"],
+ defaults: ["VehicleHalDefaults"],
+ static_libs: ["VehicleHalUtils"],
+ header_libs: [
+ "IVehicleGeneratedHeaders",
+ ],
+ shared_libs: ["libjsoncpp"],
+}
diff --git a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/include/ConfigDeclaration.h b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/include/ConfigDeclaration.h
new file mode 100644
index 0000000..40ac129
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/include/ConfigDeclaration.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef android_hardware_automotive_vehicle_aidl_impl_default_config_JsonConfigLoader_include_ConfigDeclaration_H_
+#define android_hardware_automotive_vehicle_aidl_impl_default_config_JsonConfigLoader_include_ConfigDeclaration_H_
+
+#include <VehicleHalTypes.h>
+
+#include <unordered_map>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+
+// ConfigDeclaration represents one property config, its optional initial value and its optional
+// area configs and initial values for each area.
+struct ConfigDeclaration {
+ aidl::android::hardware::automotive::vehicle::VehiclePropConfig config;
+
+ // This value will be used as an initial value for the property. If this field is specified for
+ // property that supports multiple areas then it will be used for all areas unless particular
+ // area is overridden in initialAreaValue field.
+ aidl::android::hardware::automotive::vehicle::RawPropValues initialValue;
+ // Use initialAreaValues if it is necessary to specify different values per each area.
+ std::unordered_map<int32_t, aidl::android::hardware::automotive::vehicle::RawPropValues>
+ initialAreaValues;
+
+ inline bool operator==(const ConfigDeclaration& other) const {
+ return (config == other.config && initialValue == other.initialValue &&
+ initialAreaValues == other.initialAreaValues);
+ }
+
+ friend std::ostream& operator<<(std::ostream& os, const ConfigDeclaration& c) {
+ return os << "Config Declaration for property: "
+ << aidl::android::hardware::automotive::vehicle::toString(
+ static_cast<
+ aidl::android::hardware::automotive::vehicle::VehicleProperty>(
+ c.config.prop));
+ }
+};
+
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_automotive_vehicle_aidl_impl_default_config_JsonConfigLoader_include_ConfigDeclaration_H_
diff --git a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/include/JsonConfigLoader.h b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/include/JsonConfigLoader.h
new file mode 100644
index 0000000..f3bdbd2
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/include/JsonConfigLoader.h
@@ -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.
+ */
+
+#ifndef android_hardware_automotive_vehicle_aidl_impl_default_config_JsonConfigLoader_include_JsonConfigLoader_H_
+#define android_hardware_automotive_vehicle_aidl_impl_default_config_JsonConfigLoader_include_JsonConfigLoader_H_
+
+#include <ConfigDeclaration.h>
+#include <VehicleHalTypes.h>
+
+#include <android-base/result.h>
+#include <json/json.h>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+
+// private namespace
+namespace jsonconfigloader_impl {
+
+// An abstract interface that represents a ValueParser for any constant value types.
+class ConstantParserInterface {
+ public:
+ // Parses a constant variable name to its actual value.
+ virtual android::base::Result<int> parseValue(const std::string& name) const = 0;
+ virtual ~ConstantParserInterface() = default;
+};
+
+// A class to parse a value field in JSON config file.
+// If the field is a string and the field is in the format of "XX::XX", the value will be parsed
+// as a constant value in the format of "TYPE::NAME". Otherwise, the field will be return as is
+// converted to the expected type.
+class JsonValueParser final {
+ public:
+ JsonValueParser();
+
+ android::base::Result<std::string> parseStringValue(const std::string& fieldName,
+ const Json::Value& value) const;
+
+ template <class T>
+ android::base::Result<std::vector<T>> parseArray(const std::string& fieldName,
+ const Json::Value& value) const;
+
+ template <class T>
+ android::base::Result<T> parseValue(const std::string& fieldName,
+ const Json::Value& value) const;
+
+ private:
+ template <class T>
+ static android::base::Result<T> convertValueToType(const std::string& fieldName,
+ const Json::Value& value);
+
+ std::optional<std::pair<std::string, std::string>> maybeGetTypeAndValueName(
+ const std::string& jsonFieldValue) const;
+
+ android::base::Result<int> parseConstantValue(
+ const std::pair<std::string, std::string>& typeValueName) const;
+
+ const ConstantParserInterface* getParser(const std::string& type) const {
+ auto it = mConstantParsersByType.find(type);
+ if (it == mConstantParsersByType.end()) {
+ return nullptr;
+ }
+ return it->second.get();
+ }
+
+ private:
+ inline static const std::string DELIMITER = "::";
+ std::unordered_map<std::string, std::unique_ptr<ConstantParserInterface>>
+ mConstantParsersByType;
+};
+
+// The main class to parse a VHAL config file in JSON format.
+class JsonConfigParser {
+ public:
+ android::base::Result<std::unordered_map<int32_t, ConfigDeclaration>> parseJsonConfig(
+ std::istream& is);
+
+ private:
+ JsonValueParser mValueParser;
+
+ // Parses configuration for each property.
+ std::optional<ConfigDeclaration> parseEachProperty(const Json::Value& propJsonValue,
+ std::vector<std::string>* errors);
+ // Tries to parse a JSON value to a specific type.
+ //
+ // If fieldIsOptional is True, then if the field specified by "fieldName" does not exist,
+ // this method will return true without doing anything, otherwise, it will return false.
+ //
+ // @param parentJsonNode The parent node of the field you are going to parse.
+ // @param fieldName The name for the field.
+ // @param fieldIsOptional Whether the field is optional.
+ // @param outPtr The pointer to output to if the field exists and parsing succeeded.
+ // @param errors The error array to append error to if errors are found.
+ // @return true if the field is optional and does not exist or parsed successfully.
+ template <class T>
+ bool tryParseJsonValueToVariable(const Json::Value& parentJsonNode,
+ const std::string& fieldName, bool fieldIsOptional, T* outPtr,
+ std::vector<std::string>* errors);
+ // Tries to parse a JSON value to an array of specific type.
+ //
+ // If fieldIsOptional is True, then if the field specified by "fieldName" does not exist,
+ // this method will return true without doing anything, otherwise, it will return false.
+ //
+ // @param parentJsonNode The parent node of the field you are going to parse.
+ // @param fieldName The name for the field.
+ // @param fieldIsOptional Whether the field is optional.
+ // @param outPtr The pointer to output to if the field exists and parsing succeeded.
+ // @param errors The error array to append error to if errors are found.
+ // @return true if the field is optional and does not exist or parsed successfully.
+ template <class T>
+ bool tryParseJsonArrayToVariable(const Json::Value& parentJsonNode,
+ const std::string& fieldName, bool fieldIsOptional,
+ std::vector<T>* outPtr, std::vector<std::string>* errors);
+ // Parses a JSON field to VehiclePropertyAccess or VehiclePropertyChangeMode.
+ template <class T>
+ void parseAccessChangeMode(
+ const Json::Value& parentJsonNode, const std::string& fieldName, int propId,
+ const std::string& propStr,
+ const std::unordered_map<aidl::android::hardware::automotive::vehicle::VehicleProperty,
+ T>& defaultMap,
+ T* outPtr, std::vector<std::string>* errors);
+
+ // Parses a JSON field to RawPropValues.
+ //
+ // @return True if the field exist and can be parsed to a RawPropValues.
+ bool parsePropValues(const Json::Value& parentJsonNode, const std::string& fieldName,
+ aidl::android::hardware::automotive::vehicle::RawPropValues* outPtr,
+ std::vector<std::string>* errors);
+
+ // Prase a JSON field as an array of area configs.
+ void parseAreas(const Json::Value& parentJsonNode, const std::string& fieldName,
+ ConfigDeclaration* outPtr, std::vector<std::string>* errors);
+};
+
+} // namespace jsonconfigloader_impl
+
+// A class to load vehicle property configs and initial values in JSON format.
+class JsonConfigLoader final {
+ public:
+ JsonConfigLoader();
+
+ // Loads a JSON file stream and parses it to a map from propId to ConfigDeclarations.
+ android::base::Result<std::unordered_map<int32_t, ConfigDeclaration>> loadPropConfig(
+ std::istream& is);
+
+ // Loads a JSON config file and parses it to a map from propId to ConfigDeclarations.
+ android::base::Result<std::unordered_map<int32_t, ConfigDeclaration>> loadPropConfig(
+ const std::string& configPath);
+
+ private:
+ std::unique_ptr<jsonconfigloader_impl::JsonConfigParser> mParser;
+};
+
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_automotive_vehicle_aidl_impl_default_config_JsonConfigLoader_include_JsonConfigLoader_H_
diff --git a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp
new file mode 100644
index 0000000..e6b7d14
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp
@@ -0,0 +1,565 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <JsonConfigLoader.h>
+
+#include <AccessForVehicleProperty.h>
+#include <ChangeModeForVehicleProperty.h>
+#include <PropertyUtils.h>
+
+#ifdef ENABLE_VEHICLE_HAL_TEST_PROPERTIES
+#include <TestPropertyUtils.h>
+#endif // ENABLE_VEHICLE_HAL_TEST_PROPERTIES
+
+#include <android-base/strings.h>
+#include <fstream>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+
+namespace jsonconfigloader_impl {
+
+using ::aidl::android::hardware::automotive::vehicle::AccessForVehicleProperty;
+using ::aidl::android::hardware::automotive::vehicle::ChangeModeForVehicleProperty;
+using ::aidl::android::hardware::automotive::vehicle::EvConnectorType;
+using ::aidl::android::hardware::automotive::vehicle::EvsServiceState;
+using ::aidl::android::hardware::automotive::vehicle::EvsServiceType;
+using ::aidl::android::hardware::automotive::vehicle::FuelType;
+using ::aidl::android::hardware::automotive::vehicle::GsrComplianceRequirementType;
+using ::aidl::android::hardware::automotive::vehicle::RawPropValues;
+using ::aidl::android::hardware::automotive::vehicle::VehicleApPowerStateReport;
+using ::aidl::android::hardware::automotive::vehicle::VehicleApPowerStateReq;
+using ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig;
+using ::aidl::android::hardware::automotive::vehicle::VehicleAreaMirror;
+using ::aidl::android::hardware::automotive::vehicle::VehicleAreaWindow;
+using ::aidl::android::hardware::automotive::vehicle::VehicleGear;
+using ::aidl::android::hardware::automotive::vehicle::VehicleHvacFanDirection;
+using ::aidl::android::hardware::automotive::vehicle::VehicleIgnitionState;
+using ::aidl::android::hardware::automotive::vehicle::VehicleOilLevel;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
+using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyAccess;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyChangeMode;
+using ::aidl::android::hardware::automotive::vehicle::VehicleSeatOccupancyState;
+using ::aidl::android::hardware::automotive::vehicle::VehicleTurnSignal;
+using ::aidl::android::hardware::automotive::vehicle::VehicleUnit;
+using ::aidl::android::hardware::automotive::vehicle::VehicleVendorPermission;
+
+using ::android::base::Error;
+using ::android::base::Result;
+
+// Defines a map from constant names to constant values, the values defined here corresponds to
+// the "Constants::XXXX" used in JSON config file.
+const std::unordered_map<std::string, int> CONSTANTS_BY_NAME = {
+ {"DOOR_1_RIGHT", DOOR_1_RIGHT},
+ {"DOOR_1_LEFT", DOOR_1_LEFT},
+ {"DOOR_2_RIGHT", DOOR_2_RIGHT},
+ {"DOOR_2_LEFT", DOOR_2_LEFT},
+ {"DOOR_REAR", DOOR_REAR},
+ {"HVAC_ALL", HVAC_ALL},
+ {"HVAC_LEFT", HVAC_LEFT},
+ {"HVAC_RIGHT", HVAC_RIGHT},
+ {"VENDOR_EXTENSION_INT_PROPERTY", VENDOR_EXTENSION_INT_PROPERTY},
+ {"VENDOR_EXTENSION_BOOLEAN_PROPERTY", VENDOR_EXTENSION_BOOLEAN_PROPERTY},
+ {"VENDOR_EXTENSION_STRING_PROPERTY", VENDOR_EXTENSION_STRING_PROPERTY},
+ {"VENDOR_EXTENSION_FLOAT_PROPERTY", VENDOR_EXTENSION_FLOAT_PROPERTY},
+ {"WINDOW_1_LEFT", WINDOW_1_LEFT},
+ {"WINDOW_1_RIGHT", WINDOW_1_RIGHT},
+ {"WINDOW_2_LEFT", WINDOW_2_LEFT},
+ {"WINDOW_2_RIGHT", WINDOW_2_RIGHT},
+ {"WINDOW_ROOF_TOP_1", WINDOW_ROOF_TOP_1},
+ {"WINDOW_1_RIGHT_2_LEFT_2_RIGHT", WINDOW_1_RIGHT | WINDOW_2_LEFT | WINDOW_2_RIGHT},
+ {"SEAT_1_LEFT", SEAT_1_LEFT},
+ {"SEAT_1_RIGHT", SEAT_1_RIGHT},
+ {"SEAT_2_LEFT", SEAT_2_LEFT},
+ {"SEAT_2_RIGHT", SEAT_2_RIGHT},
+ {"SEAT_2_CENTER", SEAT_2_CENTER},
+ {"WHEEL_REAR_RIGHT", WHEEL_REAR_RIGHT},
+ {"WHEEL_REAR_LEFT", WHEEL_REAR_LEFT},
+ {"WHEEL_FRONT_RIGHT", WHEEL_FRONT_RIGHT},
+ {"WHEEL_FRONT_LEFT", WHEEL_FRONT_LEFT},
+ {"CHARGE_PORT_FRONT_LEFT", CHARGE_PORT_FRONT_LEFT},
+ {"CHARGE_PORT_REAR_LEFT", CHARGE_PORT_REAR_LEFT},
+ {"FAN_DIRECTION_FLOOR", FAN_DIRECTION_FLOOR},
+ {"FAN_DIRECTION_FACE", FAN_DIRECTION_FACE},
+ {"FAN_DIRECTION_DEFROST", FAN_DIRECTION_DEFROST},
+ {"FAN_DIRECTION_FACE_FLOOR", FAN_DIRECTION_FACE | FAN_DIRECTION_FLOOR},
+ {"FAN_DIRECTION_FACE_DEFROST", FAN_DIRECTION_FACE | FAN_DIRECTION_DEFROST},
+ {"FAN_DIRECTION_FLOOR_DEFROST", FAN_DIRECTION_FLOOR | FAN_DIRECTION_DEFROST},
+ {"FAN_DIRECTION_FLOOR_DEFROST_FACE",
+ FAN_DIRECTION_FLOOR | FAN_DIRECTION_DEFROST | FAN_DIRECTION_FACE},
+ {"FUEL_DOOR_REAR_LEFT", FUEL_DOOR_REAR_LEFT},
+ {"LIGHT_STATE_ON", LIGHT_STATE_ON},
+ {"LIGHT_SWITCH_AUTO", LIGHT_SWITCH_AUTO},
+ {"MIRROR_DRIVER_LEFT_RIGHT",
+ toInt(VehicleAreaMirror::DRIVER_LEFT) | toInt(VehicleAreaMirror::DRIVER_RIGHT)},
+#ifdef ENABLE_VEHICLE_HAL_TEST_PROPERTIES
+ // Following are test properties:
+ {"ECHO_REVERSE_BYTES", ECHO_REVERSE_BYTES},
+ {"kMixedTypePropertyForTest", kMixedTypePropertyForTest},
+ {"VENDOR_CLUSTER_NAVIGATION_STATE", VENDOR_CLUSTER_NAVIGATION_STATE},
+ {"VENDOR_CLUSTER_REQUEST_DISPLAY", VENDOR_CLUSTER_REQUEST_DISPLAY},
+ {"VENDOR_CLUSTER_SWITCH_UI", VENDOR_CLUSTER_SWITCH_UI},
+ {"VENDOR_CLUSTER_DISPLAY_STATE", VENDOR_CLUSTER_DISPLAY_STATE},
+ {"VENDOR_CLUSTER_REPORT_STATE", VENDOR_CLUSTER_REPORT_STATE},
+ {"PLACEHOLDER_PROPERTY_INT", PLACEHOLDER_PROPERTY_INT},
+ {"PLACEHOLDER_PROPERTY_FLOAT", PLACEHOLDER_PROPERTY_FLOAT},
+ {"PLACEHOLDER_PROPERTY_BOOLEAN", PLACEHOLDER_PROPERTY_BOOLEAN},
+ {"PLACEHOLDER_PROPERTY_STRING", PLACEHOLDER_PROPERTY_STRING}
+#endif // ENABLE_VEHICLE_HAL_TEST_PROPERTIES
+};
+
+// A class to parse constant values for type T.
+template <class T>
+class ConstantParser final : public ConstantParserInterface {
+ public:
+ ConstantParser() {
+ for (const T& v : ndk::enum_range<T>()) {
+ std::string name = aidl::android::hardware::automotive::vehicle::toString(v);
+ // We use the same constant for both VehicleUnit::GALLON and VehicleUnit::US_GALLON,
+ // which caused toString() not work properly for US_GALLON. So we explicitly add the
+ // map here.
+ if (name == "GALLON") {
+ mValueByName["US_GALLON"] = toInt(v);
+ }
+ mValueByName[name] = toInt(v);
+ }
+ }
+
+ ~ConstantParser() = default;
+
+ Result<int> parseValue(const std::string& name) const override {
+ auto it = mValueByName.find(name);
+ if (it == mValueByName.end()) {
+ return Error() << "Constant name: " << name << " is not defined";
+ }
+ return it->second;
+ }
+
+ private:
+ std::unordered_map<std::string, int> mValueByName;
+};
+
+// A class to parse constant values defined in CONSTANTS_BY_NAME map.
+class LocalVariableParser final : public ConstantParserInterface {
+ public:
+ ~LocalVariableParser() = default;
+
+ Result<int> parseValue(const std::string& name) const override {
+ auto constantsIt = CONSTANTS_BY_NAME.find(name);
+ if (constantsIt == CONSTANTS_BY_NAME.end()) {
+ return Error() << "Constant variable name: " << name << " is not defined";
+ }
+ return constantsIt->second;
+ }
+};
+
+JsonValueParser::JsonValueParser() {
+ mConstantParsersByType["VehiclePropertyAccess"] =
+ std::make_unique<ConstantParser<VehiclePropertyAccess>>();
+ mConstantParsersByType["VehiclePropertyChangeMode"] =
+ std::make_unique<ConstantParser<VehiclePropertyChangeMode>>();
+ mConstantParsersByType["VehicleGear"] = std::make_unique<ConstantParser<VehicleGear>>();
+ mConstantParsersByType["VehicleAreaWindow"] =
+ std::make_unique<ConstantParser<VehicleAreaWindow>>();
+ mConstantParsersByType["VehicleAreaMirror"] =
+ std::make_unique<ConstantParser<VehicleAreaMirror>>();
+ mConstantParsersByType["VehicleOilLevel"] = std::make_unique<ConstantParser<VehicleOilLevel>>();
+ mConstantParsersByType["VehicleUnit"] = std::make_unique<ConstantParser<VehicleUnit>>();
+ mConstantParsersByType["VehicleSeatOccupancyState"] =
+ std::make_unique<ConstantParser<VehicleSeatOccupancyState>>();
+ mConstantParsersByType["VehicleHvacFanDirection"] =
+ std::make_unique<ConstantParser<VehicleHvacFanDirection>>();
+ mConstantParsersByType["VehicleApPowerStateReport"] =
+ std::make_unique<ConstantParser<VehicleApPowerStateReport>>();
+ mConstantParsersByType["VehicleTurnSignal"] =
+ std::make_unique<ConstantParser<VehicleTurnSignal>>();
+ mConstantParsersByType["VehicleVendorPermission"] =
+ std::make_unique<ConstantParser<VehicleVendorPermission>>();
+ mConstantParsersByType["EvsServiceType"] = std::make_unique<ConstantParser<EvsServiceType>>();
+ mConstantParsersByType["EvsServiceState"] = std::make_unique<ConstantParser<EvsServiceState>>();
+ mConstantParsersByType["EvConnectorType"] = std::make_unique<ConstantParser<EvConnectorType>>();
+ mConstantParsersByType["VehicleProperty"] = std::make_unique<ConstantParser<VehicleProperty>>();
+ mConstantParsersByType["GsrComplianceRequirementType"] =
+ std::make_unique<ConstantParser<GsrComplianceRequirementType>>();
+ mConstantParsersByType["VehicleIgnitionState"] =
+ std::make_unique<ConstantParser<VehicleIgnitionState>>();
+ mConstantParsersByType["FuelType"] = std::make_unique<ConstantParser<FuelType>>();
+ mConstantParsersByType["Constants"] = std::make_unique<LocalVariableParser>();
+}
+
+template <>
+Result<int32_t> JsonValueParser::convertValueToType<int32_t>(const std::string& fieldName,
+ const Json::Value& value) {
+ if (!value.isInt()) {
+ return Error() << "The value: " << value << " for field: " << fieldName
+ << " is not in correct type, expect int";
+ }
+ return static_cast<int32_t>(value.asInt());
+}
+
+template <>
+Result<float> JsonValueParser::convertValueToType<float>(const std::string& fieldName,
+ const Json::Value& value) {
+ // isFloat value does not exist, so we use isDouble here.
+ if (!value.isDouble()) {
+ return Error() << "The value: " << value << " for field: " << fieldName
+ << " is not in correct type, expect float";
+ }
+ return value.asFloat();
+}
+
+template <>
+Result<int64_t> JsonValueParser::convertValueToType<int64_t>(const std::string& fieldName,
+ const Json::Value& value) {
+ if (!value.isInt64()) {
+ return Error() << "The value: " << value << " for field: " << fieldName
+ << " is not in correct type, expect int64";
+ }
+ return static_cast<int64_t>(value.asInt64());
+}
+
+template <>
+Result<std::string> JsonValueParser::convertValueToType<std::string>(const std::string& fieldName,
+ const Json::Value& value) {
+ if (!value.isString()) {
+ return Error() << "The value: " << value << " for field: " << fieldName
+ << " is not in correct type, expect string";
+ }
+ return value.asString();
+}
+
+Result<std::string> JsonValueParser::parseStringValue(const std::string& fieldName,
+ const Json::Value& value) const {
+ return convertValueToType<std::string>(fieldName, value);
+}
+
+template <class T>
+Result<T> JsonValueParser::parseValue(const std::string& fieldName,
+ const Json::Value& value) const {
+ if (!value.isString()) {
+ return convertValueToType<T>(fieldName, value);
+ }
+ auto maybeTypeAndValue = maybeGetTypeAndValueName(value.asString());
+ if (!maybeTypeAndValue.has_value()) {
+ return Error() << "Invalid constant value: " << value << " for field: " << fieldName;
+ }
+ auto constantParseResult = parseConstantValue(maybeTypeAndValue.value());
+ if (!constantParseResult.ok()) {
+ return constantParseResult.error();
+ }
+ int constantValue = constantParseResult.value();
+ return static_cast<T>(constantValue);
+}
+
+template <>
+Result<std::string> JsonValueParser::parseValue<std::string>(const std::string& fieldName,
+ const Json::Value& value) const {
+ return parseStringValue(fieldName, value);
+}
+
+template <class T>
+Result<std::vector<T>> JsonValueParser::parseArray(const std::string& fieldName,
+ const Json::Value& value) const {
+ if (!value.isArray()) {
+ return Error() << "The value: " << value << " for field: " << fieldName
+ << " is not in correct type, expect array";
+ }
+ std::vector<T> parsedValues;
+ for (unsigned int i = 0; i < value.size(); i++) {
+ auto result = parseValue<T>(fieldName, value[i]);
+ if (!result.ok()) {
+ return result.error();
+ }
+ parsedValues.push_back(result.value());
+ }
+ return std::move(parsedValues);
+}
+
+std::optional<std::pair<std::string, std::string>> JsonValueParser::maybeGetTypeAndValueName(
+ const std::string& jsonFieldValue) const {
+ size_t pos = jsonFieldValue.find(DELIMITER);
+ if (pos == std::string::npos) {
+ return {};
+ }
+ std::string type = jsonFieldValue.substr(0, pos);
+ std::string valueName = jsonFieldValue.substr(pos + DELIMITER.length(), std::string::npos);
+ if (type != "Constants" && mConstantParsersByType.find(type) == mConstantParsersByType.end()) {
+ return {};
+ }
+ return std::make_pair(type, valueName);
+}
+
+Result<int> JsonValueParser::parseConstantValue(
+ const std::pair<std::string, std::string>& typeValueName) const {
+ const std::string& type = typeValueName.first;
+ const std::string& valueName = typeValueName.second;
+ auto it = mConstantParsersByType.find(type);
+ if (it == mConstantParsersByType.end()) {
+ return Error() << "Unrecognized type: " << type;
+ }
+ auto result = it->second->parseValue(valueName);
+ if (!result.ok()) {
+ return Error() << type << "::" << valueName << " undefined";
+ }
+ return result;
+}
+
+template <class T>
+bool JsonConfigParser::tryParseJsonValueToVariable(const Json::Value& parentJsonNode,
+ const std::string& fieldName,
+ bool fieldIsOptional, T* outPtr,
+ std::vector<std::string>* errors) {
+ if (!parentJsonNode.isObject()) {
+ errors->push_back("Node: " + parentJsonNode.toStyledString() + " is not an object");
+ return false;
+ }
+ if (!parentJsonNode.isMember(fieldName)) {
+ if (!fieldIsOptional) {
+ errors->push_back("Missing required field: " + fieldName +
+ " in node: " + parentJsonNode.toStyledString());
+ return false;
+ }
+ return true;
+ }
+ auto result = mValueParser.parseValue<T>(fieldName, parentJsonNode[fieldName]);
+ if (!result.ok()) {
+ errors->push_back(result.error().message());
+ return false;
+ }
+ *outPtr = std::move(result.value());
+ return true;
+}
+
+template <class T>
+bool JsonConfigParser::tryParseJsonArrayToVariable(const Json::Value& parentJsonNode,
+ const std::string& fieldName,
+ bool fieldIsOptional, std::vector<T>* outPtr,
+ std::vector<std::string>* errors) {
+ if (!parentJsonNode.isObject()) {
+ errors->push_back("Node: " + parentJsonNode.toStyledString() + " is not an object");
+ return false;
+ }
+ if (!parentJsonNode.isMember(fieldName)) {
+ if (!fieldIsOptional) {
+ errors->push_back("Missing required field: " + fieldName +
+ " in node: " + parentJsonNode.toStyledString());
+ return false;
+ }
+ return true;
+ }
+ auto result = mValueParser.parseArray<T>(fieldName, parentJsonNode[fieldName]);
+ if (!result.ok()) {
+ errors->push_back(result.error().message());
+ return false;
+ }
+ *outPtr = std::move(result.value());
+ return true;
+}
+
+template <class T>
+void JsonConfigParser::parseAccessChangeMode(
+ const Json::Value& parentJsonNode, const std::string& fieldName, int propId,
+ const std::string& propStr, const std::unordered_map<VehicleProperty, T>& defaultMap,
+ T* outPtr, std::vector<std::string>* errors) {
+ if (!parentJsonNode.isObject()) {
+ errors->push_back("Node: " + parentJsonNode.toStyledString() + " is not an object");
+ return;
+ }
+ if (parentJsonNode.isMember(fieldName)) {
+ auto result = mValueParser.parseValue<int32_t>(fieldName, parentJsonNode[fieldName]);
+ if (!result.ok()) {
+ errors->push_back(result.error().message());
+ return;
+ }
+ *outPtr = static_cast<T>(result.value());
+ return;
+ }
+ auto it = defaultMap.find(static_cast<VehicleProperty>(propId));
+ if (it == defaultMap.end()) {
+ errors->push_back("No " + fieldName + " specified for property: " + propStr);
+ return;
+ }
+ *outPtr = it->second;
+ return;
+}
+
+bool JsonConfigParser::parsePropValues(const Json::Value& parentJsonNode,
+ const std::string& fieldName, RawPropValues* outPtr,
+ std::vector<std::string>* errors) {
+ if (!parentJsonNode.isObject()) {
+ errors->push_back("Node: " + parentJsonNode.toStyledString() + " is not an object");
+ return false;
+ }
+ if (!parentJsonNode.isMember(fieldName)) {
+ return false;
+ }
+ const Json::Value& jsonValue = parentJsonNode[fieldName];
+ bool success = true;
+ success &= tryParseJsonArrayToVariable(jsonValue, "int32Values",
+ /*optional=*/true, &(outPtr->int32Values), errors);
+ success &= tryParseJsonArrayToVariable(jsonValue, "floatValues",
+ /*optional=*/true, &(outPtr->floatValues), errors);
+ success &= tryParseJsonArrayToVariable(jsonValue, "int64Values",
+ /*optional=*/true, &(outPtr->int64Values), errors);
+ // We don't support "byteValues" yet.
+ success &= tryParseJsonValueToVariable(jsonValue, "stringValue",
+ /*optional=*/true, &(outPtr->stringValue), errors);
+ return success;
+}
+
+void JsonConfigParser::parseAreas(const Json::Value& parentJsonNode, const std::string& fieldName,
+ ConfigDeclaration* config, std::vector<std::string>* errors) {
+ if (!parentJsonNode.isObject()) {
+ errors->push_back("Node: " + parentJsonNode.toStyledString() + " is not an object");
+ return;
+ }
+ if (!parentJsonNode.isMember(fieldName)) {
+ return;
+ }
+ const Json::Value& jsonValue = parentJsonNode[fieldName];
+
+ if (!jsonValue.isArray()) {
+ errors->push_back("Field: " + fieldName + " is not an array");
+ return;
+ }
+ for (unsigned int i = 0; i < jsonValue.size(); i++) {
+ int32_t areaId;
+ const Json::Value& jsonAreaConfig = jsonValue[i];
+ if (!tryParseJsonValueToVariable(jsonAreaConfig, "areaId",
+ /*optional=*/false, &areaId, errors)) {
+ continue;
+ }
+ VehicleAreaConfig areaConfig = {};
+ areaConfig.areaId = areaId;
+ tryParseJsonValueToVariable(jsonAreaConfig, "minInt32Value", /*optional=*/true,
+ &areaConfig.minInt32Value, errors);
+ tryParseJsonValueToVariable(jsonAreaConfig, "maxInt32Value", /*optional=*/true,
+ &areaConfig.maxInt32Value, errors);
+ tryParseJsonValueToVariable(jsonAreaConfig, "minInt64Value", /*optional=*/true,
+ &areaConfig.minInt64Value, errors);
+ tryParseJsonValueToVariable(jsonAreaConfig, "maxInt64Value", /*optional=*/true,
+ &areaConfig.maxInt64Value, errors);
+ tryParseJsonValueToVariable(jsonAreaConfig, "minFloatValue", /*optional=*/true,
+ &areaConfig.minFloatValue, errors);
+ tryParseJsonValueToVariable(jsonAreaConfig, "maxFloatValue", /*optional=*/true,
+ &areaConfig.maxFloatValue, errors);
+ config->config.areaConfigs.push_back(std::move(areaConfig));
+
+ RawPropValues areaValue = {};
+ if (parsePropValues(jsonAreaConfig, "defaultValue", &areaValue, errors)) {
+ config->initialAreaValues[areaId] = std::move(areaValue);
+ }
+ }
+}
+
+std::optional<ConfigDeclaration> JsonConfigParser::parseEachProperty(
+ const Json::Value& propJsonValue, std::vector<std::string>* errors) {
+ size_t initialErrorCount = errors->size();
+ ConfigDeclaration configDecl = {};
+ int32_t propId;
+
+ if (!tryParseJsonValueToVariable(propJsonValue, "property", /*optional=*/false, &propId,
+ errors)) {
+ return std::nullopt;
+ }
+
+ configDecl.config.prop = propId;
+ std::string propStr = propJsonValue["property"].toStyledString();
+
+ parseAccessChangeMode(propJsonValue, "access", propId, propStr, AccessForVehicleProperty,
+ &configDecl.config.access, errors);
+
+ parseAccessChangeMode(propJsonValue, "changeMode", propId, propStr,
+ ChangeModeForVehicleProperty, &configDecl.config.changeMode, errors);
+
+ tryParseJsonValueToVariable(propJsonValue, "configString", /*optional=*/true,
+ &configDecl.config.configString, errors);
+
+ tryParseJsonArrayToVariable(propJsonValue, "configArray", /*optional=*/true,
+ &configDecl.config.configArray, errors);
+
+ parsePropValues(propJsonValue, "defaultValue", &configDecl.initialValue, errors);
+
+ tryParseJsonValueToVariable(propJsonValue, "minSampleRate", /*optional=*/true,
+ &configDecl.config.minSampleRate, errors);
+
+ tryParseJsonValueToVariable(propJsonValue, "maxSampleRate", /*optional=*/true,
+ &configDecl.config.maxSampleRate, errors);
+
+ parseAreas(propJsonValue, "areas", &configDecl, errors);
+
+ if (errors->size() != initialErrorCount) {
+ return std::nullopt;
+ }
+ return configDecl;
+}
+
+Result<std::unordered_map<int32_t, ConfigDeclaration>> JsonConfigParser::parseJsonConfig(
+ std::istream& is) {
+ Json::CharReaderBuilder builder;
+ Json::Value root;
+ std::unordered_map<int32_t, ConfigDeclaration> configsByPropId;
+ std::string errs;
+ if (!Json::parseFromStream(builder, is, &root, &errs)) {
+ return Error() << "Failed to parse property config file as JSON, error: " << errs;
+ }
+ if (!root.isObject()) {
+ return Error() << "root element must be an object";
+ }
+ if (!root.isMember("properties") || !root["properties"].isArray()) {
+ return Error() << "Missing 'properties' field in root or the field is not an array";
+ }
+ Json::Value properties = root["properties"];
+ std::vector<std::string> errors;
+ for (unsigned int i = 0; i < properties.size(); i++) {
+ if (auto maybeConfig = parseEachProperty(properties[i], &errors); maybeConfig.has_value()) {
+ configsByPropId[maybeConfig.value().config.prop] = std::move(maybeConfig.value());
+ }
+ }
+ if (!errors.empty()) {
+ return Error() << android::base::Join(errors, '\n');
+ }
+ return configsByPropId;
+}
+
+} // namespace jsonconfigloader_impl
+
+JsonConfigLoader::JsonConfigLoader() {
+ mParser = std::make_unique<jsonconfigloader_impl::JsonConfigParser>();
+}
+
+android::base::Result<std::unordered_map<int32_t, ConfigDeclaration>>
+JsonConfigLoader::loadPropConfig(std::istream& is) {
+ return mParser->parseJsonConfig(is);
+}
+
+android::base::Result<std::unordered_map<int32_t, ConfigDeclaration>>
+JsonConfigLoader::loadPropConfig(const std::string& configPath) {
+ std::ifstream ifs(configPath.c_str());
+ if (!ifs) {
+ return android::base::Error() << "couldn't open " << configPath << " for parsing.";
+ }
+
+ return loadPropConfig(ifs);
+}
+
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/test/Android.bp b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/test/Android.bp
new file mode 100644
index 0000000..dae37b9
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/test/Android.bp
@@ -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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_test {
+ name: "JsonConfigLoaderUnitTest",
+ vendor: true,
+ srcs: ["*.cpp"],
+ static_libs: [
+ "VehicleHalJsonConfigLoader",
+ "VehicleHalUtils",
+ "libgtest",
+ ],
+ shared_libs: [
+ "libjsoncpp",
+ ],
+ defaults: ["VehicleHalDefaults"],
+ test_suites: ["device-tests"],
+}
+
+cc_test {
+ name: "JsonConfigLoaderUnitTestEnableTestProperties",
+ vendor: true,
+ srcs: ["*.cpp"],
+ static_libs: [
+ "VehicleHalJsonConfigLoaderEnableTestProperties",
+ "VehicleHalUtils",
+ "libgtest",
+ ],
+ shared_libs: [
+ "libjsoncpp",
+ ],
+ defaults: ["VehicleHalDefaults"],
+ test_suites: ["device-tests"],
+}
diff --git a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/test/JsonConfigLoaderUnitTest.cpp b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/test/JsonConfigLoaderUnitTest.cpp
new file mode 100644
index 0000000..9ff8c1b
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/test/JsonConfigLoaderUnitTest.cpp
@@ -0,0 +1,622 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <JsonConfigLoader.h>
+
+#include <PropertyUtils.h>
+
+#include <gtest/gtest.h>
+#include <sstream>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+
+using ::aidl::android::hardware::automotive::vehicle::RawPropValues;
+using ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
+using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyAccess;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyChangeMode;
+
+class JsonConfigLoaderUnitTest : public ::testing::Test {
+ protected:
+ JsonConfigLoader mLoader;
+};
+
+TEST_F(JsonConfigLoaderUnitTest, testBasic) {
+ std::istringstream iss(R"(
+ {
+ "properties": [{
+ "property": 291504388
+ }]
+ }
+ )");
+
+ auto result = mLoader.loadPropConfig(iss);
+
+ ASSERT_TRUE(result.ok()) << result.error().message();
+
+ auto configs = result.value();
+ ASSERT_EQ(configs.size(), 1u);
+ ASSERT_EQ(configs.begin()->second.config.prop, 291504388);
+}
+
+TEST_F(JsonConfigLoaderUnitTest, testRootNotObject) {
+ std::istringstream iss(R"(
+ []
+ )");
+
+ ASSERT_FALSE(mLoader.loadPropConfig(iss).ok()) << "root is not an object must cause error";
+}
+
+TEST_F(JsonConfigLoaderUnitTest, testMissingPropertiesField) {
+ std::istringstream iss(R"(
+ {
+ "abcd": 1234
+ }
+ )");
+
+ ASSERT_FALSE(mLoader.loadPropConfig(iss).ok()) << "Missing 'properties' field must cause error";
+}
+
+TEST_F(JsonConfigLoaderUnitTest, testPropertiesFieldNotArray) {
+ std::istringstream iss(R"(
+ {
+ "properties': {'a': 'b'}
+ }
+ )");
+
+ ASSERT_FALSE(mLoader.loadPropConfig(iss).ok())
+ << "'properties' field is not an array must cause error";
+}
+
+TEST_F(JsonConfigLoaderUnitTest, testPropertyIsEnum) {
+ std::istringstream iss(R"(
+ {
+ "properties": [{
+ "property": "VehicleProperty::INFO_FUEL_CAPACITY"
+ }]
+ }
+ )");
+
+ auto result = mLoader.loadPropConfig(iss);
+
+ ASSERT_TRUE(result.ok()) << result.error().message();
+
+ auto configs = result.value();
+ ASSERT_EQ(configs.size(), 1u);
+ ASSERT_EQ(configs.begin()->second.config.prop, toInt(VehicleProperty::INFO_FUEL_CAPACITY));
+}
+
+TEST_F(JsonConfigLoaderUnitTest, testPropertyEnum_FailInvalidEnum) {
+ std::istringstream iss(R"(
+ {
+ "properties": [{
+ "property": "VehicleProperty::BLAH"
+ }]
+ }
+ )");
+
+ ASSERT_FALSE(mLoader.loadPropConfig(iss).ok())
+ << "Invalid VehicleProperty enum must cause error";
+}
+
+TEST_F(JsonConfigLoaderUnitTest, testPropertyEnum_FailInvalidType) {
+ std::istringstream iss(R"(
+ {
+ "properties": [{
+ "property": "test"
+ }]
+ }
+ )");
+
+ ASSERT_FALSE(mLoader.loadPropConfig(iss).ok())
+ << "Invalid VehicleProperty type must cause error";
+}
+
+TEST_F(JsonConfigLoaderUnitTest, testProperty_FailInvalidJson) {
+ std::istringstream iss(R"(
+ {
+ "properties": [{
+ }
+ )");
+
+ ASSERT_FALSE(mLoader.loadPropConfig(iss).ok()) << "Invalid JSON format must cause error";
+}
+
+TEST_F(JsonConfigLoaderUnitTest, testConfigArray) {
+ std::istringstream iss(R"(
+ {
+ "properties": [{
+ "property": "VehicleProperty::INFO_FUEL_CAPACITY",
+ "configArray": [1, 2, 3]
+ }]
+ }
+ )");
+
+ auto result = mLoader.loadPropConfig(iss);
+
+ ASSERT_TRUE(result.ok()) << result.error().message();
+
+ auto configs = result.value();
+ ASSERT_EQ(configs.size(), 1u);
+ ASSERT_EQ(configs.begin()->second.config.configArray, std::vector<int>({1, 2, 3}));
+}
+
+TEST_F(JsonConfigLoaderUnitTest, testConfigArrayConstants) {
+ std::istringstream iss(R"(
+ {
+ "properties": [{
+ "property": "VehicleProperty::INFO_FUEL_CAPACITY",
+ "configArray": [1, 2, "Constants::FUEL_DOOR_REAR_LEFT"]
+ }]
+ }
+ )");
+
+ auto result = mLoader.loadPropConfig(iss);
+
+ ASSERT_TRUE(result.ok()) << result.error().message();
+
+ auto configs = result.value();
+ ASSERT_EQ(configs.size(), 1u);
+ ASSERT_EQ(configs.begin()->second.config.configArray,
+ std::vector<int>({1, 2, FUEL_DOOR_REAR_LEFT}));
+}
+
+// We have special logic to deal with GALLON and US_GALLON since they share the same value.
+TEST_F(JsonConfigLoaderUnitTest, testConfigArrayUnitGallon) {
+ std::istringstream iss(R"(
+ {
+ "properties": [{
+ "property": "VehicleProperty::INFO_FUEL_CAPACITY",
+ "configArray": [1, 2, "VehicleUnit::GALLON"]
+ }]
+ }
+ )");
+
+ auto result = mLoader.loadPropConfig(iss);
+
+ ASSERT_TRUE(result.ok()) << result.error().message();
+}
+
+TEST_F(JsonConfigLoaderUnitTest, testConfigArrayUnitUsGallon) {
+ std::istringstream iss(R"(
+ {
+ "properties": [{
+ "property": "VehicleProperty::INFO_FUEL_CAPACITY",
+ "configArray": [1, 2, "VehicleUnit::US_GALLON"]
+ }]
+ }
+ )");
+
+ auto result = mLoader.loadPropConfig(iss);
+
+ ASSERT_TRUE(result.ok()) << result.error().message();
+}
+
+TEST_F(JsonConfigLoaderUnitTest, testConfigArray_FailInvalidEnum) {
+ std::istringstream iss(R"(
+ {
+ "properties": [{
+ "property": "VehicleProperty::INFO_FUEL_CAPACITY",
+ "configArray": [1, 2, "VehicleUnits::BLAH"]
+ }]
+ }
+ )");
+
+ ASSERT_FALSE(mLoader.loadPropConfig(iss).ok())
+ << "Invalid enum in ConfigArray must cause error";
+}
+
+TEST_F(JsonConfigLoaderUnitTest, testConfigArray_FailNotArray) {
+ std::istringstream iss(R"(
+ {
+ "properties": [{
+ "property": "VehicleProperty::INFO_FUEL_CAPACITY",
+ "configArray": "123"
+ }]
+ }
+ )");
+
+ ASSERT_FALSE(mLoader.loadPropConfig(iss).ok())
+ << "ConfigArray is not an array must cause error";
+}
+
+TEST_F(JsonConfigLoaderUnitTest, testConfigString) {
+ std::istringstream iss(R"(
+ {
+ "properties": [{
+ "property": "VehicleProperty::INFO_FUEL_CAPACITY",
+ "configString": "test"
+ }]
+ }
+ )");
+
+ auto result = mLoader.loadPropConfig(iss);
+
+ ASSERT_TRUE(result.ok()) << result.error().message();
+
+ auto configs = result.value();
+ ASSERT_EQ(configs.size(), 1u);
+ ASSERT_EQ(configs.begin()->second.config.configString, "test");
+}
+
+TEST_F(JsonConfigLoaderUnitTest, testConfigString_FailNotString) {
+ std::istringstream iss(R"(
+ {
+ "properties": [{
+ "property": "VehicleProperty::INFO_FUEL_CAPACITY",
+ "configString": 1234
+ }]
+ }
+ )");
+
+ ASSERT_FALSE(mLoader.loadPropConfig(iss).ok())
+ << "ConfigString is not a String must cause error";
+}
+
+TEST_F(JsonConfigLoaderUnitTest, testCheckDefaultAccessChangeMode) {
+ std::istringstream iss(R"(
+ {
+ "properties": [{
+ "property": "VehicleProperty::INFO_FUEL_CAPACITY"
+ }]
+ }
+ )");
+
+ auto result = mLoader.loadPropConfig(iss);
+
+ ASSERT_TRUE(result.ok()) << result.error().message();
+ auto configs = result.value();
+ ASSERT_EQ(configs.size(), 1u);
+
+ const VehiclePropConfig& propConfig = configs.begin()->second.config;
+ ASSERT_EQ(propConfig.access, VehiclePropertyAccess::READ);
+ ASSERT_EQ(propConfig.changeMode, VehiclePropertyChangeMode::STATIC);
+}
+
+TEST_F(JsonConfigLoaderUnitTest, testAccessOverride) {
+ std::istringstream iss(R"(
+ {
+ "properties": [{
+ "property": "VehicleProperty::INFO_FUEL_CAPACITY",
+ "access": "VehiclePropertyAccess::WRITE"
+ }]
+ }
+ )");
+
+ auto result = mLoader.loadPropConfig(iss);
+
+ ASSERT_TRUE(result.ok()) << result.error().message();
+ auto configs = result.value();
+ ASSERT_EQ(configs.size(), 1u);
+
+ const VehiclePropConfig& propConfig = configs.begin()->second.config;
+ ASSERT_EQ(propConfig.access, VehiclePropertyAccess::WRITE);
+ ASSERT_EQ(propConfig.changeMode, VehiclePropertyChangeMode::STATIC);
+}
+
+TEST_F(JsonConfigLoaderUnitTest, testChangeModeOverride) {
+ std::istringstream iss(R"(
+ {
+ "properties": [{
+ "property": "VehicleProperty::INFO_FUEL_CAPACITY",
+ "changeMode": "VehiclePropertyChangeMode::ON_CHANGE"
+ }]
+ }
+ )");
+
+ auto result = mLoader.loadPropConfig(iss);
+
+ ASSERT_TRUE(result.ok()) << result.error().message();
+ auto configs = result.value();
+ ASSERT_EQ(configs.size(), 1u);
+
+ const VehiclePropConfig& propConfig = configs.begin()->second.config;
+ ASSERT_EQ(propConfig.access, VehiclePropertyAccess::READ);
+ ASSERT_EQ(propConfig.changeMode, VehiclePropertyChangeMode::ON_CHANGE);
+}
+
+TEST_F(JsonConfigLoaderUnitTest, testCustomProp) {
+ std::istringstream iss(R"(
+ {
+ "properties": [{
+ "property": 1234,
+ "access": "VehiclePropertyAccess::WRITE",
+ "changeMode": "VehiclePropertyChangeMode::ON_CHANGE"
+ }]
+ }
+ )");
+
+ auto result = mLoader.loadPropConfig(iss);
+
+ ASSERT_TRUE(result.ok()) << result.error().message();
+ auto configs = result.value();
+ ASSERT_EQ(configs.size(), 1u);
+
+ const VehiclePropConfig& propConfig = configs.begin()->second.config;
+ ASSERT_EQ(propConfig.access, VehiclePropertyAccess::WRITE);
+ ASSERT_EQ(propConfig.changeMode, VehiclePropertyChangeMode::ON_CHANGE);
+}
+
+TEST_F(JsonConfigLoaderUnitTest, testCustomProp_FailMissingAccess) {
+ std::istringstream iss(R"(
+ {
+ "properties": [{
+ "property": 1234,
+ "changeMode": "VehiclePropertyChangeMode::ON_CHANGE"
+ }]
+ }
+ )");
+
+ ASSERT_FALSE(mLoader.loadPropConfig(iss).ok())
+ << "Missing access for custom property must cause error";
+}
+
+TEST_F(JsonConfigLoaderUnitTest, testCustomProp_FailMissingChangeMode) {
+ std::istringstream iss(R"(
+ {
+ "properties": [{
+ "property": 1234,
+ "access": "VehiclePropertyAccess::WRITE"
+ }]
+ }
+ )");
+
+ ASSERT_FALSE(mLoader.loadPropConfig(iss).ok())
+ << "Missing change mode for custom property must cause error";
+}
+
+TEST_F(JsonConfigLoaderUnitTest, testMinSampleRate) {
+ std::istringstream iss(R"(
+ {
+ "properties": [{
+ "property": "VehicleProperty::INFO_FUEL_CAPACITY",
+ "minSampleRate": 1,
+ }]
+ }
+ )");
+
+ auto result = mLoader.loadPropConfig(iss);
+
+ ASSERT_TRUE(result.ok()) << result.error().message();
+
+ auto configs = result.value();
+ ASSERT_EQ(configs.size(), 1u);
+ ASSERT_EQ(configs.begin()->second.config.minSampleRate, 1);
+}
+
+TEST_F(JsonConfigLoaderUnitTest, testMinSampleRate_FailInvalidType) {
+ std::istringstream iss(R"(
+ {
+ "properties": [{
+ "property": "VehicleProperty::INFO_FUEL_CAPACITY",
+ "minSampleRate": "abcd",
+ }]
+ }
+ )");
+
+ ASSERT_FALSE(mLoader.loadPropConfig(iss).ok())
+ << "Wrong type for MinSampleRate must cause error";
+}
+
+TEST_F(JsonConfigLoaderUnitTest, testMaxSampleRate) {
+ std::istringstream iss(R"(
+ {
+ "properties": [{
+ "property": "VehicleProperty::INFO_FUEL_CAPACITY",
+ "maxSampleRate": 1,
+ }]
+ }
+ )");
+
+ auto result = mLoader.loadPropConfig(iss);
+
+ ASSERT_TRUE(result.ok()) << result.error().message();
+
+ auto configs = result.value();
+ ASSERT_EQ(configs.size(), 1u);
+ ASSERT_EQ(configs.begin()->second.config.maxSampleRate, 1);
+}
+
+TEST_F(JsonConfigLoaderUnitTest, testMaxSampleRate_FailInvalidType) {
+ std::istringstream iss(R"(
+ {
+ "properties": [{
+ "property": "VehicleProperty::INFO_FUEL_CAPACITY",
+ "maxSampleRate": "abcd",
+ }]
+ }
+ )");
+
+ ASSERT_FALSE(mLoader.loadPropConfig(iss).ok())
+ << "Wrong type for MaxSampleRate must cause error";
+}
+
+TEST_F(JsonConfigLoaderUnitTest, testDefaultValue_Simple) {
+ std::istringstream iss(R"(
+ {
+ "properties": [{
+ "property": "VehicleProperty::INFO_FUEL_CAPACITY",
+ "defaultValue": {
+ "int32Values": [1, 2]
+ }
+ }]
+ }
+ )");
+
+ auto result = mLoader.loadPropConfig(iss);
+
+ ASSERT_TRUE(result.ok()) << result.error().message();
+
+ auto configs = result.value();
+ ASSERT_EQ(configs.size(), 1u);
+ ASSERT_EQ(configs.begin()->second.initialValue.int32Values, std::vector<int32_t>({1, 2}));
+}
+
+TEST_F(JsonConfigLoaderUnitTest, testDefaultValue_Mixed) {
+ std::istringstream iss(R"(
+ {
+ "properties": [{
+ "property": "VehicleProperty::INFO_FUEL_CAPACITY",
+ "defaultValue": {
+ "int32Values": [1, "Constants::FUEL_DOOR_REAR_LEFT"],
+ "int64Values": [2, "Constants::FUEL_DOOR_REAR_LEFT"],
+ "floatValues": [3.0, "Constants::FUEL_DOOR_REAR_LEFT"],
+ "stringValue": "abcd"
+ }
+ }]
+ }
+ )");
+
+ auto result = mLoader.loadPropConfig(iss);
+
+ ASSERT_TRUE(result.ok()) << result.error().message();
+
+ auto configs = result.value();
+ ASSERT_EQ(configs.size(), 1u);
+
+ const RawPropValues& initialValue = configs.begin()->second.initialValue;
+ ASSERT_EQ(initialValue.int32Values, std::vector<int32_t>({1, FUEL_DOOR_REAR_LEFT}));
+ ASSERT_EQ(initialValue.int64Values,
+ std::vector<int64_t>({2, static_cast<int64_t>(FUEL_DOOR_REAR_LEFT)}));
+ ASSERT_EQ(initialValue.floatValues,
+ std::vector<float>({3.0, static_cast<float>(FUEL_DOOR_REAR_LEFT)}));
+ ASSERT_EQ(initialValue.stringValue, "abcd");
+}
+
+TEST_F(JsonConfigLoaderUnitTest, testDefaultValue_FailNotObject) {
+ std::istringstream iss(R"(
+ {
+ "properties": [{
+ "property": "VehicleProperty::INFO_FUEL_CAPACITY",
+ "defaultValue": []
+ }]
+ }
+ )");
+
+ ASSERT_FALSE(mLoader.loadPropConfig(iss).ok())
+ << "DefaultValue is not an object must cause error";
+}
+
+TEST_F(JsonConfigLoaderUnitTest, testDefaultValue_FailInvalidType) {
+ std::istringstream iss(R"(
+ {
+ "properties": [{
+ "property": "VehicleProperty::INFO_FUEL_CAPACITY",
+ "defaultValue": {
+ "int32Values": [1.1]
+ }
+ }]
+ }
+ )");
+
+ ASSERT_FALSE(mLoader.loadPropConfig(iss).ok())
+ << "Wrong type for DefaultValue must cause error";
+}
+
+TEST_F(JsonConfigLoaderUnitTest, testAreas_Simple) {
+ std::istringstream iss(R"(
+ {
+ "properties": [{
+ "property": "VehicleProperty::INFO_FUEL_CAPACITY",
+ "areas": [{
+ "areaId": "Constants::HVAC_ALL",
+ "minInt32Value": 1,
+ "maxInt32Value": 7
+ }]
+ }]
+ }
+ )");
+
+ auto result = mLoader.loadPropConfig(iss);
+
+ auto configs = result.value();
+ ASSERT_EQ(configs.size(), 1u);
+
+ const VehiclePropConfig& config = configs.begin()->second.config;
+ ASSERT_EQ(config.areaConfigs.size(), 1u);
+ const VehicleAreaConfig& areaConfig = config.areaConfigs[0];
+ ASSERT_EQ(areaConfig.minInt32Value, 1);
+ ASSERT_EQ(areaConfig.maxInt32Value, 7);
+ ASSERT_EQ(areaConfig.areaId, HVAC_ALL);
+}
+
+TEST_F(JsonConfigLoaderUnitTest, testAreas_DefaultValueForEachArea) {
+ std::istringstream iss(R"(
+ {
+ "properties": [{
+ "property": "VehicleProperty::INFO_FUEL_CAPACITY",
+ "areas": [{
+ "areaId": "Constants::HVAC_LEFT",
+ "defaultValue": {
+ "int32Values": [1]
+ }
+ }, {
+ "areaId": "Constants::HVAC_RIGHT",
+ "defaultValue": {
+ "int32Values": [2]
+ }
+ }]
+ }]
+ }
+ )");
+
+ auto result = mLoader.loadPropConfig(iss);
+
+ auto configs = result.value();
+ ASSERT_EQ(configs.size(), 1u);
+
+ const VehiclePropConfig& config = configs.begin()->second.config;
+ ASSERT_EQ(config.areaConfigs.size(), 2u);
+ ASSERT_EQ(config.areaConfigs[0].areaId, HVAC_LEFT);
+ ASSERT_EQ(config.areaConfigs[1].areaId, HVAC_RIGHT);
+ ASSERT_EQ(configs.begin()->second.initialAreaValues[HVAC_LEFT],
+ RawPropValues{.int32Values = {1}});
+ ASSERT_EQ(configs.begin()->second.initialAreaValues[HVAC_RIGHT],
+ RawPropValues{.int32Values = {2}});
+}
+
+TEST_F(JsonConfigLoaderUnitTest, testAreas_FailInvalidTypeForOneAreaValue) {
+ std::istringstream iss(R"(
+ {
+ "properties": [{
+ "property": "VehicleProperty::INFO_FUEL_CAPACITY",
+ "areas": [{
+ "areaId": "Constants::HVAC_LEFT",
+ "defaultValue": {
+ "int32Values": [1]
+ }
+ }, {
+ "areaId": "Constants::HVAC_RIGHT",
+ "defaultValue": {
+ "int32Values": [2.1]
+ }
+ }]
+ }]
+ }
+ )");
+
+ ASSERT_FALSE(mLoader.loadPropConfig(iss).ok())
+ << "Wrong type for DefaultValue for one area must cause error";
+}
+
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/vehicle/aidl/impl/default_config/config/Android.bp b/automotive/vehicle/aidl/impl/default_config/config/Android.bp
index c5f86c2..8f1c7d1 100644
--- a/automotive/vehicle/aidl/impl/default_config/config/Android.bp
+++ b/automotive/vehicle/aidl/impl/default_config/config/Android.bp
@@ -21,3 +21,27 @@
name: "VehicleHalVendorClusterTestProperties_JSON",
srcs: ["VendorClusterTestProperties.json"],
}
+
+prebuilt_etc {
+ name: "Prebuilt_VehicleHalDefaultProperties_JSON",
+ filename_from_src: true,
+ src: "DefaultProperties.json",
+ sub_dir: "automotive/vhalconfig/",
+ vendor: true,
+}
+
+prebuilt_etc {
+ name: "Prebuilt_VehicleHalTestProperties_JSON",
+ filename_from_src: true,
+ src: "TestProperties.json",
+ sub_dir: "automotive/vhalconfig/",
+ vendor: true,
+}
+
+prebuilt_etc {
+ name: "Prebuilt_VehicleHalVendorClusterTestProperties_JSON",
+ filename_from_src: true,
+ src: "VendorClusterTestProperties.json",
+ sub_dir: "automotive/vhalconfig/",
+ vendor: true,
+}
diff --git a/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json b/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
index f2415aa..3f6aa63 100644
--- a/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
+++ b/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
@@ -130,6 +130,836 @@
]
},
{
+ "property": "VehicleProperty::SEAT_BELT_BUCKLED",
+ "defaultValue": {
+ "int32Values": [
+ 0
+ ]
+ },
+ "areas": [
+ {
+ "areaId": "Constants::SEAT_1_LEFT"
+ },
+ {
+ "areaId": "Constants::SEAT_1_RIGHT"
+ },
+ {
+ "areaId": "Constants::SEAT_2_LEFT"
+ },
+ {
+ "areaId": "Constants::SEAT_2_RIGHT"
+ },
+ {
+ "areaId": "Constants::SEAT_2_CENTER"
+ }
+ ]
+ },
+ {
+ "property": "VehicleProperty::SEAT_BELT_HEIGHT_POS",
+ "defaultValue": {
+ "int32Values": [
+ 10
+ ]
+ },
+ "areas": [
+ {
+ "areaId": "Constants::SEAT_1_LEFT",
+ "minInt32Value": 0,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_1_RIGHT",
+ "minInt32Value": 0,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_2_LEFT",
+ "minInt32Value": 0,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_2_RIGHT",
+ "minInt32Value": 0,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_2_CENTER",
+ "minInt32Value": 0,
+ "maxInt32Value": 10
+ }
+ ]
+ },
+ {
+ "property": "VehicleProperty::SEAT_BELT_HEIGHT_MOVE",
+ "defaultValue": {
+ "int32Values": [
+ 0
+ ]
+ },
+ "areas": [
+ {
+ "areaId": "Constants::SEAT_1_LEFT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_1_RIGHT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_2_LEFT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_2_RIGHT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_2_CENTER",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ }
+ ]
+ },
+ {
+ "property": "VehicleProperty::SEAT_FORE_AFT_POS",
+ "defaultValue": {
+ "int32Values": [
+ 0
+ ]
+ },
+ "areas": [
+ {
+ "areaId": "Constants::SEAT_1_LEFT",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_1_RIGHT",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_2_LEFT",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_2_RIGHT",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_2_CENTER",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ }
+ ]
+ },
+ {
+ "property": "VehicleProperty::SEAT_FORE_AFT_MOVE",
+ "defaultValue": {
+ "int32Values": [
+ 0
+ ]
+ },
+ "areas": [
+ {
+ "areaId": "Constants::SEAT_1_LEFT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_1_RIGHT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_2_LEFT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_2_RIGHT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_2_CENTER",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ }
+ ]
+ },
+ {
+ "property": "VehicleProperty::SEAT_BACKREST_ANGLE_1_POS",
+ "defaultValue": {
+ "int32Values": [
+ 0
+ ]
+ },
+ "areas": [
+ {
+ "areaId": "Constants::SEAT_1_LEFT",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_1_RIGHT",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_2_LEFT",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_2_RIGHT",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_2_CENTER",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ }
+ ]
+ },
+ {
+ "property": "VehicleProperty::SEAT_BACKREST_ANGLE_1_MOVE",
+ "defaultValue": {
+ "int32Values": [
+ 0
+ ]
+ },
+ "areas": [
+ {
+ "areaId": "Constants::SEAT_1_LEFT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_1_RIGHT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_2_LEFT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_2_RIGHT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_2_CENTER",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ }
+ ]
+ },
+ {
+ "property": "VehicleProperty::SEAT_BACKREST_ANGLE_2_POS",
+ "defaultValue": {
+ "int32Values": [
+ 0
+ ]
+ },
+ "areas": [
+ {
+ "areaId": "Constants::SEAT_1_LEFT",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_1_RIGHT",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_2_LEFT",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_2_RIGHT",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_2_CENTER",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ }
+ ]
+ },
+ {
+ "property": "VehicleProperty::SEAT_BACKREST_ANGLE_2_MOVE",
+ "defaultValue": {
+ "int32Values": [
+ 0
+ ]
+ },
+ "areas": [
+ {
+ "areaId": "Constants::SEAT_1_LEFT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_1_RIGHT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_2_LEFT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_2_RIGHT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_2_CENTER",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ }
+ ]
+ },
+ {
+ "property": "VehicleProperty::SEAT_HEIGHT_POS",
+ "defaultValue": {
+ "int32Values": [
+ 0
+ ]
+ },
+ "areas": [
+ {
+ "areaId": "Constants::SEAT_1_LEFT",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_1_RIGHT",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_2_LEFT",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_2_RIGHT",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_2_CENTER",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ }
+ ]
+ },
+ {
+ "property": "VehicleProperty::SEAT_HEIGHT_MOVE",
+ "defaultValue": {
+ "int32Values": [
+ 0
+ ]
+ },
+ "areas": [
+ {
+ "areaId": "Constants::SEAT_1_LEFT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_1_RIGHT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_2_LEFT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_2_RIGHT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_2_CENTER",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ }
+ ]
+ },
+ {
+ "property": "VehicleProperty::SEAT_DEPTH_POS",
+ "defaultValue": {
+ "int32Values": [
+ 0
+ ]
+ },
+ "areas": [
+ {
+ "areaId": "Constants::SEAT_1_LEFT",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_1_RIGHT",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_2_LEFT",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_2_RIGHT",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_2_CENTER",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ }
+ ]
+ },
+ {
+ "property": "VehicleProperty::SEAT_DEPTH_MOVE",
+ "defaultValue": {
+ "int32Values": [
+ 0
+ ]
+ },
+ "areas": [
+ {
+ "areaId": "Constants::SEAT_1_LEFT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_1_RIGHT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_2_LEFT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_2_RIGHT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_2_CENTER",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ }
+ ]
+ },
+ {
+ "property": "VehicleProperty::SEAT_TILT_POS",
+ "defaultValue": {
+ "int32Values": [
+ 0
+ ]
+ },
+ "areas": [
+ {
+ "areaId": "Constants::SEAT_1_LEFT",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_1_RIGHT",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_2_LEFT",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_2_RIGHT",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_2_CENTER",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ }
+ ]
+ },
+ {
+ "property": "VehicleProperty::SEAT_TILT_MOVE",
+ "defaultValue": {
+ "int32Values": [
+ 0
+ ]
+ },
+ "areas": [
+ {
+ "areaId": "Constants::SEAT_1_LEFT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_1_RIGHT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_2_LEFT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_2_RIGHT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_2_CENTER",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ }
+ ]
+ },
+ {
+ "property": "VehicleProperty::SEAT_LUMBAR_FORE_AFT_POS",
+ "defaultValue": {
+ "int32Values": [
+ 0
+ ]
+ },
+ "areas": [
+ {
+ "areaId": "Constants::SEAT_1_LEFT",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_1_RIGHT",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_2_LEFT",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_2_RIGHT",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_2_CENTER",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ }
+ ]
+ },
+ {
+ "property": "VehicleProperty::SEAT_LUMBAR_FORE_AFT_MOVE",
+ "defaultValue": {
+ "int32Values": [
+ 0
+ ]
+ },
+ "areas": [
+ {
+ "areaId": "Constants::SEAT_1_LEFT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_1_RIGHT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_2_LEFT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_2_RIGHT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_2_CENTER",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ }
+ ]
+ },
+ {
+ "property": "VehicleProperty::SEAT_LUMBAR_SIDE_SUPPORT_POS",
+ "defaultValue": {
+ "int32Values": [
+ 0
+ ]
+ },
+ "areas": [
+ {
+ "areaId": "Constants::SEAT_1_LEFT",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_1_RIGHT",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_2_LEFT",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_2_RIGHT",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_2_CENTER",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ }
+ ]
+ },
+ {
+ "property": "VehicleProperty::SEAT_LUMBAR_SIDE_SUPPORT_MOVE",
+ "defaultValue": {
+ "int32Values": [
+ 0
+ ]
+ },
+ "areas": [
+ {
+ "areaId": "Constants::SEAT_1_LEFT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_1_RIGHT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_2_LEFT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_2_RIGHT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_2_CENTER",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ }
+ ]
+ },
+ {
+ "property": "VehicleProperty::SEAT_HEADREST_HEIGHT_MOVE",
+ "defaultValue": {
+ "int32Values": [
+ 0
+ ]
+ },
+ "areas": [
+ {
+ "areaId": "Constants::SEAT_1_LEFT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_1_RIGHT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_2_LEFT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_2_RIGHT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_2_CENTER",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ }
+ ]
+ },
+ {
+ "property": "VehicleProperty::SEAT_HEADREST_ANGLE_POS",
+ "defaultValue": {
+ "int32Values": [
+ 0
+ ]
+ },
+ "areas": [
+ {
+ "areaId": "Constants::SEAT_1_LEFT",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_1_RIGHT",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_2_LEFT",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_2_RIGHT",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_2_CENTER",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ }
+ ]
+ },
+ {
+ "property": "VehicleProperty::SEAT_HEADREST_ANGLE_MOVE",
+ "defaultValue": {
+ "int32Values": [
+ 0
+ ]
+ },
+ "areas": [
+ {
+ "areaId": "Constants::SEAT_1_LEFT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_1_RIGHT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_2_LEFT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_2_RIGHT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_2_CENTER",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ }
+ ]
+ },
+ {
+ "property": "VehicleProperty::SEAT_HEADREST_FORE_AFT_POS",
+ "defaultValue": {
+ "int32Values": [
+ 0
+ ]
+ },
+ "areas": [
+ {
+ "areaId": "Constants::SEAT_1_LEFT",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_1_RIGHT",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_2_LEFT",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_2_RIGHT",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_2_CENTER",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ }
+ ]
+ },
+ {
+ "property": "VehicleProperty::SEAT_HEADREST_FORE_AFT_MOVE",
+ "defaultValue": {
+ "int32Values": [
+ 0
+ ]
+ },
+ "areas": [
+ {
+ "areaId": "Constants::SEAT_1_LEFT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_1_RIGHT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_2_LEFT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_2_RIGHT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "Constants::SEAT_2_CENTER",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ }
+ ]
+ },
+ {
"property": "VehicleProperty::SEAT_OCCUPANCY",
"areas": [
{
@@ -536,6 +1366,19 @@
]
},
{
+ "property": "VehicleProperty::HVAC_ACTUAL_FAN_SPEED_RPM",
+ "defaultValue": {
+ "int32Values": [
+ 50
+ ]
+ },
+ "areas": [
+ {
+ "areaId": "Constants::HVAC_ALL"
+ }
+ ]
+ },
+ {
"property": "VehicleProperty::HVAC_POWER_ON",
"defaultValue": {
"int32Values": [
@@ -783,6 +1626,42 @@
"comment": "+ve values for heating and -ve for cooling"
},
{
+ "property": "VehicleProperty::HVAC_SIDE_MIRROR_HEAT",
+ "defaultValue": {
+ "int32Values": [
+ 0
+ ]
+ },
+ "areas": [
+ {
+ "areaId": "Constants::MIRROR_DRIVER_LEFT_RIGHT",
+ "minInt32Value": 0,
+ "maxInt32Value": 2
+ }
+ ]
+ },
+ {
+ "property": "VehicleProperty::HVAC_TEMPERATURE_CURRENT",
+ "areas": [
+ {
+ "defaultValue": {
+ "floatValues": [
+ 17.3
+ ]
+ },
+ "areaId": 49
+ },
+ {
+ "defaultValue": {
+ "floatValues": [
+ 19.1
+ ]
+ },
+ "areaId": 68
+ }
+ ]
+ },
+ {
"property": "VehicleProperty::HVAC_TEMPERATURE_SET",
"areas": [
{
@@ -820,7 +1699,7 @@
"defaultValue": {
"floatValues": [
66.19999694824219,
- 49.0,
+ "VehicleUnit::FAHRENHEIT",
19.0,
66.5
]
@@ -840,12 +1719,12 @@
"property": "VehicleProperty::HVAC_TEMPERATURE_DISPLAY_UNITS",
"defaultValue": {
"int32Values": [
- 49
+ "VehicleUnit::FAHRENHEIT"
]
},
"configArray": [
- 49,
- 48
+ "VehicleUnit::FAHRENHEIT",
+ "VehicleUnit::CELSIUS"
]
},
{
@@ -1009,6 +1888,122 @@
]
},
{
+ "property": "VehicleProperty::MIRROR_Z_POS",
+ "defaultValue": {
+ "int32Values": [
+ 0
+ ]
+ },
+ "areas": [
+ {
+ "areaId": "VehicleAreaMirror::DRIVER_LEFT",
+ "minInt32Value": -3,
+ "maxInt32Value": 3
+ },
+ {
+ "areaId": "VehicleAreaMirror::DRIVER_RIGHT",
+ "minInt32Value": -3,
+ "maxInt32Value": 3
+ },
+ {
+ "areaId": "VehicleAreaMirror::DRIVER_CENTER",
+ "minInt32Value": -3,
+ "maxInt32Value": 3
+ }
+ ]
+ },
+ {
+ "property": "VehicleProperty::MIRROR_Z_MOVE",
+ "defaultValue": {
+ "int32Values": [
+ 0
+ ]
+ },
+ "areas": [
+ {
+ "areaId": "VehicleAreaMirror::DRIVER_LEFT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "VehicleAreaMirror::DRIVER_RIGHT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "VehicleAreaMirror::DRIVER_CENTER",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ }
+ ]
+ },
+ {
+ "property": "VehicleProperty::MIRROR_Y_POS",
+ "defaultValue": {
+ "int32Values": [
+ 0
+ ]
+ },
+ "areas": [
+ {
+ "areaId": "VehicleAreaMirror::DRIVER_LEFT",
+ "minInt32Value": -3,
+ "maxInt32Value": 3
+ },
+ {
+ "areaId": "VehicleAreaMirror::DRIVER_RIGHT",
+ "minInt32Value": -3,
+ "maxInt32Value": 3
+ },
+ {
+ "areaId": "VehicleAreaMirror::DRIVER_CENTER",
+ "minInt32Value": -3,
+ "maxInt32Value": 3
+ }
+ ]
+ },
+ {
+ "property": "VehicleProperty::MIRROR_Y_MOVE",
+ "defaultValue": {
+ "int32Values": [
+ 0
+ ]
+ },
+ "areas": [
+ {
+ "areaId": "VehicleAreaMirror::DRIVER_LEFT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "VehicleAreaMirror::DRIVER_RIGHT",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ },
+ {
+ "areaId": "VehicleAreaMirror::DRIVER_CENTER",
+ "minInt32Value": -1,
+ "maxInt32Value": 1
+ }
+ ]
+ },
+ {
+ "property": "VehicleProperty::MIRROR_LOCK",
+ "defaultValue": {
+ "int32Values": [
+ 1
+ ]
+ }
+ },
+ {
+ "property": "VehicleProperty::MIRROR_FOLD",
+ "defaultValue": {
+ "int32Values": [
+ 1
+ ]
+ }
+ },
+ {
"property": "VehicleProperty::WINDOW_LOCK",
"areas": [
{
@@ -1032,22 +2027,22 @@
{
"areaId": "Constants::WINDOW_1_LEFT",
"minInt32Value": 0,
- "maxInt32Value": 10,
+ "maxInt32Value": 10
},
{
"areaId": "Constants::WINDOW_1_RIGHT",
"minInt32Value": 0,
- "maxInt32Value": 10,
+ "maxInt32Value": 10
},
{
"areaId": "Constants::WINDOW_2_LEFT",
"minInt32Value": 0,
- "maxInt32Value": 10,
+ "maxInt32Value": 10
},
{
"areaId": "Constants::WINDOW_2_RIGHT",
"minInt32Value": 0,
- "maxInt32Value": 10,
+ "maxInt32Value": 10
},
{
"areaId": "Constants::WINDOW_ROOF_TOP_1",
@@ -1187,6 +2182,39 @@
}
},
{
+ "property": "VehicleProperty::CABIN_LIGHTS_STATE",
+ "defaultValue": {
+ "int32Values": [
+ "Constants::LIGHT_STATE_ON"
+ ]
+ }
+ },
+ {
+ "property": "VehicleProperty::READING_LIGHTS_STATE",
+ "defaultValue": {
+ "int32Values": [
+ "Constants::LIGHT_STATE_ON"
+ ]
+ },
+ "areas": [
+ {
+ "areaId": "Constants::SEAT_1_LEFT"
+ },
+ {
+ "areaId": "Constants::SEAT_1_RIGHT"
+ },
+ {
+ "areaId": "Constants::SEAT_2_LEFT"
+ },
+ {
+ "areaId": "Constants::SEAT_2_RIGHT"
+ },
+ {
+ "areaId": "Constants::SEAT_2_CENTER"
+ }
+ ]
+ },
+ {
"property": "VehicleProperty::HEADLIGHTS_SWITCH",
"defaultValue": {
"int32Values": [
@@ -1279,13 +2307,13 @@
"property": "VehicleProperty::CURRENT_POWER_POLICY"
},
{
- "property": "VehicleProperty::ANDROID_EPOCH_TIME",
+ "property": "VehicleProperty::ANDROID_EPOCH_TIME"
},
{
- "property": "VehicleProperty::WATCHDOG_ALIVE",
+ "property": "VehicleProperty::WATCHDOG_ALIVE"
},
{
- "property": "VehicleProperty::WATCHDOG_TERMINATED_PROCESS",
+ "property": "VehicleProperty::WATCHDOG_TERMINATED_PROCESS"
},
{
"property": "VehicleProperty::VHAL_HEARTBEAT"
@@ -1315,7 +2343,7 @@
]
},
"comment":
- "Value means: 0 /* Off */, -1, -1, -1, -1 /* Bounds */, -1, -1, -1, -1 /* Insets */",
+ "Value means: 0 /* Off */, -1, -1, -1, -1 /* Bounds */, -1, -1, -1, -1 /* Insets */"
},
{
"property": "VehicleProperty::CLUSTER_REPORT_STATE",
@@ -1332,18 +2360,18 @@
]
},
{
- "property": "VehicleProperty::CLUSTER_REQUEST_DISPLAY",
+ "property": "VehicleProperty::CLUSTER_REQUEST_DISPLAY"
},
{
- "property": "VehicleProperty::CLUSTER_NAVIGATION_STATE",
+ "property": "VehicleProperty::CLUSTER_NAVIGATION_STATE"
},
{
"property": "VehicleProperty::GENERAL_SAFETY_REGULATION_COMPLIANCE_REQUIREMENT",
"defaultValue": {
"int32Values": [
- "GsrComplianceRequirementType::GSR_COMPLIANCE_REQUIRED_THROUGH_SYSTEM_IMAGE"
+ "GsrComplianceRequirementType::GSR_COMPLIANCE_REQUIRED_V1"
]
}
}
]
-}
\ No newline at end of file
+}
diff --git a/automotive/vehicle/aidl/impl/default_config/config/README.md b/automotive/vehicle/aidl/impl/default_config/config/README.md
new file mode 100644
index 0000000..0e3fc5e
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/default_config/config/README.md
@@ -0,0 +1,151 @@
+# Property Configuration Files
+
+Each JSON file in this folder is a property configuration file for reference
+Vehicle HAL. They contain VehiclePropConfig information along with initial
+value information.
+
+## JSON schema
+
+Each JSON file must be in a schema like the following example:
+(The comment starting with "//" is for documentation only and must be removed
+from the actual JSON file. The "comment" field is used for comment in the
+actual JSON file and will be ignored by the parser)
+
+```
+{
+ // (number) The version for the JSON schema.
+ "apiVersion": 1,
+ // (non-empty array of objects) The property configuration list.
+ //
+ // Each object is a configuration for one property.
+ "properties": [
+ {
+ // (number/string) The ID for the property.
+ // This value is defined in a string value
+ // which represents a constant value, see the "JSON Number-type
+ // Field Values" section for detail.
+ "property": "VehicleProperty::INFO_FUEL_CAPACITY",
+ // (optional, number/string) The access mode for the property.
+ // If specified, this overwrite the default access mode specified in
+ // VehicleProperty.aidl. Must be specified for vendor properties.
+ "access": "VehiclePropertyAccess::READ",
+ // (optional, number/string) The change mode for the property.
+ // If specified, this overwrite the default change mode specified in
+ // VehicleProperty.aidl. Must be specified for vendor properties.
+ "changeMode": "VehiclePropertyChangeMode::STATIC",
+ // (optional, string) The config string.
+ "configString": "blahblah",
+ // (optional, array of number/string) The config array.
+ "configArray": [1, 2, "Constants::HVAC_ALL"],
+ // (optional, object) The default value for the property.
+ // If not specified, the property will be shown as unavailable
+ // until its value is set.
+ "defaultValue": {
+ // (optional, array of int number/string) Int values.
+ "int32Values": [1, 2, "Constants::HVAC_ALL"],
+ // (optional, array of int number/string) Long values.
+ "int64Values": [1, 2],
+ // (optional, array of float number/string) Float values.
+ "floatValues": [1.1, 2.2],
+ // (optional, string) String value.
+ "stringValue": "test"
+ },
+ // (optional, number/string) The minimum sample rate in HZ.
+ // Only work for VehiclePropertyChangeMode::CONTINUOUS property.
+ // Must be specified for continuous property.
+ "minSampleRate": 1,
+ // (optional, number/string) The maximum sample rate in HZ.
+ // Only work for VehiclePropertyChangeMode::CONTINUOUS property.
+ // Must be specified for continuous property.
+ "maxSampleRate": 10,
+ // (optional, array of objects) The area configs.
+ "areas:" [
+ {
+ // (number/string) The area ID.
+ "areaId": "Constants::DOOR_1_LEFT",
+ // (optional number/string) The minimum int value.
+ "minInt32Value": 1,
+ // (optional number/string) The maximum int value.
+ "maxInt32Value": 10,
+ // (optional number/string) The minimum long value.
+ "minInt64Value": 1,
+ // (optional number/string) The maximum long value.
+ "maxInt64Value": 10,
+ // (optional number/string) The minimum float value.
+ "minFloatValue": 1,
+ // (optional number/string) The maximum float value.
+ "maxFloatValue": 10,
+ // (optional object) The default value for this area.
+ // Uses the same format as the "defaultValue" field for
+ // property object. If specified, this overwrite the global
+ // defaultValue.
+ "defaultValue": {
+ "int32Values": [1, 2, "Constants::HVAC_ALL"],
+ "int64Values": [1, 2],
+ "floatValues": [1.1, 2.2],
+ "stringValue": "test"
+ }
+ }
+ ]
+ }
+ ]
+}
+```
+
+## JSON Number-type Field Values
+
+For number type field values, they can either be defined as a numeric number,
+e.g., `{"minInt32Value": 1}` or be defined as a string which represents a
+defined constant value, e.g.,
+`{"property": "VehicleProperty::INFO_FUEL_CAPACITY"}`.
+
+For constant values, they must be a string in the format of `XXX::XXX`, where
+the field before `::` is the constant type, and the field after `::` is the
+variable name.
+
+We support the following constant types:
+
+* VehiclePropertyAccess
+
+* VehiclePropertyChangeMode
+
+* VehicleGear
+
+* VehicleAreaWindow
+
+* VehicleOilLevel
+
+* VehicleUnit
+
+* VehicleSeatOccupancyState
+
+* VehicleHvacFanDirection
+
+* VehicleApPowerStateReport
+
+* VehicleTurnSignal
+
+* VehicleVendorPermission
+
+* EvsServiceType
+
+* EvsServiceState
+
+* EvConnectorType
+
+* VehicleProperty
+
+* GsrComplianceRequirementType
+
+* VehicleIgnitionState
+
+* FuelType
+
+* Constants
+
+Every constant type except "Constants" corresponds to a enum defined in Vehicle
+HAL interfac. E.g. "VehicleProperty" corresponds to the enums defined in
+"VehicleProperty.aidl".
+
+"Constants" type refers to the constant variables defined in the paresr.
+Specifically, the "CONSTANTS_BY_NAME" map defined in "JsonConfigLoader.cpp".
diff --git a/automotive/vehicle/aidl/impl/default_config/include/DefaultConfig.h b/automotive/vehicle/aidl/impl/default_config/include/DefaultConfig.h
deleted file mode 100644
index 986d1a6..0000000
--- a/automotive/vehicle/aidl/impl/default_config/include/DefaultConfig.h
+++ /dev/null
@@ -1,1421 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef android_hardware_automotive_vehicle_aidl_impl_default_config_include_DefaultConfig_H_
-#define android_hardware_automotive_vehicle_aidl_impl_default_config_include_DefaultConfig_H_
-
-#include <PropertyUtils.h>
-#include <TestPropertyUtils.h>
-#include <VehicleHalTypes.h>
-
-#include <map>
-#include <vector>
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace vehicle {
-
-// Types used in configs, not to be exposed as public API.
-namespace defaultconfig_impl {
-
-using ::aidl::android::hardware::automotive::vehicle::EvConnectorType;
-using ::aidl::android::hardware::automotive::vehicle::EvsServiceState;
-using ::aidl::android::hardware::automotive::vehicle::EvsServiceType;
-using ::aidl::android::hardware::automotive::vehicle::FuelType;
-using ::aidl::android::hardware::automotive::vehicle::GsrComplianceRequirementType;
-using ::aidl::android::hardware::automotive::vehicle::RawPropValues;
-using ::aidl::android::hardware::automotive::vehicle::VehicleApPowerStateReport;
-using ::aidl::android::hardware::automotive::vehicle::VehicleApPowerStateReq;
-using ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig;
-using ::aidl::android::hardware::automotive::vehicle::VehicleAreaMirror;
-using ::aidl::android::hardware::automotive::vehicle::VehicleAreaWindow;
-using ::aidl::android::hardware::automotive::vehicle::VehicleGear;
-using ::aidl::android::hardware::automotive::vehicle::VehicleHvacFanDirection;
-using ::aidl::android::hardware::automotive::vehicle::VehicleIgnitionState;
-using ::aidl::android::hardware::automotive::vehicle::VehicleOilLevel;
-using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
-using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
-using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyAccess;
-using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyChangeMode;
-using ::aidl::android::hardware::automotive::vehicle::VehicleSeatOccupancyState;
-using ::aidl::android::hardware::automotive::vehicle::VehicleTurnSignal;
-using ::aidl::android::hardware::automotive::vehicle::VehicleUnit;
-using ::aidl::android::hardware::automotive::vehicle::VehicleVendorPermission;
-
-struct ConfigDeclaration {
- VehiclePropConfig config;
-
- // This value will be used as an initial value for the property. If this field is specified for
- // property that supports multiple areas then it will be used for all areas unless particular
- // area is overridden in initialAreaValue field.
- RawPropValues initialValue;
- // Use initialAreaValues if it is necessary to specify different values per each area.
- std::map<int32_t, RawPropValues> initialAreaValues;
-};
-
-const std::vector<ConfigDeclaration> kVehicleProperties = {
- {.config =
- {
- .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::STATIC,
- },
- .initialValue = {.floatValues = {15000.0f}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::INFO_FUEL_TYPE),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::STATIC,
- },
- .initialValue = {.int32Values = {toInt(FuelType::FUEL_TYPE_UNLEADED)}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::INFO_EV_BATTERY_CAPACITY),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::STATIC,
- },
- .initialValue = {.floatValues = {150000.0f}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::INFO_EV_CONNECTOR_TYPE),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::STATIC,
- },
- .initialValue = {.int32Values = {toInt(EvConnectorType::IEC_TYPE_1_AC)}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::INFO_FUEL_DOOR_LOCATION),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::STATIC,
- },
- .initialValue = {.int32Values = {FUEL_DOOR_REAR_LEFT}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::INFO_EV_PORT_LOCATION),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::STATIC,
- },
- .initialValue = {.int32Values = {CHARGE_PORT_FRONT_LEFT}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::INFO_MULTI_EV_PORT_LOCATIONS),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::STATIC,
- },
- .initialValue = {.int32Values = {CHARGE_PORT_FRONT_LEFT, CHARGE_PORT_REAR_LEFT}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::INFO_MAKE),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::STATIC,
- },
- .initialValue = {.stringValue = "Toy Vehicle"}},
- {.config =
- {
- .prop = toInt(VehicleProperty::INFO_MODEL),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::STATIC,
- },
- .initialValue = {.stringValue = "Speedy Model"}},
- {.config =
- {
- .prop = toInt(VehicleProperty::INFO_MODEL_YEAR),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::STATIC,
- },
- .initialValue = {.int32Values = {2020}}},
- {.config =
- {
- .prop = toInt(VehicleProperty::INFO_EXTERIOR_DIMENSIONS),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::STATIC,
- },
- .initialValue = {.int32Values = {1776, 4950, 2008, 2140, 2984, 1665, 1667, 11800}}},
- {.config =
- {
- .prop = toInt(VehicleProperty::PERF_VEHICLE_SPEED),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
- .minSampleRate = 1.0f,
- .maxSampleRate = 10.0f,
- },
- .initialValue = {.floatValues = {0.0f}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::VEHICLE_SPEED_DISPLAY_UNITS),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .configArray = {toInt(VehicleUnit::METER_PER_SEC),
- toInt(VehicleUnit::MILES_PER_HOUR),
- toInt(VehicleUnit::KILOMETERS_PER_HOUR)},
- },
- .initialValue = {.int32Values = {toInt(VehicleUnit::KILOMETERS_PER_HOUR)}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::EV_BATTERY_DISPLAY_UNITS),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .configArray = {toInt(VehicleUnit::WATT_HOUR),
- toInt(VehicleUnit::AMPERE_HOURS),
- toInt(VehicleUnit::KILOWATT_HOUR)},
- },
- .initialValue = {.int32Values = {toInt(VehicleUnit::KILOWATT_HOUR)}}},
-
- {.config = {.prop = toInt(VehicleProperty::SEAT_BELT_BUCKLED),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = SEAT_1_LEFT},
- VehicleAreaConfig{.areaId = SEAT_1_RIGHT},
- VehicleAreaConfig{.areaId = SEAT_2_LEFT},
- VehicleAreaConfig{.areaId = SEAT_2_RIGHT},
- VehicleAreaConfig{.areaId = SEAT_2_CENTER}}},
- .initialAreaValues = {{SEAT_1_LEFT, {.int32Values = {0}}},
- {SEAT_1_RIGHT, {.int32Values = {0}}},
- {SEAT_2_LEFT, {.int32Values = {0}}},
- {SEAT_2_RIGHT, {.int32Values = {0}}},
- {SEAT_2_CENTER, {.int32Values = {0}}}}},
-
- {.config = {.prop = toInt(VehicleProperty::SEAT_BELT_HEIGHT_POS),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = SEAT_1_LEFT,
- .minInt32Value = 0,
- .maxInt32Value = 10},
- VehicleAreaConfig{.areaId = SEAT_1_RIGHT,
- .minInt32Value = 0,
- .maxInt32Value = 10},
- VehicleAreaConfig{.areaId = SEAT_2_LEFT,
- .minInt32Value = 0,
- .maxInt32Value = 10},
- VehicleAreaConfig{.areaId = SEAT_2_RIGHT,
- .minInt32Value = 0,
- .maxInt32Value = 10},
- VehicleAreaConfig{.areaId = SEAT_2_CENTER,
- .minInt32Value = 0,
- .maxInt32Value = 10}}},
- .initialAreaValues = {{SEAT_1_LEFT, {.int32Values = {10}}},
- {SEAT_1_RIGHT, {.int32Values = {10}}},
- {SEAT_2_LEFT, {.int32Values = {10}}},
- {SEAT_2_RIGHT, {.int32Values = {10}}},
- {SEAT_2_CENTER, {.int32Values = {10}}}}},
-
- {.config = {.prop = toInt(VehicleProperty::SEAT_BELT_HEIGHT_MOVE),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = SEAT_1_LEFT,
- .minInt32Value = -1,
- .maxInt32Value = 1},
- VehicleAreaConfig{.areaId = SEAT_1_RIGHT,
- .minInt32Value = -1,
- .maxInt32Value = 1},
- VehicleAreaConfig{.areaId = SEAT_2_LEFT,
- .minInt32Value = -1,
- .maxInt32Value = 1},
- VehicleAreaConfig{.areaId = SEAT_2_RIGHT,
- .minInt32Value = -1,
- .maxInt32Value = 1},
- VehicleAreaConfig{.areaId = SEAT_2_CENTER,
- .minInt32Value = -1,
- .maxInt32Value = 1}}},
- .initialAreaValues = {{SEAT_1_LEFT, {.int32Values = {0}}},
- {SEAT_1_RIGHT, {.int32Values = {0}}},
- {SEAT_2_LEFT, {.int32Values = {0}}},
- {SEAT_2_RIGHT, {.int32Values = {0}}},
- {SEAT_2_CENTER, {.int32Values = {0}}}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::SEAT_OCCUPANCY),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (SEAT_1_LEFT)},
- VehicleAreaConfig{.areaId = (SEAT_1_RIGHT)}},
- },
- .initialAreaValues = {{SEAT_1_LEFT,
- {.int32Values = {toInt(VehicleSeatOccupancyState::VACANT)}}},
- {SEAT_1_RIGHT,
- {.int32Values = {toInt(VehicleSeatOccupancyState::VACANT)}}}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::INFO_DRIVER_SEAT),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::STATIC,
- // this was a zoned property on an old vhal, but it is meant to be global
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
- },
- .initialValue = {.int32Values = {SEAT_1_LEFT}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::PERF_ODOMETER),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
- .minSampleRate = 1.0f,
- .maxSampleRate = 10.0f,
- },
- .initialValue = {.floatValues = {0.0f}}},
- {.config =
- {
- .prop = toInt(VehicleProperty::PERF_STEERING_ANGLE),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
- .minSampleRate = 1.0f,
- .maxSampleRate = 10.0f,
- },
- .initialValue = {.floatValues = {0.0f}}},
- {.config =
- {
- .prop = toInt(VehicleProperty::PERF_REAR_STEERING_ANGLE),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
- .minSampleRate = 1.0f,
- .maxSampleRate = 10.0f,
- },
- .initialValue = {.floatValues = {0.0f}}},
- {
- .config =
- {
- .prop = toInt(VehicleProperty::ENGINE_RPM),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
- .minSampleRate = 1.0f,
- .maxSampleRate = 10.0f,
- },
- .initialValue = {.floatValues = {0.0f}},
- },
-
- {.config =
- {
- .prop = toInt(VehicleProperty::FUEL_LEVEL),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
- .minSampleRate = 1.0f,
- .maxSampleRate = 100.0f,
- },
- .initialValue = {.floatValues = {15000.0f}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::FUEL_DOOR_OPEN),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- .initialValue = {.int32Values = {0}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::EV_BATTERY_LEVEL),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
- .minSampleRate = 1.0f,
- .maxSampleRate = 100.0f,
- },
- .initialValue = {.floatValues = {150000.0f}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::EV_CHARGE_PORT_OPEN),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- .initialValue = {.int32Values = {0}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::EV_CHARGE_PORT_CONNECTED),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- .initialValue = {.int32Values = {0}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::EV_BATTERY_INSTANTANEOUS_CHARGE_RATE),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
- .minSampleRate = 1.0f,
- .maxSampleRate = 10.0f,
- },
- .initialValue = {.floatValues = {0.0f}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::EV_CHARGE_CURRENT_DRAW_LIMIT),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .configArray = {/*max current draw allowed by vehicle in amperes=*/20},
- },
- .initialValue = {.floatValues = {(float)12.5}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::EV_CHARGE_PERCENT_LIMIT),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .configArray = {20, 40, 60, 80, 100},
- },
- .initialValue = {.floatValues = {40}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::EV_CHARGE_STATE),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- .initialValue = {.int32Values = {2}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::EV_CHARGE_SWITCH),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- .initialValue = {.int32Values = {0 /* false */}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::EV_CHARGE_TIME_REMAINING),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
- .minSampleRate = 1.0f,
- .maxSampleRate = 10.0f,
- },
- .initialValue = {.int32Values = {20}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::EV_REGENERATIVE_BRAKING_STATE),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- .initialValue = {.int32Values = {2}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::TRAILER_PRESENT),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- .initialValue = {.int32Values = {2}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::VEHICLE_CURB_WEIGHT),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::STATIC,
- .configArray = {/*gross weight kg=*/2948},
- },
- .initialValue = {.int32Values = {2211 /*kg*/}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::RANGE_REMAINING),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
- .minSampleRate = 1.0f,
- .maxSampleRate = 2.0f,
- },
- .initialValue = {.floatValues = {50000.0f}}}, // units in meters
-
- {.config =
- {
- .prop = toInt(VehicleProperty::TIRE_PRESSURE),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
- .areaConfigs = {VehicleAreaConfig{
- .areaId = WHEEL_FRONT_LEFT,
- .minFloatValue = 193.0f,
- .maxFloatValue = 300.0f,
- },
- VehicleAreaConfig{
- .areaId = WHEEL_FRONT_RIGHT,
- .minFloatValue = 193.0f,
- .maxFloatValue = 300.0f,
- },
- VehicleAreaConfig{
- .areaId = WHEEL_REAR_LEFT,
- .minFloatValue = 193.0f,
- .maxFloatValue = 300.0f,
- },
- VehicleAreaConfig{
- .areaId = WHEEL_REAR_RIGHT,
- .minFloatValue = 193.0f,
- .maxFloatValue = 300.0f,
- }},
- .minSampleRate = 1.0f,
- .maxSampleRate = 2.0f,
- },
- .initialValue = {.floatValues = {200.0f}}}, // units in kPa
-
- {.config =
- {
- .prop = toInt(VehicleProperty::CRITICALLY_LOW_TIRE_PRESSURE),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::STATIC,
- .areaConfigs = {VehicleAreaConfig{.areaId = WHEEL_FRONT_LEFT},
- VehicleAreaConfig{.areaId = WHEEL_FRONT_RIGHT},
- VehicleAreaConfig{.areaId = WHEEL_REAR_RIGHT},
- VehicleAreaConfig{.areaId = WHEEL_REAR_LEFT}},
- },
- .initialAreaValues = {{WHEEL_FRONT_LEFT, {.floatValues = {137.0f}}},
- {WHEEL_FRONT_RIGHT, {.floatValues = {137.0f}}},
- {WHEEL_REAR_RIGHT, {.floatValues = {137.0f}}},
- {WHEEL_REAR_LEFT, {.floatValues = {137.0f}}}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::TIRE_PRESSURE_DISPLAY_UNITS),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .configArray = {toInt(VehicleUnit::KILOPASCAL), toInt(VehicleUnit::PSI),
- toInt(VehicleUnit::BAR)},
- },
- .initialValue = {.int32Values = {toInt(VehicleUnit::PSI)}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::CURRENT_GEAR),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .configArray = {toInt(VehicleGear::GEAR_PARK),
- toInt(VehicleGear::GEAR_NEUTRAL),
- toInt(VehicleGear::GEAR_REVERSE),
- toInt(VehicleGear::GEAR_1), toInt(VehicleGear::GEAR_2),
- toInt(VehicleGear::GEAR_3), toInt(VehicleGear::GEAR_4),
- toInt(VehicleGear::GEAR_5)},
- },
- .initialValue = {.int32Values = {toInt(VehicleGear::GEAR_PARK)}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::PARKING_BRAKE_ON),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- .initialValue = {.int32Values = {1}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::PARKING_BRAKE_AUTO_APPLY),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- .initialValue = {.int32Values = {1}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::FUEL_LEVEL_LOW),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- .initialValue = {.int32Values = {0}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::FUEL_VOLUME_DISPLAY_UNITS),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .configArray = {(int)VehicleUnit::LITER, (int)VehicleUnit::US_GALLON},
- },
- .initialValue = {.int32Values = {(int)VehicleUnit::LITER}}},
-
- {.config =
- {
- .prop = toInt(
- VehicleProperty::FUEL_CONSUMPTION_UNITS_DISTANCE_OVER_VOLUME),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- .initialValue = {.int32Values = {1}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::HW_KEY_INPUT),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- .initialValue = {.int32Values = {0, 0, 0}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::HW_ROTARY_INPUT),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- .initialValue = {.int32Values = {0, 0, 0}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::HW_CUSTOM_INPUT),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .configArray = {0, 0, 0, 3, 0, 0, 0, 0, 0},
- },
- .initialValue =
- {
- .int32Values = {0, 0, 0},
- }},
-
- {.config = {.prop = toInt(VehicleProperty::HVAC_POWER_ON),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}},
- // TODO(bryaneyler): Ideally, this is generated dynamically from
- // kHvacPowerProperties.
- .configArray = {toInt(VehicleProperty::HVAC_FAN_SPEED),
- toInt(VehicleProperty::HVAC_FAN_DIRECTION)}},
- .initialValue = {.int32Values = {1}}},
-
- {
- .config = {.prop = toInt(VehicleProperty::HVAC_DEFROSTER),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs =
- {VehicleAreaConfig{
- .areaId = toInt(VehicleAreaWindow::FRONT_WINDSHIELD)},
- VehicleAreaConfig{
- .areaId = toInt(VehicleAreaWindow::REAR_WINDSHIELD)}}},
- .initialValue = {.int32Values = {0}} // Will be used for all areas.
- },
- {
- .config = {.prop = toInt(VehicleProperty::HVAC_ELECTRIC_DEFROSTER_ON),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs =
- {VehicleAreaConfig{
- .areaId = toInt(VehicleAreaWindow::FRONT_WINDSHIELD)},
- VehicleAreaConfig{
- .areaId = toInt(VehicleAreaWindow::REAR_WINDSHIELD)}}},
- .initialValue = {.int32Values = {0}} // Will be used for all areas.
- },
-
- {.config = {.prop = toInt(VehicleProperty::HVAC_MAX_DEFROST_ON),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
- .initialValue = {.int32Values = {0}}},
-
- {.config = {.prop = toInt(VehicleProperty::HVAC_RECIRC_ON),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
- .initialValue = {.int32Values = {1}}},
-
- {.config = {.prop = toInt(VehicleProperty::HVAC_AUTO_RECIRC_ON),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
- .initialValue = {.int32Values = {0}}},
-
- {.config = {.prop = toInt(VehicleProperty::HVAC_AC_ON),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
- .initialValue = {.int32Values = {1}}},
-
- {.config = {.prop = toInt(VehicleProperty::HVAC_MAX_AC_ON),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
- .initialValue = {.int32Values = {0}}},
-
- {.config = {.prop = toInt(VehicleProperty::HVAC_AUTO_ON),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
- .initialValue = {.int32Values = {1}}},
-
- {.config = {.prop = toInt(VehicleProperty::HVAC_DUAL_ON),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
- .initialValue = {.int32Values = {0}}},
-
- {.config = {.prop = toInt(VehicleProperty::HVAC_FAN_SPEED),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{
- .areaId = HVAC_ALL, .minInt32Value = 1, .maxInt32Value = 7}}},
- .initialValue = {.int32Values = {3}}},
-
- {.config = {.prop = toInt(VehicleProperty::HVAC_FAN_DIRECTION),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
- .initialValue = {.int32Values = {toInt(VehicleHvacFanDirection::FACE)}}},
-
- {.config = {.prop = toInt(VehicleProperty::HVAC_FAN_DIRECTION_AVAILABLE),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::STATIC,
- .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
- .initialValue = {.int32Values = {FAN_DIRECTION_FACE, FAN_DIRECTION_FLOOR,
- FAN_DIRECTION_FACE | FAN_DIRECTION_FLOOR,
- FAN_DIRECTION_DEFROST,
- FAN_DIRECTION_FACE | FAN_DIRECTION_DEFROST,
- FAN_DIRECTION_FLOOR | FAN_DIRECTION_DEFROST,
- FAN_DIRECTION_FLOOR | FAN_DIRECTION_DEFROST |
- FAN_DIRECTION_FACE}}},
- {.config = {.prop = toInt(VehicleProperty::HVAC_SEAT_VENTILATION),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{
- .areaId = SEAT_1_LEFT,
- .minInt32Value = 0,
- .maxInt32Value = 3,
- },
- VehicleAreaConfig{
- .areaId = SEAT_1_RIGHT,
- .minInt32Value = 0,
- .maxInt32Value = 3,
- }}},
- .initialValue =
- {.int32Values = {0}}}, // 0 is off and +ve values indicate ventilation level.
-
- {.config = {.prop = toInt(VehicleProperty::HVAC_STEERING_WHEEL_HEAT),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{
- .areaId = (0), .minInt32Value = -2, .maxInt32Value = 2}}},
- .initialValue = {.int32Values = {0}}}, // +ve values for heating and -ve for cooling
-
- {.config = {.prop = toInt(VehicleProperty::HVAC_SEAT_TEMPERATURE),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{
- .areaId = SEAT_1_LEFT,
- .minInt32Value = -2,
- .maxInt32Value = 2,
- },
- VehicleAreaConfig{
- .areaId = SEAT_1_RIGHT,
- .minInt32Value = -2,
- .maxInt32Value = 2,
- }}},
- .initialValue = {.int32Values = {0}}}, // +ve values for heating and -ve for cooling
-
- {.config = {.prop = toInt(VehicleProperty::HVAC_SIDE_MIRROR_HEAT),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{
- .areaId = toInt(VehicleAreaMirror::DRIVER_LEFT) |
- toInt(VehicleAreaMirror::DRIVER_RIGHT),
- .minInt32Value = 0,
- .maxInt32Value = 2,
- }}},
- .initialValue = {.int32Values = {0}}},
-
- {.config = {.prop = toInt(VehicleProperty::HVAC_TEMPERATURE_SET),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .configArray = {160, 280, 5, 605, 825, 10},
- .areaConfigs = {VehicleAreaConfig{
- .areaId = HVAC_LEFT,
- .minFloatValue = 16,
- .maxFloatValue = 32,
- },
- VehicleAreaConfig{
- .areaId = HVAC_RIGHT,
- .minFloatValue = 16,
- .maxFloatValue = 32,
- }}},
- .initialAreaValues = {{HVAC_LEFT, {.floatValues = {16}}},
- {HVAC_RIGHT, {.floatValues = {20}}}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::HVAC_TEMPERATURE_VALUE_SUGGESTION),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- .initialValue = {.floatValues = {66.2f, (float)VehicleUnit::FAHRENHEIT, 19.0f, 66.5f}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::ENV_OUTSIDE_TEMPERATURE),
- .access = VehiclePropertyAccess::READ,
- // TODO(bryaneyler): Support ON_CHANGE as well.
- .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
- .minSampleRate = 1.0f,
- .maxSampleRate = 2.0f,
- },
- .initialValue = {.floatValues = {25.0f}}},
-
- {.config = {.prop = toInt(VehicleProperty::HVAC_TEMPERATURE_DISPLAY_UNITS),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .configArray = {toInt(VehicleUnit::FAHRENHEIT), toInt(VehicleUnit::CELSIUS)}},
- .initialValue = {.int32Values = {toInt(VehicleUnit::FAHRENHEIT)}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::DISTANCE_DISPLAY_UNITS),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
- .configArray = {toInt(VehicleUnit::KILOMETER), toInt(VehicleUnit::MILE)},
- },
- .initialValue = {.int32Values = {toInt(VehicleUnit::MILE)}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::NIGHT_MODE),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- .initialValue = {.int32Values = {0}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::GEAR_SELECTION),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .configArray = {toInt(VehicleGear::GEAR_PARK),
- toInt(VehicleGear::GEAR_NEUTRAL),
- toInt(VehicleGear::GEAR_REVERSE),
- toInt(VehicleGear::GEAR_DRIVE), toInt(VehicleGear::GEAR_1),
- toInt(VehicleGear::GEAR_2), toInt(VehicleGear::GEAR_3),
- toInt(VehicleGear::GEAR_4), toInt(VehicleGear::GEAR_5)},
- },
- .initialValue = {.int32Values = {toInt(VehicleGear::GEAR_PARK)}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::TURN_SIGNAL_STATE),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- .initialValue = {.int32Values = {toInt(VehicleTurnSignal::NONE)}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::IGNITION_STATE),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- .initialValue = {.int32Values = {toInt(VehicleIgnitionState::ON)}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::ENGINE_COOLANT_TEMP),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
- .minSampleRate = 1.0f,
- .maxSampleRate = 10.0f,
- },
- .initialValue = {.floatValues = {75.0f}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::ENGINE_OIL_LEVEL),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- .initialValue = {.int32Values = {toInt(VehicleOilLevel::NORMAL)}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::ENGINE_OIL_TEMP),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
- .minSampleRate = 0.1, // 0.1 Hz, every 10 seconds
- .maxSampleRate = 10, // 10 Hz, every 100 ms
- },
- .initialValue = {.floatValues = {101.0f}}},
-
- {
- .config = {.prop = kMixedTypePropertyForTest,
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .configArray = {1, 1, 0, 2, 0, 0, 1, 0, 0}},
- .initialValue =
- {
- .int32Values = {1 /* indicate TRUE boolean value */, 2, 3},
- .floatValues = {4.5f},
- .stringValue = "MIXED property",
- },
- },
-
- {.config = {.prop = toInt(VehicleProperty::DOOR_LOCK),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = DOOR_1_LEFT},
- VehicleAreaConfig{.areaId = DOOR_1_RIGHT},
- VehicleAreaConfig{.areaId = DOOR_2_LEFT},
- VehicleAreaConfig{.areaId = DOOR_2_RIGHT}}},
- .initialAreaValues = {{DOOR_1_LEFT, {.int32Values = {1}}},
- {DOOR_1_RIGHT, {.int32Values = {1}}},
- {DOOR_2_LEFT, {.int32Values = {1}}},
- {DOOR_2_RIGHT, {.int32Values = {1}}}}},
-
- {.config = {.prop = toInt(VehicleProperty::DOOR_POS),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs =
- {VehicleAreaConfig{
- .areaId = DOOR_1_LEFT, .minInt32Value = 0, .maxInt32Value = 1},
- VehicleAreaConfig{.areaId = DOOR_1_RIGHT,
- .minInt32Value = 0,
- .maxInt32Value = 1},
- VehicleAreaConfig{
- .areaId = DOOR_2_LEFT, .minInt32Value = 0, .maxInt32Value = 1},
- VehicleAreaConfig{.areaId = DOOR_2_RIGHT,
- .minInt32Value = 0,
- .maxInt32Value = 1},
- VehicleAreaConfig{
- .areaId = DOOR_REAR, .minInt32Value = 0, .maxInt32Value = 1}}},
- .initialValue = {.int32Values = {0}}},
-
- {.config = {.prop = toInt(VehicleProperty::WINDOW_LOCK),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = WINDOW_1_RIGHT | WINDOW_2_LEFT |
- WINDOW_2_RIGHT}}},
- .initialAreaValues = {{WINDOW_1_RIGHT | WINDOW_2_LEFT | WINDOW_2_RIGHT,
- {.int32Values = {0}}}}},
-
- {.config = {.prop = toInt(VehicleProperty::WINDOW_POS),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = WINDOW_1_LEFT,
- .minInt32Value = 0,
- .maxInt32Value = 10},
- VehicleAreaConfig{.areaId = WINDOW_1_RIGHT,
- .minInt32Value = 0,
- .maxInt32Value = 10},
- VehicleAreaConfig{.areaId = WINDOW_2_LEFT,
- .minInt32Value = 0,
- .maxInt32Value = 10},
- VehicleAreaConfig{.areaId = WINDOW_2_RIGHT,
- .minInt32Value = 0,
- .maxInt32Value = 10},
- VehicleAreaConfig{.areaId = WINDOW_ROOF_TOP_1,
- .minInt32Value = -10,
- .maxInt32Value = 10}}},
- .initialValue = {.int32Values = {0}}},
-
- {.config =
- {
- .prop = WHEEL_TICK,
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
- .configArray = {ALL_WHEELS, 50000, 50000, 50000, 50000},
- .minSampleRate = 1.0f,
- .maxSampleRate = 10.0f,
- },
- .initialValue = {.int64Values = {0, 100000, 200000, 300000, 400000}}},
-
- {.config = {.prop = ABS_ACTIVE,
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE},
- .initialValue = {.int32Values = {0}}},
-
- {.config = {.prop = TRACTION_CONTROL_ACTIVE,
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE},
- .initialValue = {.int32Values = {0}}},
-
- {.config = {.prop = toInt(VehicleProperty::AP_POWER_STATE_REQ),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .configArray = {0}}},
-
- {.config = {.prop = toInt(VehicleProperty::AP_POWER_STATE_REPORT),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE},
- .initialValue = {.int32Values = {toInt(VehicleApPowerStateReport::WAIT_FOR_VHAL), 0}}},
-
- {.config = {.prop = toInt(VehicleProperty::DISPLAY_BRIGHTNESS),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.minInt32Value = 0, .maxInt32Value = 100}}},
- .initialValue = {.int32Values = {100}}},
-
- {
- .config = {.prop = OBD2_LIVE_FRAME,
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .configArray = {0, 0}},
- },
-
- {
- .config = {.prop = OBD2_FREEZE_FRAME,
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .configArray = {0, 0}},
- },
-
- {
- .config = {.prop = OBD2_FREEZE_FRAME_INFO,
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE},
- },
-
- {
- .config = {.prop = OBD2_FREEZE_FRAME_CLEAR,
- .access = VehiclePropertyAccess::WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .configArray = {1}},
- },
-
- {.config =
- {
- .prop = toInt(VehicleProperty::HEADLIGHTS_STATE),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- .initialValue = {.int32Values = {LIGHT_STATE_ON}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::HIGH_BEAM_LIGHTS_STATE),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- .initialValue = {.int32Values = {LIGHT_STATE_ON}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::FRONT_FOG_LIGHTS_STATE),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- .initialValue = {.int32Values = {LIGHT_STATE_ON}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::REAR_FOG_LIGHTS_STATE),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- .initialValue = {.int32Values = {LIGHT_STATE_ON}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::HAZARD_LIGHTS_STATE),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- .initialValue = {.int32Values = {LIGHT_STATE_ON}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::HEADLIGHTS_SWITCH),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- .initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::HIGH_BEAM_LIGHTS_SWITCH),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- .initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}},
-
- // FOG_LIGHTS_SWITCH must not be implemented when FRONT_FOG_LIGHTS_SWITCH is implemented
- {.config =
- {
- .prop = toInt(VehicleProperty::FRONT_FOG_LIGHTS_SWITCH),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- .initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}},
-
- // FOG_LIGHTS_SWITCH must not be implemented when REAR_FOG_LIGHTS_SWITCH is implemented
- {.config =
- {
- .prop = toInt(VehicleProperty::REAR_FOG_LIGHTS_SWITCH),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- .initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::HAZARD_LIGHTS_SWITCH),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- .initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::EVS_SERVICE_REQUEST),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- .initialValue = {.int32Values = {toInt(EvsServiceType::REARVIEW),
- toInt(EvsServiceState::OFF)}}},
-
- {.config = {.prop = VEHICLE_MAP_SERVICE,
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE}},
-
- // Example Vendor Extension properties for testing
- {.config = {.prop = VENDOR_EXTENSION_BOOLEAN_PROPERTY,
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = DOOR_1_LEFT},
- VehicleAreaConfig{.areaId = DOOR_1_RIGHT},
- VehicleAreaConfig{.areaId = DOOR_2_LEFT},
- VehicleAreaConfig{.areaId = DOOR_2_RIGHT}}},
- .initialAreaValues = {{DOOR_1_LEFT, {.int32Values = {1}}},
- {DOOR_1_RIGHT, {.int32Values = {1}}},
- {DOOR_2_LEFT, {.int32Values = {0}}},
- {DOOR_2_RIGHT, {.int32Values = {0}}}}},
-
- {.config = {.prop = VENDOR_EXTENSION_FLOAT_PROPERTY,
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_LEFT,
- .minFloatValue = -10,
- .maxFloatValue = 10},
- VehicleAreaConfig{.areaId = HVAC_RIGHT,
- .minFloatValue = -10,
- .maxFloatValue = 10}}},
- .initialAreaValues = {{HVAC_LEFT, {.floatValues = {1}}},
- {HVAC_RIGHT, {.floatValues = {2}}}}},
-
- {.config = {.prop = VENDOR_EXTENSION_INT_PROPERTY,
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs =
- {VehicleAreaConfig{.areaId = toInt(VehicleAreaWindow::FRONT_WINDSHIELD),
- .minInt32Value = -100,
- .maxInt32Value = 100},
- VehicleAreaConfig{.areaId = toInt(VehicleAreaWindow::REAR_WINDSHIELD),
- .minInt32Value = -100,
- .maxInt32Value = 100},
- VehicleAreaConfig{.areaId = toInt(VehicleAreaWindow::ROOF_TOP_1),
- .minInt32Value = -100,
- .maxInt32Value = 100}}},
- .initialAreaValues = {{toInt(VehicleAreaWindow::FRONT_WINDSHIELD), {.int32Values = {1}}},
- {toInt(VehicleAreaWindow::REAR_WINDSHIELD), {.int32Values = {0}}},
- {toInt(VehicleAreaWindow::ROOF_TOP_1), {.int32Values = {-1}}}}},
-
- {.config = {.prop = VENDOR_EXTENSION_STRING_PROPERTY,
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE},
- .initialValue = {.stringValue = "Vendor String Property"}},
-
- {.config = {.prop = toInt(VehicleProperty::ELECTRONIC_TOLL_COLLECTION_CARD_TYPE),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE},
- .initialValue = {.int32Values = {0}}},
-
- {.config = {.prop = toInt(VehicleProperty::ELECTRONIC_TOLL_COLLECTION_CARD_STATUS),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE},
- .initialValue = {.int32Values = {0}}},
-
- {.config =
- {
- .prop = toInt(VehicleProperty::SUPPORT_CUSTOMIZE_VENDOR_PERMISSION),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .configArray = {kMixedTypePropertyForTest,
- toInt(VehicleVendorPermission::
- PERMISSION_GET_VENDOR_CATEGORY_INFO),
- toInt(VehicleVendorPermission::
- PERMISSION_SET_VENDOR_CATEGORY_INFO),
- VENDOR_EXTENSION_INT_PROPERTY,
- toInt(VehicleVendorPermission::
- PERMISSION_GET_VENDOR_CATEGORY_SEAT),
- toInt(VehicleVendorPermission::PERMISSION_NOT_ACCESSIBLE),
- VENDOR_EXTENSION_FLOAT_PROPERTY,
- toInt(VehicleVendorPermission::PERMISSION_DEFAULT),
- toInt(VehicleVendorPermission::PERMISSION_DEFAULT)},
- },
- .initialValue = {.int32Values = {1}}},
-
- {
- .config =
- {
- .prop = toInt(VehicleProperty::INITIAL_USER_INFO),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- },
- {
- .config =
- {
- .prop = toInt(VehicleProperty::SWITCH_USER),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- },
- {
- .config =
- {
- .prop = toInt(VehicleProperty::CREATE_USER),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- },
- {
- .config =
- {
- .prop = toInt(VehicleProperty::REMOVE_USER),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- },
- {
- .config =
- {
- .prop = toInt(VehicleProperty::USER_IDENTIFICATION_ASSOCIATION),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- },
- {
- .config =
- {
- .prop = toInt(VehicleProperty::POWER_POLICY_REQ),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- },
- {
- .config =
- {
- .prop = toInt(VehicleProperty::POWER_POLICY_GROUP_REQ),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- },
- {
- .config =
- {
- .prop = toInt(VehicleProperty::CURRENT_POWER_POLICY),
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- },
- {
- .config =
- {
- .prop = toInt(VehicleProperty::ANDROID_EPOCH_TIME),
- .access = VehiclePropertyAccess::WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- },
- {
- .config =
- {
- .prop = toInt(VehicleProperty::WATCHDOG_ALIVE),
- .access = VehiclePropertyAccess::WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- },
- {
- .config =
- {
- .prop = toInt(VehicleProperty::WATCHDOG_TERMINATED_PROCESS),
- .access = VehiclePropertyAccess::WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- },
- {
- .config =
- {
- .prop = toInt(VehicleProperty::VHAL_HEARTBEAT),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- },
- {
- .config =
- {
- .prop = toInt(VehicleProperty::CLUSTER_SWITCH_UI),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- .initialValue = {.int32Values = {0 /* ClusterHome */}},
- },
- {
- .config =
- {
- .prop = toInt(VehicleProperty::CLUSTER_DISPLAY_STATE),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- .initialValue = {.int32Values = {0 /* Off */, -1, -1, -1, -1 /* Bounds */, -1, -1,
- -1, -1 /* Insets */}},
- },
- {
- .config =
- {
- .prop = toInt(VehicleProperty::CLUSTER_REPORT_STATE),
- .access = VehiclePropertyAccess::WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .configArray = {0, 0, 0, 11, 0, 0, 0, 0, 16},
- },
- },
- {
- .config =
- {
- .prop = toInt(VehicleProperty::CLUSTER_REQUEST_DISPLAY),
- .access = VehiclePropertyAccess::WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- },
- {
- .config =
- {
- .prop = toInt(VehicleProperty::CLUSTER_NAVIGATION_STATE),
- .access = VehiclePropertyAccess::WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- },
- {
- .config =
- {
- .prop = PLACEHOLDER_PROPERTY_INT,
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- .initialValue = {.int32Values = {0}},
- },
- {
- .config =
- {
- .prop = PLACEHOLDER_PROPERTY_FLOAT,
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- .initialValue = {.floatValues = {0.0f}},
- },
- {
- .config =
- {
- .prop = PLACEHOLDER_PROPERTY_BOOLEAN,
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- .initialValue = {.int32Values = {0 /* false */}},
- },
- {
- .config =
- {
- .prop = PLACEHOLDER_PROPERTY_STRING,
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- .initialValue = {.stringValue = {"Test"}},
- },
- {
- .config =
- {
- .prop = ECHO_REVERSE_BYTES,
- .access = VehiclePropertyAccess::READ_WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- },
- {
- .config =
- {
- .prop = toInt(
- VehicleProperty::
- GENERAL_SAFETY_REGULATION_COMPLIANCE_REQUIREMENT),
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::STATIC,
- },
- .initialValue = {.int32Values = {toInt(
- GsrComplianceRequirementType::
- GSR_COMPLIANCE_REQUIRED_THROUGH_SYSTEM_IMAGE)}},
- },
-#ifdef ENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING
- // Vendor propetry for E2E ClusterHomeService testing.
- {
- .config =
- {
- .prop = VENDOR_CLUSTER_SWITCH_UI,
- .access = VehiclePropertyAccess::WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- },
- {
- .config =
- {
- .prop = VENDOR_CLUSTER_DISPLAY_STATE,
- .access = VehiclePropertyAccess::WRITE,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- },
- {
- .config =
- {
- .prop = VENDOR_CLUSTER_REPORT_STATE,
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .configArray = {0, 0, 0, 11, 0, 0, 0, 0, 16},
- },
- .initialValue = {.int32Values = {0 /* Off */, -1, -1, -1, -1 /* Bounds */, -1, -1,
- -1, -1 /* Insets */, 0 /* ClusterHome */,
- -1 /* ClusterNone */}},
- },
- {
- .config =
- {
- .prop = VENDOR_CLUSTER_REQUEST_DISPLAY,
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- .initialValue = {.int32Values = {0 /* ClusterHome */}},
- },
- {
- .config =
- {
- .prop = VENDOR_CLUSTER_NAVIGATION_STATE,
- .access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- },
- },
-#endif // ENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING
-};
-
-} // namespace defaultconfig_impl
-
-// public namespace
-namespace defaultconfig {
-
-typedef defaultconfig_impl::ConfigDeclaration ConfigDeclaration;
-
-inline constexpr const std::vector<ConfigDeclaration>& getDefaultConfigs() {
- return defaultconfig_impl::kVehicleProperties;
-}
-
-} // namespace defaultconfig
-
-} // namespace vehicle
-} // namespace automotive
-} // namespace hardware
-} // namespace android
-
-#endif // android_hardware_automotive_vehicle_aidl_impl_default_config_include_DefaultConfig_H_
diff --git a/automotive/vehicle/aidl/impl/default_config/test/Android.bp b/automotive/vehicle/aidl/impl/default_config/test/Android.bp
index 771472c..8702eae 100644
--- a/automotive/vehicle/aidl/impl/default_config/test/Android.bp
+++ b/automotive/vehicle/aidl/impl/default_config/test/Android.bp
@@ -24,11 +24,47 @@
defaults: ["VehicleHalDefaults"],
srcs: ["*.cpp"],
static_libs: [
+ "VehicleHalJsonConfigLoader",
"VehicleHalUtils",
+ "libgmock",
"libgtest",
],
header_libs: [
- "VehicleHalDefaultConfig",
+ "IVehicleGeneratedHeaders",
+ ],
+ shared_libs: [
+ "libjsoncpp",
+ ],
+ data: [
+ ":VehicleHalDefaultProperties_JSON",
+ ],
+ test_suites: ["device-tests"],
+}
+
+cc_test {
+ name: "VehicleHalDefaultConfigTestEnableTestProperties",
+ vendor: true,
+ defaults: ["VehicleHalDefaults"],
+ srcs: ["*.cpp"],
+ static_libs: [
+ "VehicleHalJsonConfigLoaderEnableTestProperties",
+ "VehicleHalUtils",
+ "libgmock",
+ "libgtest",
+ ],
+ cflags: [
+ "-DENABLE_VEHICLE_HAL_TEST_PROPERTIES",
+ ],
+ header_libs: [
+ "IVehicleGeneratedHeaders",
+ ],
+ shared_libs: [
+ "libjsoncpp",
+ ],
+ data: [
+ ":VehicleHalDefaultProperties_JSON",
+ ":VehicleHalTestProperties_JSON",
+ ":VehicleHalVendorClusterTestProperties_JSON",
],
test_suites: ["device-tests"],
}
diff --git a/automotive/vehicle/aidl/impl/default_config/test/DefaultConfigTest.cpp b/automotive/vehicle/aidl/impl/default_config/test/DefaultConfigTest.cpp
index baaae75..95fecfe 100644
--- a/automotive/vehicle/aidl/impl/default_config/test/DefaultConfigTest.cpp
+++ b/automotive/vehicle/aidl/impl/default_config/test/DefaultConfigTest.cpp
@@ -14,27 +14,75 @@
* limitations under the License.
*/
-#include <DefaultConfig.h>
+#include <JsonConfigLoader.h>
#include <VehicleUtils.h>
+#include <android-base/file.h>
+#include <gmock/gmock.h>
#include <gtest/gtest.h>
+#include <fstream>
+#include <unordered_map>
namespace android {
namespace hardware {
namespace automotive {
namespace vehicle {
-namespace defaultconfig {
namespace test {
-TEST(DefaultConfigTest, loadDefaultConfigs) {
- for (ConfigDeclaration config : getDefaultConfigs()) {
- ASSERT_NE(0, config.config.prop);
- }
+using ::android::base::Error;
+using ::android::base::Result;
+using ::testing::UnorderedElementsAreArray;
+
+constexpr char kDefaultPropertiesConfigFile[] = "DefaultProperties.json";
+
+#ifdef ENABLE_VEHICLE_HAL_TEST_PROPERTIES
+constexpr char kTestPropertiesConfigFile[] = "TestProperties.json";
+constexpr char kVendorClusterTestPropertiesConfigFile[] = "VendorClusterTestProperties.json";
+#endif // ENABLE_VEHICLE_HAL_TEST_PROPERTIES
+
+std::string getTestFilePath(const char* filename) {
+ static std::string baseDir = android::base::GetExecutableDirectory();
+ return baseDir + "/" + filename;
}
+Result<std::unordered_map<int32_t, ConfigDeclaration>> loadConfig(JsonConfigLoader& loader,
+ const char* path) {
+ std::string configPath = getTestFilePath(path);
+ std::ifstream ifs(configPath.c_str());
+ if (!ifs) {
+ return Error() << "couldn't open %s for parsing." << configPath;
+ }
+
+ return loader.loadPropConfig(ifs);
+}
+
+TEST(DefaultConfigTest, TestloadDefaultProperties) {
+ JsonConfigLoader loader;
+ auto result = loadConfig(loader, kDefaultPropertiesConfigFile);
+
+ ASSERT_TRUE(result.ok()) << result.error().message();
+}
+
+#ifdef ENABLE_VEHICLE_HAL_TEST_PROPERTIES
+
+TEST(DefaultConfigTest, TestloadTestProperties) {
+ JsonConfigLoader loader;
+ auto result = loadConfig(loader, kTestPropertiesConfigFile);
+
+ ASSERT_TRUE(result.ok()) << result.error().message();
+}
+
+TEST(DefaultConfigTest, TestloadVendorClusterTestProperties) {
+ JsonConfigLoader loader;
+ auto result = loadConfig(loader, kVendorClusterTestPropertiesConfigFile);
+
+ ASSERT_TRUE(result.ok()) << result.error().message();
+}
+
+#endif // ENABLE_VEHICLE_HAL_TEST_PROPERTIES
+
} // namespace test
-} // namespace defaultconfig
} // namespace vehicle
} // namespace automotive
} // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/Android.bp b/automotive/vehicle/aidl/impl/fake_impl/hardware/Android.bp
index dcd9208..4c17cde 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/Android.bp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/Android.bp
@@ -24,6 +24,7 @@
srcs: ["src/*.cpp"],
local_include_dirs: ["include"],
export_include_dirs: ["include"],
+ cflags: ["-DENABLE_VEHICLE_HAL_TEST_PROPERTIES"],
defaults: [
"VehicleHalDefaults",
"FakeVehicleHardwareDefaults",
@@ -32,18 +33,23 @@
cc_defaults {
name: "FakeVehicleHardwareDefaults",
- cflags: ["-DENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING"],
header_libs: [
"IVehicleHardware",
- "VehicleHalDefaultConfig",
+ "VehicleHalTestUtilHeaders",
],
export_header_lib_headers: ["IVehicleHardware"],
static_libs: [
+ "VehicleHalJsonConfigLoaderEnableTestProperties",
"VehicleHalUtils",
"FakeVehicleHalValueGenerators",
"FakeObd2Frame",
"FakeUserHal",
],
+ required: [
+ "Prebuilt_VehicleHalDefaultProperties_JSON",
+ "Prebuilt_VehicleHalTestProperties_JSON",
+ "Prebuilt_VehicleHalVendorClusterTestProperties_JSON",
+ ],
shared_libs: [
"libjsoncpp",
],
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
index 8cc19b1..1636cb6 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
@@ -18,11 +18,12 @@
#define android_hardware_automotive_vehicle_aidl_impl_fake_impl_hardware_include_FakeVehicleHardware_H_
#include <ConcurrentQueue.h>
-#include <DefaultConfig.h>
+#include <ConfigDeclaration.h>
#include <FakeObd2Frame.h>
#include <FakeUserHal.h>
#include <GeneratorHub.h>
#include <IVehicleHardware.h>
+#include <JsonConfigLoader.h>
#include <RecurrentTimer.h>
#include <VehicleHalTypes.h>
#include <VehiclePropertyStore.h>
@@ -32,9 +33,9 @@
#include <android-base/stringprintf.h>
#include <android-base/thread_annotations.h>
-#include <map>
#include <memory>
#include <mutex>
+#include <unordered_map>
#include <vector>
namespace android {
@@ -49,7 +50,8 @@
FakeVehicleHardware();
- explicit FakeVehicleHardware(std::unique_ptr<VehiclePropValuePool> valuePool);
+ FakeVehicleHardware(std::string defaultConfigDir, std::string overrideConfigDir,
+ bool forceOverride);
~FakeVehicleHardware();
@@ -151,17 +153,23 @@
aidl::android::hardware::automotive::vehicle::SetValueRequest>
mPendingSetValueRequests;
+ const std::string mDefaultConfigDir;
+ const std::string mOverrideConfigDir;
+ const bool mForceOverride;
+
+ // Only used during initialization.
+ JsonConfigLoader mLoader;
+
void init();
// Stores the initial value to property store.
- void storePropInitialValue(const defaultconfig::ConfigDeclaration& config);
+ void storePropInitialValue(const ConfigDeclaration& config);
// The callback that would be called when a vehicle property value change happens.
void onValueChangeCallback(
const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value);
- // If property "persist.vendor.vhal_init_value_override" is set to true, override the properties
- // using config files in 'overrideDir'.
- void maybeOverrideProperties(const char* overrideDir);
- // Override the properties using config files in 'overrideDir'.
- void overrideProperties(const char* overrideDir);
+ // Load the config files in format '*.json' from the directory and parse the config files
+ // into a map from property ID to ConfigDeclarations.
+ void loadPropConfigsFromDir(const std::string& dirPath,
+ std::unordered_map<int32_t, ConfigDeclaration>* configs);
// Function to be called when a value change event comes from vehicle bus. In our fake
// implementation, this function is only called during "--inject-event" dump command.
void eventFromVehicleBus(
@@ -185,6 +193,8 @@
const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value) const;
bool isHvacPropAndHvacNotAvailable(int32_t propId);
+ std::unordered_map<int32_t, ConfigDeclaration> loadConfigDeclarations();
+
std::string dumpAllProperties();
std::string dumpOnePropertyByConfig(
int rowNumber,
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
index 7c451fe..d87e5aa 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
@@ -19,7 +19,6 @@
#include "FakeVehicleHardware.h"
-#include <DefaultConfig.h>
#include <FakeObd2Frame.h>
#include <JsonFakeValueGenerator.h>
#include <LinearFakeValueGenerator.h>
@@ -27,6 +26,8 @@
#include <TestPropertyUtils.h>
#include <VehicleHalTypes.h>
#include <VehicleUtils.h>
+
+#include <android-base/file.h>
#include <android-base/parsedouble.h>
#include <android-base/properties.h>
#include <android-base/strings.h>
@@ -74,9 +75,16 @@
using ::android::base::StartsWith;
using ::android::base::StringPrintf;
-const char* VENDOR_OVERRIDE_DIR = "/vendor/etc/automotive/vhaloverride/";
-const char* OVERRIDE_PROPERTY = "persist.vendor.vhal_init_value_override";
-const char* POWER_STATE_REQ_CONFIG_PROPERTY = "ro.vendor.fake_vhal.ap_power_state_req.config";
+// The directory for default property configuration file.
+// For config file format, see impl/default_config/config/README.md.
+constexpr char DEFAULT_CONFIG_DIR[] = "/vendor/etc/automotive/vhalconfig/";
+// The directory for property configuration file that overrides the default configuration file.
+// For config file format, see impl/default_config/config/README.md.
+constexpr char OVERRIDE_CONFIG_DIR[] = "/vendor/etc/automotive/vhaloverride/";
+// If OVERRIDE_PROPERTY is set, we will use the configuration files from OVERRIDE_CONFIG_DIR to
+// overwrite the default configs.
+constexpr char OVERRIDE_PROPERTY[] = "persist.vendor.vhal_init_value_override";
+constexpr char POWER_STATE_REQ_CONFIG_PROPERTY[] = "ro.vendor.fake_vhal.ap_power_state_req.config";
// A list of supported options for "--set" command.
const std::unordered_set<std::string> SET_PROP_OPTIONS = {
@@ -97,7 +105,7 @@
} // namespace
-void FakeVehicleHardware::storePropInitialValue(const defaultconfig::ConfigDeclaration& config) {
+void FakeVehicleHardware::storePropInitialValue(const ConfigDeclaration& config) {
const VehiclePropConfig& vehiclePropConfig = config.config;
int propId = vehiclePropConfig.prop;
@@ -139,10 +147,11 @@
}
FakeVehicleHardware::FakeVehicleHardware()
- : FakeVehicleHardware(std::make_unique<VehiclePropValuePool>()) {}
+ : FakeVehicleHardware(DEFAULT_CONFIG_DIR, OVERRIDE_CONFIG_DIR, false) {}
-FakeVehicleHardware::FakeVehicleHardware(std::unique_ptr<VehiclePropValuePool> valuePool)
- : mValuePool(std::move(valuePool)),
+FakeVehicleHardware::FakeVehicleHardware(std::string defaultConfigDir,
+ std::string overrideConfigDir, bool forceOverride)
+ : mValuePool(std::make_unique<VehiclePropValuePool>()),
mServerSidePropStore(new VehiclePropertyStore(mValuePool)),
mFakeObd2Frame(new obd2frame::FakeObd2Frame(mServerSidePropStore)),
mFakeUserHal(new FakeUserHal(mValuePool)),
@@ -150,7 +159,10 @@
mGeneratorHub(new GeneratorHub(
[this](const VehiclePropValue& value) { eventFromVehicleBus(value); })),
mPendingGetValueRequests(this),
- mPendingSetValueRequests(this) {
+ mPendingSetValueRequests(this),
+ mDefaultConfigDir(defaultConfigDir),
+ mOverrideConfigDir(overrideConfigDir),
+ mForceOverride(forceOverride) {
init();
}
@@ -160,9 +172,19 @@
mGeneratorHub.reset();
}
+std::unordered_map<int32_t, ConfigDeclaration> FakeVehicleHardware::loadConfigDeclarations() {
+ std::unordered_map<int32_t, ConfigDeclaration> configsByPropId;
+ loadPropConfigsFromDir(mDefaultConfigDir, &configsByPropId);
+ if (mForceOverride ||
+ android::base::GetBoolProperty(OVERRIDE_PROPERTY, /*default_value=*/false)) {
+ loadPropConfigsFromDir(mOverrideConfigDir, &configsByPropId);
+ }
+ return configsByPropId;
+}
+
void FakeVehicleHardware::init() {
- for (auto& it : defaultconfig::getDefaultConfigs()) {
- VehiclePropConfig cfg = it.config;
+ for (auto& [_, configDeclaration] : loadConfigDeclarations()) {
+ VehiclePropConfig cfg = configDeclaration.config;
VehiclePropertyStore::TokenFunction tokenFunction = nullptr;
if (cfg.prop == toInt(VehicleProperty::AP_POWER_STATE_REQ)) {
@@ -178,15 +200,18 @@
// logic.
continue;
}
- storePropInitialValue(it);
+ storePropInitialValue(configDeclaration);
}
- maybeOverrideProperties(VENDOR_OVERRIDE_DIR);
-
// OBD2_LIVE_FRAME and OBD2_FREEZE_FRAME must be configured in default configs.
- mFakeObd2Frame->initObd2LiveFrame(*mServerSidePropStore->getConfig(OBD2_LIVE_FRAME).value());
- mFakeObd2Frame->initObd2FreezeFrame(
- *mServerSidePropStore->getConfig(OBD2_FREEZE_FRAME).value());
+ auto maybeObd2LiveFrame = mServerSidePropStore->getConfig(OBD2_LIVE_FRAME);
+ if (maybeObd2LiveFrame.has_value()) {
+ mFakeObd2Frame->initObd2LiveFrame(*maybeObd2LiveFrame.value());
+ }
+ auto maybeObd2FreezeFrame = mServerSidePropStore->getConfig(OBD2_FREEZE_FRAME);
+ if (maybeObd2FreezeFrame.has_value()) {
+ mFakeObd2Frame->initObd2FreezeFrame(*maybeObd2FreezeFrame.value());
+ }
mServerSidePropStore->setOnValueChangeCallback(
[this](const VehiclePropValue& value) { return onValueChangeCallback(value); });
@@ -408,7 +433,7 @@
*isSpecialValue = true;
return mFakeObd2Frame->clearObd2FreezeFrames(value);
-#ifdef ENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING
+#ifdef ENABLE_VEHICLE_HAL_TEST_PROPERTIES
case toInt(VehicleProperty::CLUSTER_REPORT_STATE):
[[fallthrough]];
case toInt(VehicleProperty::CLUSTER_REQUEST_DISPLAY):
@@ -436,7 +461,7 @@
<< getErrorMsg(writeResult);
}
return {};
-#endif // ENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING
+#endif // ENABLE_VEHICLE_HAL_TEST_PROPERTIES
default:
break;
@@ -1264,33 +1289,26 @@
(*mOnPropertyChangeCallback)(std::move(updatedValues));
}
-void FakeVehicleHardware::maybeOverrideProperties(const char* overrideDir) {
- if (android::base::GetBoolProperty(OVERRIDE_PROPERTY, false)) {
- overrideProperties(overrideDir);
- }
-}
-
-void FakeVehicleHardware::overrideProperties(const char* overrideDir) {
- ALOGI("loading vendor override properties from %s", overrideDir);
- if (auto dir = opendir(overrideDir); dir != NULL) {
+void FakeVehicleHardware::loadPropConfigsFromDir(
+ const std::string& dirPath,
+ std::unordered_map<int32_t, ConfigDeclaration>* configsByPropId) {
+ ALOGI("loading properties from %s", dirPath.c_str());
+ if (auto dir = opendir(dirPath.c_str()); dir != NULL) {
std::regex regJson(".*[.]json", std::regex::icase);
while (auto f = readdir(dir)) {
if (!std::regex_match(f->d_name, regJson)) {
continue;
}
- std::string file = overrideDir + std::string(f->d_name);
- JsonFakeValueGenerator tmpGenerator(file);
-
- std::vector<VehiclePropValue> propValues = tmpGenerator.getAllEvents();
- for (const VehiclePropValue& prop : propValues) {
- auto propToStore = mValuePool->obtain(prop);
- propToStore->timestamp = elapsedRealtimeNano();
- if (auto result = mServerSidePropStore->writeValue(std::move(propToStore),
- /*updateStatus=*/true);
- !result.ok()) {
- ALOGW("failed to write vendor override properties: %d, error: %s, code: %d",
- prop.prop, getErrorMsg(result).c_str(), getIntErrorCode(result));
- }
+ std::string filePath = dirPath + "/" + std::string(f->d_name);
+ ALOGI("loading properties from %s", filePath.c_str());
+ auto result = mLoader.loadPropConfig(filePath);
+ if (!result.ok()) {
+ ALOGE("failed to load config file: %s, error: %s", filePath.c_str(),
+ result.error().message().c_str());
+ continue;
+ }
+ for (auto& [propId, configDeclaration] : result.value()) {
+ (*configsByPropId)[propId] = std::move(configDeclaration);
}
}
closedir(dir);
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp
index cfd6577..8d8fcf5 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp
@@ -22,13 +22,13 @@
name: "FakeVehicleHardwareTest",
vendor: true,
srcs: ["*.cpp"],
- cflags: ["-DENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING"],
+ cflags: ["-DENABLE_VEHICLE_HAL_TEST_PROPERTIES"],
header_libs: [
"IVehicleHardware",
- "VehicleHalDefaultConfig",
"VehicleHalTestUtilHeaders",
],
static_libs: [
+ "VehicleHalJsonConfigLoaderEnableTestProperties",
"VehicleHalUtils",
"FakeVehicleHardware",
"FakeVehicleHalValueGenerators",
@@ -41,6 +41,9 @@
"libjsoncpp",
],
data: [
+ ":VehicleHalDefaultProperties_JSON",
+ ":VehicleHalTestProperties_JSON",
+ ":VehicleHalVendorClusterTestProperties_JSON",
":FakeVehicleHardwareTestOverrideJson",
":FakeVehicleHardwareTestPropJson",
],
@@ -55,5 +58,5 @@
filegroup {
name: "FakeVehicleHardwareTestPropJson",
- srcs: ["prop.json"],
+ srcs: ["fakedata/prop.json"],
}
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
index ab6bf51..c230c51 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
@@ -16,7 +16,6 @@
#include <FakeVehicleHardware.h>
-#include <DefaultConfig.h>
#include <FakeObd2Frame.h>
#include <FakeUserHal.h>
#include <PropertyUtils.h>
@@ -80,7 +79,9 @@
public:
FakeVehicleHardwareTestHelper(FakeVehicleHardware* hardware) { mHardware = hardware; }
- void overrideProperties(const char* overrideDir) { mHardware->overrideProperties(overrideDir); }
+ std::unordered_map<int32_t, ConfigDeclaration> loadConfigDeclarations() {
+ return mHardware->loadConfigDeclarations();
+ }
private:
FakeVehicleHardware* mHardware;
@@ -89,7 +90,9 @@
class FakeVehicleHardwareTest : public ::testing::Test {
protected:
void SetUp() override {
- mHardware = std::make_unique<FakeVehicleHardware>();
+ mHardware = std::make_unique<FakeVehicleHardware>(android::base::GetExecutableDirectory(),
+ /*overrideConfigDir=*/"",
+ /*forceOverride=*/false);
auto callback = std::make_unique<IVehicleHardware::PropertyChangeCallback>(
[this](const std::vector<VehiclePropValue>& values) {
onPropertyChangeEvent(values);
@@ -109,6 +112,10 @@
FakeVehicleHardware* getHardware() { return mHardware.get(); }
+ void setHardware(std::unique_ptr<FakeVehicleHardware> hardware) {
+ mHardware = std::move(hardware);
+ }
+
StatusCode setValues(const std::vector<SetValueRequest>& requests) {
{
std::scoped_lock<std::mutex> lockGuard(mLock);
@@ -374,7 +381,8 @@
TEST_F(FakeVehicleHardwareTest, testGetAllPropertyConfigs) {
std::vector<VehiclePropConfig> configs = getHardware()->getAllPropertyConfigs();
- ASSERT_EQ(configs.size(), defaultconfig::getDefaultConfigs().size());
+ FakeVehicleHardwareTestHelper helper(getHardware());
+ ASSERT_EQ(configs.size(), helper.loadConfigDeclarations().size());
}
TEST_F(FakeVehicleHardwareTest, testGetDefaultValues) {
@@ -382,7 +390,8 @@
std::vector<GetValueResult> expectedGetValueResults;
int64_t requestId = 1;
- for (auto& config : defaultconfig::getDefaultConfigs()) {
+ FakeVehicleHardwareTestHelper helper(getHardware());
+ for (auto& [propId, config] : helper.loadConfigDeclarations()) {
if (obd2frame::FakeObd2Frame::isDiagnosticProperty(config.config)) {
// Ignore storing default value for diagnostic property. They have special get/set
// logic.
@@ -394,12 +403,11 @@
continue;
}
- if (config.config.prop == ECHO_REVERSE_BYTES) {
+ if (propId == ECHO_REVERSE_BYTES) {
// Ignore ECHO_REVERSE_BYTES, it has special logic.
continue;
}
- int propId = config.config.prop;
if (isGlobalProp(propId)) {
if (config.initialValue == RawPropValues{}) {
addGetValueRequest(getValueRequests, expectedGetValueResults, requestId++,
@@ -657,10 +665,12 @@
}
TEST_F(FakeVehicleHardwareTest, testVendorOverrideProperties) {
- std::string overrideDir = android::base::GetExecutableDirectory() + "/override/";
+ std::string currentDir = android::base::GetExecutableDirectory();
+ std::string overrideDir = currentDir + "/override/";
// Set vendor override directory.
- FakeVehicleHardwareTestHelper helper(getHardware());
- helper.overrideProperties(overrideDir.c_str());
+ std::unique_ptr<FakeVehicleHardware> hardware =
+ std::make_unique<FakeVehicleHardware>(currentDir, overrideDir, /*forceOverride=*/true);
+ setHardware(std::move(hardware));
// This is the same as the prop in 'gear_selection.json'.
int gearProp = toInt(VehicleProperty::GEAR_SELECTION);
@@ -695,10 +705,12 @@
}
TEST_F(FakeVehicleHardwareTest, testVendorOverridePropertiesMultipleAreas) {
- std::string overrideDir = android::base::GetExecutableDirectory() + "/override/";
+ std::string currentDir = android::base::GetExecutableDirectory();
+ std::string overrideDir = currentDir + "/override/";
// Set vendor override directory.
- FakeVehicleHardwareTestHelper helper(getHardware());
- helper.overrideProperties(overrideDir.c_str());
+ std::unique_ptr<FakeVehicleHardware> hardware =
+ std::make_unique<FakeVehicleHardware>(currentDir, overrideDir, /*forceOverride=*/true);
+ setHardware(std::move(hardware));
// This is the same as the prop in 'hvac_temperature_set.json'.
int hvacProp = toInt(VehicleProperty::HVAC_TEMPERATURE_SET);
@@ -711,22 +723,16 @@
ASSERT_TRUE(result.ok()) << "expect to get the overridden property ok: " << getStatus(result);
ASSERT_EQ(static_cast<size_t>(1), result.value().value.floatValues.size());
ASSERT_EQ(30.0f, result.value().value.floatValues[0]);
-
- // HVAC_RIGHT should not be affected and return the default value.
- result = getValue(VehiclePropValue{
- .prop = hvacProp,
- .areaId = HVAC_RIGHT,
- });
-
- ASSERT_TRUE(result.ok()) << "expect to get the default property ok: " << getStatus(result);
- ASSERT_EQ(static_cast<size_t>(1), result.value().value.floatValues.size());
- ASSERT_EQ(20.0f, result.value().value.floatValues[0]);
}
TEST_F(FakeVehicleHardwareTest, testVendorOverridePropertiesDirDoesNotExist) {
- // Set vendor override directory to a non-existing dir
- FakeVehicleHardwareTestHelper helper(getHardware());
- helper.overrideProperties("123");
+ std::string currentDir = android::base::GetExecutableDirectory();
+ std::string overrideDir = currentDir + "/override/";
+ // Set vendor override directory to a non-existing dir.
+ std::unique_ptr<FakeVehicleHardware> hardware =
+ std::make_unique<FakeVehicleHardware>(currentDir, "1234", /*forceOverride=*/true);
+ setHardware(std::move(hardware));
+
auto result = getValue(VehiclePropValue{
.prop = toInt(VehicleProperty::GEAR_SELECTION),
});
@@ -1840,7 +1846,7 @@
std::string getTestFilePath(const char* filename) {
static std::string baseDir = android::base::GetExecutableDirectory();
- return baseDir + "/" + filename;
+ return baseDir + "/fakedata/" + filename;
}
TEST_F(FakeVehicleHardwareTest, testDebugGenFakeDataJson) {
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/prop.json b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/fakedata/prop.json
similarity index 100%
rename from automotive/vehicle/aidl/impl/fake_impl/hardware/test/prop.json
rename to automotive/vehicle/aidl/impl/fake_impl/hardware/test/fakedata/prop.json
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/override/gear_selection.json b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/override/gear_selection.json
index 59666b8..693f1e2 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/override/gear_selection.json
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/override/gear_selection.json
@@ -1,9 +1,13 @@
-[
- {
- "timestamp": 1000000,
- "areaId": 0,
- "value": 8,
- // GEAR_SELECTION
- "prop": 289408000
- }
-]
+{
+ "apiVersion": 1,
+ "properties": [
+ {
+ "property": "VehicleProperty::GEAR_SELECTION",
+ "defaultValue": {
+ "int32Values": [
+ 8
+ ]
+ }
+ }
+ ]
+}
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/override/hvac_temperature_set.json b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/override/hvac_temperature_set.json
index 93a97ed..07cfebb 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/override/hvac_temperature_set.json
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/override/hvac_temperature_set.json
@@ -1,10 +1,20 @@
-[
- {
- "timestamp": 1000000,
- // HVAC_LEFT
- "areaId": 49,
- "value": 30,
- // HVAC_TEMPERATURE_SET
- "prop": 358614275
- }
-]
+{
+ "apiVersion": 1,
+ "properties": [
+ {
+ "property": "VehicleProperty::HVAC_TEMPERATURE_SET",
+ "areas": [
+ {
+ "defaultValue": {
+ "floatValues": [
+ 30.0
+ ]
+ },
+ "areaId": 49,
+ "minFloatValue": 16.0,
+ "maxFloatValue": 32.0
+ }
+ ]
+ }
+ ]
+}
diff --git a/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/Android.bp b/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/Android.bp
index 7670c25..2b4059c 100644
--- a/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/Android.bp
+++ b/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/Android.bp
@@ -47,13 +47,19 @@
],
vendor: true,
defaults: ["VehicleHalDefaults"],
- shared_libs: ["libprotobuf-cpp-full"],
+ shared_libs: [
+ "libprotobuf-cpp-full",
+ "libjsoncpp",
+ ],
static_libs: [
+ "VehicleHalJsonConfigLoaderEnableTestProperties",
"VehicleHalProtoMessageConverter",
"VehicleHalProtos",
"VehicleHalUtils",
"libgtest",
],
- header_libs: ["VehicleHalDefaultConfig"],
+ data: [
+ ":VehicleHalDefaultProperties_JSON",
+ ],
test_suites: ["device-tests"],
}
diff --git a/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/test/proto_message_converter_test.cpp b/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/test/proto_message_converter_test.cpp
index c742db5..308be46 100644
--- a/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/test/proto_message_converter_test.cpp
+++ b/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/test/proto_message_converter_test.cpp
@@ -16,9 +16,11 @@
#include <vector>
-#include <DefaultConfig.h>
+#include <JsonConfigLoader.h>
#include <ProtoMessageConverter.h>
#include <VehicleHalTypes.h>
+
+#include <android-base/file.h>
#include <android-base/format.h>
#include <android/hardware/automotive/vehicle/VehiclePropConfig.pb.h>
#include <android/hardware/automotive/vehicle/VehiclePropValue.pb.h>
@@ -35,23 +37,39 @@
namespace proto = ::android::hardware::automotive::vehicle::proto;
namespace aidl_vehicle = ::aidl::android::hardware::automotive::vehicle;
+constexpr char DEFAULT_PROPERTIES_CONFIG[] = "DefaultProperties.json";
+
+inline std::string getConfigPath(const std::string& name) {
+ return android::base::GetExecutableDirectory() + "/" + name;
+}
+
std::vector<aidl_vehicle::VehiclePropConfig> prepareTestConfigs() {
+ JsonConfigLoader loader;
+ auto result = loader.loadPropConfig(getConfigPath(DEFAULT_PROPERTIES_CONFIG));
+ if (!result.ok()) {
+ return {};
+ }
std::vector<aidl_vehicle::VehiclePropConfig> configs;
- for (auto& property : defaultconfig::getDefaultConfigs()) {
- configs.push_back(property.config);
+ for (auto& [_, configDeclaration] : result.value()) {
+ configs.push_back(configDeclaration.config);
}
return configs;
}
std::vector<aidl_vehicle::VehiclePropValue> prepareTestValues() {
+ JsonConfigLoader loader;
+ auto result = loader.loadPropConfig(getConfigPath(DEFAULT_PROPERTIES_CONFIG));
+ if (!result.ok()) {
+ return {};
+ }
std::vector<aidl_vehicle::VehiclePropValue> values;
int64_t timestamp = 1;
- for (auto& property : defaultconfig::getDefaultConfigs()) {
+ for (auto& [_, configDeclaration] : result.value()) {
values.push_back({
.timestamp = timestamp,
.areaId = 123,
- .prop = property.config.prop,
- .value = property.initialValue,
+ .prop = configDeclaration.config.prop,
+ .value = configDeclaration.initialValue,
.status = aidl_vehicle::VehiclePropertyStatus::ERROR,
});
}
diff --git a/automotive/vehicle/aidl/impl/utils/common/src/RecurrentTimer.cpp b/automotive/vehicle/aidl/impl/utils/common/src/RecurrentTimer.cpp
index fbc79fa..43f5d69 100644
--- a/automotive/vehicle/aidl/impl/utils/common/src/RecurrentTimer.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/src/RecurrentTimer.cpp
@@ -50,7 +50,7 @@
std::scoped_lock<std::mutex> lockGuard(mLock);
// Aligns the nextTime to multiply of interval.
- int64_t nextTime = ceil(elapsedRealtimeNano() / intervalInNano) * intervalInNano;
+ int64_t nextTime = ceil(uptimeNanos() / intervalInNano) * intervalInNano;
std::unique_ptr<CallbackInfo> info = std::make_unique<CallbackInfo>();
info->callback = callback;
@@ -130,7 +130,7 @@
}
// The first element is the nearest next event.
int64_t nextTime = mCallbackQueue[0]->nextTime;
- int64_t now = elapsedRealtimeNano();
+ int64_t now = uptimeNanos();
if (nextTime > now) {
interval = nextTime - now;
} else {
@@ -148,7 +148,7 @@
{
ScopedLockAssertion lockAssertion(mLock);
- int64_t now = elapsedRealtimeNano();
+ int64_t now = uptimeNanos();
while (mCallbackQueue.size() > 0) {
int64_t nextTime = mCallbackQueue[0]->nextTime;
if (nextTime > now) {
diff --git a/automotive/vehicle/aidl/impl/utils/test/include/TestPropertyUtils.h b/automotive/vehicle/aidl/impl/utils/test/include/TestPropertyUtils.h
index d512713..e6ea6fe 100644
--- a/automotive/vehicle/aidl/impl/utils/test/include/TestPropertyUtils.h
+++ b/automotive/vehicle/aidl/impl/utils/test/include/TestPropertyUtils.h
@@ -35,7 +35,6 @@
} // namespace testpropertyutils_impl
-#ifdef ENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING
// Converts the system property to the vendor property.
// WARNING: This is only for the end-to-end testing, Should NOT include in the user build.
inline constexpr int32_t toVendor(
@@ -55,7 +54,6 @@
toVendor(testpropertyutils_impl::VehicleProperty::CLUSTER_REQUEST_DISPLAY);
constexpr int32_t VENDOR_CLUSTER_NAVIGATION_STATE =
toVendor(testpropertyutils_impl::VehicleProperty::CLUSTER_NAVIGATION_STATE);
-#endif // ENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING
// These properties are placeholder properties for developers to test new features without
// implementing a real property.
diff --git a/automotive/vehicle/aidl/impl/vhal/Android.bp b/automotive/vehicle/aidl/impl/vhal/Android.bp
index 8b4f559..4feea79 100644
--- a/automotive/vehicle/aidl/impl/vhal/Android.bp
+++ b/automotive/vehicle/aidl/impl/vhal/Android.bp
@@ -74,23 +74,12 @@
"FakeVehicleHardwareDefaults",
"VehicleHalDefaults",
"android-automotive-large-parcelable-defaults",
- ],
- header_libs: [
- "IVehicleHardware",
- "VehicleHalDefaultConfig",
+ "service_fuzzer_defaults",
],
static_libs: [
"DefaultVehicleHal",
"FakeVehicleHardware",
"VehicleHalUtils",
- "libbase",
- "libbinder_random_parcel",
- "libcutils",
- ],
- shared_libs: [
- "libbinder_ndk",
- "libbinder",
- "libutils",
],
srcs: ["src/fuzzer.cpp"],
fuzz_config: {
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.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/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/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 a687162..4aea83f 100644
--- a/bluetooth/audio/aidl/Android.bp
+++ b/bluetooth/audio/aidl/Android.bp
@@ -42,7 +42,7 @@
ndk: {
apex_available: [
"//apex_available:platform",
- "com.android.bluetooth",
+ "com.android.btservices",
],
min_sdk_version: "31",
},
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
index d5e85b8..036d6cd 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
@@ -491,11 +491,18 @@
.broadcastCapability = kInvalidBroadcastCapability});
// Adds the capability for the case that encode and decode exist at the
- // same time
+ // same time(force one active device for decode)
kDefaultOffloadLeAudioCapabilities.push_back(
{.unicastEncodeCapability = lc3Capability,
.unicastDecodeCapability = lc3MonoDecodeCapability,
.broadcastCapability = kInvalidBroadcastCapability});
+
+ // Adds the capability for the case that encode and decode exist at the
+ // same time
+ kDefaultOffloadLeAudioCapabilities.push_back(
+ {.unicastEncodeCapability = lc3Capability,
+ .unicastDecodeCapability = lc3Capability,
+ .broadcastCapability = kInvalidBroadcastCapability});
}
}
}
diff --git a/boot/aidl/default/BootControl.cpp b/boot/aidl/default/BootControl.cpp
index 4e3c21b..b73c94d 100644
--- a/boot/aidl/default/BootControl.cpp
+++ b/boot/aidl/default/BootControl.cpp
@@ -84,10 +84,12 @@
ScopedAStatus BootControl::getSuffix(int32_t in_slot, std::string* _aidl_return) {
if (!impl_.IsValidSlot(in_slot)) {
- return ScopedAStatus::fromServiceSpecificErrorWithMessage(
- INVALID_SLOT, (std::string("Invalid slot ") + std::to_string(in_slot)).c_str());
+ // 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);
}
- *_aidl_return = impl_.GetSuffix(in_slot);
return ScopedAStatus::ok();
}
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..ab3c789
--- /dev/null
+++ b/boot/aidl/vts/functional/VtsHalBootAidlTargetTest.cpp
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 BootHidlTest : 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(BootHidlTest, GetNumberSlots) {
+ int32_t slots{};
+ boot->getNumberSlots(&slots);
+ ASSERT_LE(2, slots);
+}
+
+// validity check Boot::getCurrentSlot().
+TEST_P(BootHidlTest, GetCurrentSlot) {
+ int curSlot = -1;
+ boot->getCurrentSlot(&curSlot);
+ int slots = 0;
+ boot->getNumberSlots(&slots);
+ ASSERT_LT(curSlot, slots);
+}
+
+// validity check Boot::markBootSuccessful().
+TEST_P(BootHidlTest, 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(BootHidlTest, 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(BootHidlTest, 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(BootHidlTest, 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(BootHidlTest, 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(BootHidlTest, 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, BootHidlTest,
+ testing::ValuesIn(android::getAidlHalInstanceNames(IBootControl::descriptor)));
diff --git a/broadcastradio/2.0/default/VirtualRadio.cpp b/broadcastradio/2.0/default/VirtualRadio.cpp
index c59fd8f..e6b1017 100644
--- a/broadcastradio/2.0/default/VirtualRadio.cpp
+++ b/broadcastradio/2.0/default/VirtualRadio.cpp
@@ -46,9 +46,9 @@
VirtualRadio gDabRadio(
"DAB radio mock",
{
- {make_selector_dab(12345, 225648), "BBC Radio 1", "Khalid", "Talk"}, // 12B
- {make_selector_dab(22345, 222064), "Classic FM", "Jean Sibelius", "Andante Festivo"}, // 11D
- {make_selector_dab(32345, 222064), "Absolute Radio", "Coldplay", "Clocks"}, // 11D
+ {make_selector_dab(0xA00001u, 0x0001u), "BBC Radio 1", "Khalid", "Talk"},
+ {make_selector_dab(0xB00001u, 0x1001u), "Classic FM", "Jean Sibelius", "Andante Festivo"},
+ {make_selector_dab(0xB00002u, 0x1001u), "Absolute Radio", "Coldplay", "Clocks"},
});
// clang-format on
diff --git a/broadcastradio/aidl/OWNERS b/broadcastradio/aidl/OWNERS
new file mode 100644
index 0000000..302fdd7
--- /dev/null
+++ b/broadcastradio/aidl/OWNERS
@@ -0,0 +1,4 @@
+xuweilin@google.com
+oscarazu@google.com
+ericjeong@google.com
+keunyoung@google.com
diff --git a/camera/common/1.0/default/HandleImporter.cpp b/camera/common/1.0/default/HandleImporter.cpp
index fbe8686..d2fdf02 100644
--- a/camera/common/1.0/default/HandleImporter.cpp
+++ b/camera/common/1.0/default/HandleImporter.cpp
@@ -18,6 +18,7 @@
#include "HandleImporter.h"
#include <gralloctypes/Gralloc4.h>
+#include "aidl/android/hardware/graphics/common/Smpte2086.h"
#include <log/log.h>
namespace android {
@@ -30,6 +31,7 @@
using aidl::android::hardware::graphics::common::PlaneLayout;
using aidl::android::hardware::graphics::common::PlaneLayoutComponent;
using aidl::android::hardware::graphics::common::PlaneLayoutComponentType;
+using aidl::android::hardware::graphics::common::Smpte2086;
using MetadataType = android::hardware::graphics::mapper::V4_0::IMapper::MetadataType;
using MapperErrorV2 = android::hardware::graphics::mapper::V2_0::Error;
using MapperErrorV3 = android::hardware::graphics::mapper::V3_0::Error;
@@ -127,16 +129,35 @@
bool isMetadataPesent(const sp<IMapperV4> mapper, const buffer_handle_t& buf,
MetadataType metadataType) {
auto buffer = const_cast<native_handle_t*>(buf);
- mapper->get(buffer, metadataType, [] (const auto& tmpError,
+ bool ret = false;
+ hidl_vec<uint8_t> vec;
+ mapper->get(buffer, metadataType, [&] (const auto& tmpError,
const auto& tmpMetadata) {
if (tmpError == MapperErrorV4::NONE) {
- return tmpMetadata.size() > 0;
+ vec = tmpMetadata;
} else {
ALOGE("%s: failed to get metadata %d!", __FUNCTION__, tmpError);
- return false;
}});
- return false;
+ if (vec.size() > 0) {
+ if (metadataType == gralloc4::MetadataType_Smpte2086){
+ std::optional<Smpte2086> realSmpte2086;
+ gralloc4::decodeSmpte2086(vec, &realSmpte2086);
+ ret = realSmpte2086.has_value();
+ } else if (metadataType == gralloc4::MetadataType_Smpte2094_10) {
+ std::optional<std::vector<uint8_t>> realSmpte2094_10;
+ gralloc4::decodeSmpte2094_10(vec, &realSmpte2094_10);
+ ret = realSmpte2094_10.has_value();
+ } else if (metadataType == gralloc4::MetadataType_Smpte2094_40) {
+ std::optional<std::vector<uint8_t>> realSmpte2094_40;
+ gralloc4::decodeSmpte2094_40(vec, &realSmpte2094_40);
+ ret = realSmpte2094_40.has_value();
+ } else {
+ ALOGE("%s: Unknown metadata type!", __FUNCTION__);
+ }
+ }
+
+ return ret;
}
std::vector<PlaneLayout> getPlaneLayouts(const sp<IMapperV4> mapper, buffer_handle_t& buf) {
diff --git a/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp b/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
index fe03732..70ab7a0 100644
--- a/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
+++ b/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
@@ -1739,6 +1739,10 @@
std::list<PixelFormat> pixelFormats = {PixelFormat::YCBCR_420_888, PixelFormat::RAW16};
for (PixelFormat format : pixelFormats) {
+ previewStream.usage =
+ static_cast<aidl::android::hardware::graphics::common::BufferUsage>(
+ GRALLOC1_CONSUMER_USAGE_CPU_READ);
+ previewStream.dataSpace = Dataspace::UNKNOWN;
configureStreams(name, mProvider, format, &mSession, &previewStream, &halStreams,
&supportsPartialResults, &partialResultCount, &useHalBufManager, &cb,
0, /*maxResolution*/ true);
@@ -1843,7 +1847,6 @@
TEST_P(CameraAidlTest, process10BitDynamicRangeRequest) {
std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
int64_t bufferId = 1;
- int32_t frameNumber = 1;
CameraMetadata settings;
for (const auto& name : cameraDeviceNames) {
@@ -1866,7 +1869,7 @@
CameraMetadata req;
android::hardware::camera::common::V1_0::helper::CameraMetadata defaultSettings;
ndk::ScopedAStatus ret =
- mSession->constructDefaultRequestSettings(RequestTemplate::STILL_CAPTURE, &req);
+ mSession->constructDefaultRequestSettings(RequestTemplate::PREVIEW, &req);
ASSERT_TRUE(ret.isOk());
const camera_metadata_t* metadata =
@@ -1896,6 +1899,10 @@
Stream previewStream;
std::shared_ptr<DeviceCb> cb;
for (const auto& profile : profileList) {
+ previewStream.usage =
+ static_cast<aidl::android::hardware::graphics::common::BufferUsage>(
+ GRALLOC1_CONSUMER_USAGE_HWCOMPOSER);
+ previewStream.dataSpace = getDataspace(PixelFormat::IMPLEMENTATION_DEFINED);
configureStreams(name, mProvider, PixelFormat::IMPLEMENTATION_DEFINED, &mSession,
&previewStream, &halStreams, &supportsPartialResults,
&partialResultCount, &useHalBufManager, &cb, 0,
@@ -1916,63 +1923,75 @@
// Don't use the queue onwards.
}
- std::vector<buffer_handle_t> graphicBuffers;
- graphicBuffers.reserve(halStreams.size());
+ mInflightMap.clear();
+ // Stream as long as needed to fill the Hal inflight queue
+ std::vector<CaptureRequest> requests(halStreams[0].maxBuffers);
- std::shared_ptr<InFlightRequest> inflightReq = std::make_shared<InFlightRequest>(
- static_cast<ssize_t>(halStreams.size()), false, supportsPartialResults,
- partialResultCount, std::unordered_set<std::string>(), resultQueue);
+ for (int32_t frameNumber = 0; frameNumber < requests.size(); frameNumber++) {
+ std::shared_ptr<InFlightRequest> inflightReq = std::make_shared<InFlightRequest>(
+ static_cast<ssize_t>(halStreams.size()), false, supportsPartialResults,
+ partialResultCount, std::unordered_set<std::string>(), resultQueue);
- std::vector<CaptureRequest> requests(1);
- CaptureRequest& request = requests[0];
- std::vector<StreamBuffer>& outputBuffers = request.outputBuffers;
- outputBuffers.resize(halStreams.size());
+ CaptureRequest& request = requests[frameNumber];
+ std::vector<StreamBuffer>& outputBuffers = request.outputBuffers;
+ outputBuffers.resize(halStreams.size());
- size_t k = 0;
- for (const auto& halStream : halStreams) {
- buffer_handle_t buffer_handle;
- if (useHalBufManager) {
- outputBuffers[k] = {halStream.id, 0,
- NativeHandle(), BufferStatus::OK,
- NativeHandle(), NativeHandle()};
- } else {
- allocateGraphicBuffer(previewStream.width, previewStream.height,
- android_convertGralloc1To0Usage(
- static_cast<uint64_t>(halStream.producerUsage),
- static_cast<uint64_t>(halStream.consumerUsage)),
- halStream.overrideFormat, &buffer_handle);
+ size_t k = 0;
+ inflightReq->mOutstandingBufferIds.resize(halStreams.size());
+ std::vector<buffer_handle_t> graphicBuffers;
+ graphicBuffers.reserve(halStreams.size());
- graphicBuffers.push_back(buffer_handle);
- outputBuffers[k] = {
- halStream.id, bufferId, android::makeToAidl(buffer_handle),
- BufferStatus::OK, NativeHandle(), NativeHandle()};
- bufferId++;
+ for (const auto& halStream : halStreams) {
+ buffer_handle_t buffer_handle;
+ if (useHalBufManager) {
+ outputBuffers[k] = {halStream.id, 0,
+ NativeHandle(), BufferStatus::OK,
+ NativeHandle(), NativeHandle()};
+ } else {
+ auto usage = android_convertGralloc1To0Usage(
+ static_cast<uint64_t>(halStream.producerUsage),
+ static_cast<uint64_t>(halStream.consumerUsage));
+ allocateGraphicBuffer(previewStream.width, previewStream.height, usage,
+ halStream.overrideFormat, &buffer_handle);
+
+ inflightReq->mOutstandingBufferIds[halStream.id][bufferId] = buffer_handle;
+ graphicBuffers.push_back(buffer_handle);
+ outputBuffers[k] = {halStream.id, bufferId,
+ android::makeToAidl(buffer_handle), BufferStatus::OK, NativeHandle(),
+ NativeHandle()};
+ bufferId++;
+ }
+ k++;
}
- k++;
- }
- request.inputBuffer = {
- -1, 0, NativeHandle(), BufferStatus::ERROR, NativeHandle(), NativeHandle()};
- request.frameNumber = frameNumber;
- request.fmqSettingsSize = 0;
- request.settings = settings;
- request.inputWidth = 0;
- request.inputHeight = 0;
+ request.inputBuffer = {
+ -1, 0, NativeHandle(), BufferStatus::ERROR, NativeHandle(), NativeHandle()};
+ request.frameNumber = frameNumber;
+ request.fmqSettingsSize = 0;
+ request.settings = settings;
+ request.inputWidth = 0;
+ request.inputHeight = 0;
- {
- std::unique_lock<std::mutex> l(mLock);
- mInflightMap.clear();
- mInflightMap[frameNumber] = inflightReq;
+ {
+ std::unique_lock<std::mutex> l(mLock);
+ mInflightMap[frameNumber] = inflightReq;
+ }
+
}
int32_t numRequestProcessed = 0;
std::vector<BufferCache> cachesToRemove;
ndk::ScopedAStatus returnStatus =
- mSession->processCaptureRequest(requests, cachesToRemove, &numRequestProcessed);
+ mSession->processCaptureRequest(requests, cachesToRemove, &numRequestProcessed);
ASSERT_TRUE(returnStatus.isOk());
- ASSERT_EQ(numRequestProcessed, 1u);
+ ASSERT_EQ(numRequestProcessed, requests.size());
- {
+ returnStatus = mSession->repeatingRequestEnd(requests.size() - 1,
+ std::vector<int32_t> {halStreams[0].id});
+ ASSERT_TRUE(returnStatus.isOk());
+
+ for (int32_t frameNumber = 0; frameNumber < requests.size(); frameNumber++) {
+ const auto& inflightReq = mInflightMap[frameNumber];
std::unique_lock<std::mutex> l(mLock);
while (!inflightReq->errorCodeValid &&
((0 < inflightReq->numBuffersLeft) || (!inflightReq->haveResultMetadata))) {
@@ -1985,6 +2004,7 @@
ASSERT_NE(inflightReq->resultOutputBuffers.size(), 0u);
verify10BitMetadata(mHandleImporter, *inflightReq, profile);
}
+
if (useHalBufManager) {
std::vector<int32_t> streamIds(halStreams.size());
for (size_t i = 0; i < streamIds.size(); i++) {
diff --git a/camera/provider/aidl/vts/camera_aidl_test.cpp b/camera/provider/aidl/vts/camera_aidl_test.cpp
index c11fc0c..20f32bf 100644
--- a/camera/provider/aidl/vts/camera_aidl_test.cpp
+++ b/camera/provider/aidl/vts/camera_aidl_test.cpp
@@ -2639,8 +2639,20 @@
outputStreams.clear();
Size maxSize;
- auto rc = getMaxOutputSizeForFormat(staticMeta, format, &maxSize, maxResolution);
- ASSERT_EQ(Status::OK, rc);
+ if (maxResolution) {
+ auto rc = getMaxOutputSizeForFormat(staticMeta, format, &maxSize, maxResolution);
+ ASSERT_EQ(Status::OK, rc);
+ } else {
+ AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
+ static_cast<int32_t>(format)};
+ auto rc = getAvailableOutputStreams(staticMeta, outputStreams, &previewThreshold);
+
+ ASSERT_EQ(Status::OK, rc);
+ ASSERT_FALSE(outputStreams.empty());
+ maxSize.width = outputStreams[0].width;
+ maxSize.height = outputStreams[0].height;
+ }
+
std::vector<Stream> streams(1);
streams[0] = {0,
@@ -2648,9 +2660,8 @@
maxSize.width,
maxSize.height,
format,
- static_cast<::aidl::android::hardware::graphics::common::BufferUsage>(
- GRALLOC1_CONSUMER_USAGE_CPU_READ),
- Dataspace::UNKNOWN,
+ previewStream->usage,
+ previewStream->dataSpace,
StreamRotation::ROTATION_0,
"",
0,
@@ -2736,7 +2747,8 @@
HandleImporter& importer, const InFlightRequest& request,
aidl::android::hardware::camera::metadata::RequestAvailableDynamicRangeProfilesMap
profile) {
- for (const auto& b : request.resultOutputBuffers) {
+ for (auto b : request.resultOutputBuffers) {
+ importer.importBuffer(b.buffer.buffer);
bool smpte2086Present = importer.isSmpte2086Present(b.buffer.buffer);
bool smpte2094_10Present = importer.isSmpte2094_10Present(b.buffer.buffer);
bool smpte2094_40Present = importer.isSmpte2094_40Present(b.buffer.buffer);
@@ -2753,7 +2765,6 @@
ASSERT_FALSE(smpte2094_40Present);
break;
case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10_PLUS:
- ASSERT_FALSE(smpte2086Present);
ASSERT_FALSE(smpte2094_10Present);
ASSERT_TRUE(smpte2094_40Present);
break;
@@ -2774,6 +2785,7 @@
profile);
ADD_FAILURE();
}
+ importer.freeBuffer(b.buffer.buffer);
}
}
diff --git a/camera/provider/aidl/vts/camera_aidl_test.h b/camera/provider/aidl/vts/camera_aidl_test.h
index ac4b2c9..d828cee 100644
--- a/camera/provider/aidl/vts/camera_aidl_test.h
+++ b/camera/provider/aidl/vts/camera_aidl_test.h
@@ -399,6 +399,10 @@
// Result metadata
::android::hardware::camera::common::V1_0::helper::CameraMetadata collectedResult;
+ // Inflight buffers
+ using OutstandingBuffers = std::unordered_map<uint64_t, buffer_handle_t>;
+ std::vector<OutstandingBuffers> mOutstandingBufferIds;
+
// A copy-able StreamBuffer using buffer_handle_t instead of AIDLs NativeHandle
struct NativeStreamBuffer {
int32_t streamId;
diff --git a/camera/provider/aidl/vts/device_cb.cpp b/camera/provider/aidl/vts/device_cb.cpp
index e5f2f1e..4698b4a 100644
--- a/camera/provider/aidl/vts/device_cb.cpp
+++ b/camera/provider/aidl/vts/device_cb.cpp
@@ -155,7 +155,7 @@
BufferStatus::OK, NativeHandle(), NativeHandle(),
};
- mOutstandingBufferIds[idx][mNextBufferId++] = ::android::dupToAidl(handle);
+ mOutstandingBufferIds[idx][mNextBufferId++] = handle;
}
atLeastOneStreamOk = true;
bufRets[i].streamId = stream.id;
@@ -427,9 +427,13 @@
}
CameraAidlTest::InFlightRequest::StreamBufferAndTimestamp streamBufferAndTimestamp;
+ auto outstandingBuffers = mUseHalBufManager ? mOutstandingBufferIds :
+ request->mOutstandingBufferIds;
+ auto outputBuffer = outstandingBuffers.empty() ? ::android::makeFromAidl(buffer.buffer) :
+ outstandingBuffers[buffer.streamId][buffer.bufferId];
streamBufferAndTimestamp.buffer = {buffer.streamId,
buffer.bufferId,
- ::android::makeFromAidl(buffer.buffer),
+ outputBuffer,
buffer.status,
::android::makeFromAidl(buffer.acquireFence),
::android::makeFromAidl(buffer.releaseFence)};
diff --git a/camera/provider/aidl/vts/device_cb.h b/camera/provider/aidl/vts/device_cb.h
index 82ca10d..3ae7d10 100644
--- a/camera/provider/aidl/vts/device_cb.h
+++ b/camera/provider/aidl/vts/device_cb.h
@@ -73,7 +73,7 @@
std::vector<Stream> mStreams;
std::vector<HalStream> mHalStreams;
int64_t mNextBufferId = 1;
- using OutstandingBuffers = std::unordered_map<uint64_t, NativeHandle>;
+ using OutstandingBuffers = std::unordered_map<uint64_t, buffer_handle_t>;
// size == mStreams.size(). Tracking each streams outstanding buffers
std::vector<OutstandingBuffers> mOutstandingBufferIds;
std::condition_variable mFlushedCondition;
diff --git a/common/aidl/Android.bp b/common/aidl/Android.bp
index 549d970..43f8c4d 100644
--- a/common/aidl/Android.bp
+++ b/common/aidl/Android.bp
@@ -30,7 +30,7 @@
ndk: {
apex_available: [
"//apex_available:platform",
- "com.android.bluetooth",
+ "com.android.btservices",
"com.android.media.swcodec",
"com.android.neuralnetworks",
],
diff --git a/common/fmq/aidl/Android.bp b/common/fmq/aidl/Android.bp
index 6fd4200..a85597c 100644
--- a/common/fmq/aidl/Android.bp
+++ b/common/fmq/aidl/Android.bp
@@ -32,7 +32,7 @@
ndk: {
apex_available: [
"//apex_available:platform",
- "com.android.bluetooth",
+ "com.android.btservices",
],
min_sdk_version: "29",
},
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index d899c2c..d59def7 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -37,6 +37,14 @@
<instance>default</instance>
</interface>
</hal>
+ <hal format="aidl" optional="false">
+ <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>
@@ -104,22 +112,6 @@
<regex-instance>.*</regex-instance>
</interface>
</hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.automotive.vehicle</name>
- <version>2.0</version>
- <interface>
- <name>IVehicle</name>
- <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>
@@ -128,14 +120,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>
@@ -161,14 +145,6 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.boot</name>
- <version>1.2</version>
- <interface>
- <name>IBootControl</name>
- <instance>default</instance>
- </interface>
- </hal>
<hal format="aidl" optional="true">
<name>android.hardware.boot</name>
<interface>
@@ -239,18 +215,6 @@
<regex-instance>.*</regex-instance>
</interface>
</hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.drm</name>
- <version>1.3-4</version>
- <interface>
- <name>ICryptoFactory</name>
- <regex-instance>.*</regex-instance>
- </interface>
- <interface>
- <name>IDrmFactory</name>
- <regex-instance>.*</regex-instance>
- </interface>
- </hal>
<hal format="aidl" optional="true">
<name>android.hardware.dumpstate</name>
<interface>
@@ -266,14 +230,6 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.gnss</name>
- <version>2.0-1</version>
- <interface>
- <name>IGnss</name>
- <instance>default</instance>
- </interface>
- </hal>
<hal format="aidl" optional="true">
<name>android.hardware.gnss</name>
<version>2</version>
@@ -298,21 +254,6 @@
<instance>default</instance>
</interface>
</hal>
- <!-- Either the AIDL or the HIDL allocator HAL must exist on the device.
- If the HIDL composer HAL exists, it must be at least version 2.0.
- See DeviceManifestTest.GrallocHal -->
- <hal format="hidl" optional="true">
- <name>android.hardware.graphics.allocator</name>
- <!-- New, non-Go devices should use 4.0 or the AIDL hal.
- See DeviceManifestTest.GrallocVersionCompatibility. -->
- <version>2.0</version>
- <version>3.0</version>
- <version>4.0</version>
- <interface>
- <name>IAllocator</name>
- <instance>default</instance>
- </interface>
- </hal>
<hal format="aidl" optional="true">
<name>android.hardware.graphics.allocator</name>
<version>1</version>
@@ -321,17 +262,6 @@
<instance>default</instance>
</interface>
</hal>
- <!-- Either the AIDL or the HIDL composer HAL must exist on the device.
- If the HIDL composer HAL exists, it must be at least version 2.1.
- See DeviceManifestTest.ComposerHal -->
- <hal format="hidl" optional="true">
- <name>android.hardware.graphics.composer</name>
- <version>2.1-4</version>
- <interface>
- <name>IComposer</name>
- <instance>default</instance>
- </interface>
- </hal>
<hal format="aidl" optional="true">
<name>android.hardware.graphics.composer3</name>
<version>1</version>
@@ -406,23 +336,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>
@@ -502,14 +415,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>
@@ -665,23 +570,6 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.sensors</name>
- <version>1.0</version>
- <version>2.0-1</version>
- <interface>
- <name>ISensors</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.soundtrigger</name>
- <version>2.3</version>
- <interface>
- <name>ISoundTriggerHw</name>
- <instance>default</instance>
- </interface>
- </hal>
<hal format="aidl" optional="true">
<name>android.hardware.soundtrigger3</name>
<version>1</version>
@@ -730,14 +618,6 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.tv.tuner</name>
- <version>1.0-1</version>
- <interface>
- <name>ITuner</name>
- <instance>default</instance>
- </interface>
- </hal>
<hal format="aidl" optional="true">
<name>android.hardware.tv.tuner</name>
<version>1</version>
@@ -746,11 +626,11 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.usb</name>
- <version>1.0-3</version>
+ <hal format="aidl" optional="true">
+ <name>android.hardware.tv.input</name>
+ <version>1</version>
<interface>
- <name>IUsb</name>
+ <name>ITvInput</name>
<instance>default</instance>
</interface>
</hal>
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/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/composer/2.2/utils/vts/RenderEngineVts.cpp b/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
index 4a33fb5..1700b2a 100644
--- a/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
+++ b/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
@@ -71,14 +71,12 @@
});
auto texture = std::make_shared<renderengine::impl::ExternalTexture>(
mGraphicBuffer, *mRenderEngine, renderengine::impl::ExternalTexture::Usage::WRITEABLE);
- auto [status, readyFence] = mRenderEngine
- ->drawLayers(mDisplaySettings, compositionLayers, texture,
- true, std::move(bufferFence))
- .get();
- int fd = readyFence.release();
- if (fd != -1) {
- ASSERT_EQ(0, sync_wait(fd, -1));
- ASSERT_EQ(0, close(fd));
+ auto result = mRenderEngine
+ ->drawLayers(mDisplaySettings, compositionLayers, texture, true,
+ std::move(bufferFence))
+ .get();
+ if (result.ok()) {
+ result.value()->waitForever(LOG_TAG);
}
}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/ChangedCompositionTypes.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/ChangedCompositionTypes.aidl
index ddd45b7..9e8c768 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/ChangedCompositionTypes.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/ChangedCompositionTypes.aidl
@@ -23,7 +23,6 @@
parcelable ChangedCompositionTypes {
/**
* The display which this commands refers to.
- * @see IComposer.createDisplay
*/
long display;
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/ClientTargetPropertyWithBrightness.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/ClientTargetPropertyWithBrightness.aidl
index ba6fe97..ea54a89 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/ClientTargetPropertyWithBrightness.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/ClientTargetPropertyWithBrightness.aidl
@@ -23,7 +23,6 @@
parcelable ClientTargetPropertyWithBrightness {
/**
* The display which this commands refers to.
- * @see IComposer.createDisplay
*/
long display;
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayCommand.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayCommand.aidl
index b6df147..4f69aee 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayCommand.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayCommand.aidl
@@ -26,7 +26,6 @@
parcelable DisplayCommand {
/**
* The display which this commands refers to.
- * @see IComposer.createDisplay
*/
long display;
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayRequest.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayRequest.aidl
index 27fe1e6..3a50b6e 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayRequest.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayRequest.aidl
@@ -34,7 +34,6 @@
/**
* The display which this commands refers to.
- * @see IComposer.createDisplay
*/
long display;
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/PresentFence.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/PresentFence.aidl
index 244b4e5..b757656 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/PresentFence.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/PresentFence.aidl
@@ -20,7 +20,6 @@
parcelable PresentFence {
/**
* The display which this commands refers to.
- * @see IComposer.createDisplay
*/
long display;
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/PresentOrValidate.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/PresentOrValidate.aidl
index 5ae8940..e15dbf2 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/PresentOrValidate.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/PresentOrValidate.aidl
@@ -20,7 +20,6 @@
parcelable PresentOrValidate {
/**
* The display which this commands refers to.
- * @see IComposer.createDisplay
*/
long display;
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/ReleaseFences.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/ReleaseFences.aidl
index 459a042..58649d5 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/ReleaseFences.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/ReleaseFences.aidl
@@ -20,7 +20,6 @@
parcelable ReleaseFences {
/**
* The display which this commands refers to.
- * @see IComposer.createDisplay
*/
long display;
@VintfStability
diff --git a/graphics/composer/aidl/vts/RenderEngineVts.cpp b/graphics/composer/aidl/vts/RenderEngineVts.cpp
index 71b011c..66779c8 100644
--- a/graphics/composer/aidl/vts/RenderEngineVts.cpp
+++ b/graphics/composer/aidl/vts/RenderEngineVts.cpp
@@ -66,14 +66,12 @@
auto texture = std::make_shared<::android::renderengine::impl::ExternalTexture>(
mGraphicBuffer, *mRenderEngine,
::android::renderengine::impl::ExternalTexture::Usage::WRITEABLE);
- auto [status, readyFence] = mRenderEngine
- ->drawLayers(mDisplaySettings, compositionLayers, texture,
- true, std::move(bufferFence))
- .get();
- int fd = readyFence.release();
- if (fd != -1) {
- ASSERT_EQ(0, sync_wait(fd, -1));
- ASSERT_EQ(0, close(fd));
+ auto result = mRenderEngine
+ ->drawLayers(mDisplaySettings, compositionLayers, texture, true,
+ std::move(bufferFence))
+ .get();
+ if (result.ok()) {
+ result.value()->waitForever(LOG_TAG);
}
}
diff --git a/health/aidl/default/Android.bp b/health/aidl/default/Android.bp
index 0d426da..4eb3cb1 100644
--- a/health/aidl/default/Android.bp
+++ b/health/aidl/default/Android.bp
@@ -192,33 +192,14 @@
name: "android.hardware.health-service.aidl_fuzzer",
defaults: [
"libhealth_aidl_impl_user",
+ "service_fuzzer_defaults",
],
static_libs: [
"android.hardware.health-V1-ndk",
"libbase",
- "libbinder_random_parcel",
- "libcutils",
"liblog",
- "libutils",
"fuzz_libhealth_aidl_impl",
],
- target: {
- android: {
- shared_libs: [
- "libbinder_ndk",
- "libbinder",
- ],
- },
- host: {
- static_libs: [
- "libbinder_ndk",
- "libbinder",
- ],
- },
- darwin: {
- enabled: false,
- },
- },
srcs: ["fuzzer.cpp"],
fuzz_config: {
cc: [
diff --git a/identity/aidl/default/EicOpsImpl.cc b/identity/aidl/default/EicOpsImpl.cc
index 3fd9f1d..b6d324f 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;
}
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/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/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/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/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/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/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/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/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
index 1caf8bc..5473062 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
@@ -1070,8 +1070,20 @@
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;
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index fa7dccb..4f5d821 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -741,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
@@ -994,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()
@@ -1066,6 +1068,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()
@@ -1148,6 +1151,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";
@@ -1295,6 +1299,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,
@@ -1416,6 +1421,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()
@@ -1466,6 +1472,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()
@@ -1535,6 +1542,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,
@@ -1569,6 +1577,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()));
@@ -1584,6 +1593,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()
@@ -1709,6 +1719,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()
@@ -2211,6 +2222,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,
@@ -2282,6 +2294,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()
@@ -2323,6 +2336,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;
@@ -2377,6 +2391,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()
@@ -2430,6 +2445,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()
@@ -2507,6 +2523,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)
@@ -2524,6 +2541,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;
@@ -2557,6 +2575,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;
@@ -2590,6 +2609,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;
@@ -2628,6 +2648,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
@@ -2670,6 +2691,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,
@@ -2826,6 +2848,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;
@@ -3541,6 +3564,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)
@@ -4391,6 +4415,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)
@@ -4458,6 +4483,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)
@@ -4943,6 +4969,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)
@@ -5133,6 +5160,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)
@@ -5553,6 +5581,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)
@@ -6249,6 +6278,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);
@@ -6917,6 +6947,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);
@@ -7227,6 +7258,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)
@@ -7285,6 +7317,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));
@@ -7954,6 +7987,7 @@
.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);
@@ -8267,6 +8301,7 @@
GenerateKeyMintEcKey(curve, &kmPubKey);
for (auto localCurve : ValidCurves()) {
+ SCOPED_TRACE(testing::Message() << "local-curve-" << localCurve);
if (localCurve == curve) {
continue;
}
diff --git a/sensors/aidl/vts/AndroidTest.xml b/sensors/aidl/vts/AndroidTest.xml
new file mode 100644
index 0000000..99caf28
--- /dev/null
+++ b/sensors/aidl/vts/AndroidTest.xml
@@ -0,0 +1,34 @@
+<?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 VtsAidlHalSensorsTargetTest.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-native" />
+
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+ <target_preparer class="com.android.tradefed.targetprep.StopServicesSetup"/>
+
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="VtsAidlHalSensorsTargetTest->/data/local/tmp/VtsAidlHalSensorsTargetTest" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-timeout" value="900000" />
+ <option name="runtime-hint" value="300000"/>
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="VtsAidlHalSensorsTargetTest" />
+ </test>
+</configuration>
diff --git a/soundtrigger/aidl/Android.bp b/soundtrigger/aidl/Android.bp
index 0658519..426bf48 100644
--- a/soundtrigger/aidl/Android.bp
+++ b/soundtrigger/aidl/Android.bp
@@ -23,7 +23,7 @@
],
stability: "vintf",
imports: [
- "android.media.soundtrigger.types-V1",
+ "android.media.soundtrigger.types",
],
backend: {
cpp: {
@@ -39,6 +39,20 @@
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-V2"
+
+// 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/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/tv/input/aidl/Android.bp b/tv/input/aidl/Android.bp
new file mode 100644
index 0000000..1987174
--- /dev/null
+++ b/tv/input/aidl/Android.bp
@@ -0,0 +1,27 @@
+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.tv.input",
+ vendor_available: true,
+ srcs: ["android/hardware/tv/input/*.aidl"],
+ imports: [
+ "android.hardware.common-V2",
+ "android.media.audio.common.types-V1",
+ ],
+ stability: "vintf",
+ backend: {
+ java: {
+ sdk_version: "module_current",
+ },
+ cpp: {
+ enabled: false,
+ },
+ },
+}
diff --git a/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/CableConnectionStatus.aidl b/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/CableConnectionStatus.aidl
new file mode 100644
index 0000000..a48bdb1
--- /dev/null
+++ b/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/CableConnectionStatus.aidl
@@ -0,0 +1,40 @@
+/*
+ * 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.tv.input;
+@Backing(type="int") @VintfStability
+enum CableConnectionStatus {
+ UNKNOWN = 0,
+ CONNECTED = 1,
+ DISCONNECTED = 2,
+}
diff --git a/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/ITvInput.aidl b/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/ITvInput.aidl
new file mode 100644
index 0000000..f8d5e05
--- /dev/null
+++ b/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/ITvInput.aidl
@@ -0,0 +1,45 @@
+/*
+ * 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.tv.input;
+@VintfStability
+interface ITvInput {
+ void closeStream(in int deviceId, in int streamId);
+ android.hardware.tv.input.TvStreamConfig[] getStreamConfigurations(in int deviceId);
+ android.hardware.common.NativeHandle openStream(in int deviceId, in int streamId);
+ void setCallback(in android.hardware.tv.input.ITvInputCallback callback);
+ const int STATUS_UNKNOWN = 1;
+ const int STATUS_NO_RESOURCE = 2;
+ const int STATUS_INVALID_ARGUMENTS = 3;
+ const int STATUS_INVALID_STATE = 4;
+}
diff --git a/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/ITvInputCallback.aidl b/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/ITvInputCallback.aidl
new file mode 100644
index 0000000..7f2aff6
--- /dev/null
+++ b/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/ITvInputCallback.aidl
@@ -0,0 +1,38 @@
+/*
+ * 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.tv.input;
+@VintfStability
+interface ITvInputCallback {
+ void notify(in android.hardware.tv.input.TvInputEvent event);
+}
diff --git a/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/TvInputDeviceInfo.aidl b/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/TvInputDeviceInfo.aidl
new file mode 100644
index 0000000..d095146
--- /dev/null
+++ b/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/TvInputDeviceInfo.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.tv.input;
+@VintfStability
+parcelable TvInputDeviceInfo {
+ int deviceId;
+ android.hardware.tv.input.TvInputType type;
+ int portId;
+ android.hardware.tv.input.CableConnectionStatus cableConnectionStatus;
+ android.media.audio.common.AudioDevice audioDevice;
+}
diff --git a/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/TvInputEvent.aidl b/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/TvInputEvent.aidl
new file mode 100644
index 0000000..cfa8a34
--- /dev/null
+++ b/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/TvInputEvent.aidl
@@ -0,0 +1,39 @@
+/*
+ * 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.tv.input;
+@VintfStability
+parcelable TvInputEvent {
+ android.hardware.tv.input.TvInputEventType type;
+ android.hardware.tv.input.TvInputDeviceInfo deviceInfo;
+}
diff --git a/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/TvInputEventType.aidl b/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/TvInputEventType.aidl
new file mode 100644
index 0000000..a9f518a
--- /dev/null
+++ b/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/TvInputEventType.aidl
@@ -0,0 +1,40 @@
+/*
+ * 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.tv.input;
+@Backing(type="int") @VintfStability
+enum TvInputEventType {
+ DEVICE_AVAILABLE = 1,
+ DEVICE_UNAVAILABLE = 2,
+ STREAM_CONFIGURATIONS_CHANGED = 3,
+}
diff --git a/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/TvInputType.aidl b/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/TvInputType.aidl
new file mode 100644
index 0000000..7e44a7d
--- /dev/null
+++ b/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/TvInputType.aidl
@@ -0,0 +1,47 @@
+/*
+ * 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.tv.input;
+@Backing(type="int") @VintfStability
+enum TvInputType {
+ OTHER = 1,
+ TUNER = 2,
+ COMPOSITE = 3,
+ SVIDEO = 4,
+ SCART = 5,
+ COMPONENT = 6,
+ VGA = 7,
+ DVI = 8,
+ HDMI = 9,
+ DISPLAY_PORT = 10,
+}
diff --git a/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/TvStreamConfig.aidl b/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/TvStreamConfig.aidl
new file mode 100644
index 0000000..8378ff3
--- /dev/null
+++ b/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/TvStreamConfig.aidl
@@ -0,0 +1,40 @@
+/*
+ * 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.tv.input;
+@VintfStability
+parcelable TvStreamConfig {
+ int streamId;
+ int maxVideoWidth;
+ int maxVideoHeight;
+}
diff --git a/tv/input/aidl/android/hardware/tv/input/CableConnectionStatus.aidl b/tv/input/aidl/android/hardware/tv/input/CableConnectionStatus.aidl
new file mode 100644
index 0000000..64b79dd
--- /dev/null
+++ b/tv/input/aidl/android/hardware/tv/input/CableConnectionStatus.aidl
@@ -0,0 +1,31 @@
+/*
+ * 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.tv.input;
+
+/**
+ * Status of cable connection.
+ * This status is for devices having availability to detect the cable in a mechanical way,
+ * regardless of whether the connected external device is electrically on or not.
+ * If the device does not have such capability, you must use UNKNOWN.
+ */
+@VintfStability
+@Backing(type="int")
+enum CableConnectionStatus {
+ UNKNOWN = 0,
+ CONNECTED = 1,
+ DISCONNECTED = 2,
+}
diff --git a/tv/input/aidl/android/hardware/tv/input/ITvInput.aidl b/tv/input/aidl/android/hardware/tv/input/ITvInput.aidl
new file mode 100644
index 0000000..31d6586
--- /dev/null
+++ b/tv/input/aidl/android/hardware/tv/input/ITvInput.aidl
@@ -0,0 +1,76 @@
+/*
+ * 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.tv.input;
+
+import android.hardware.common.NativeHandle;
+import android.hardware.tv.input.ITvInputCallback;
+import android.hardware.tv.input.TvStreamConfig;
+
+@VintfStability
+interface ITvInput {
+ /**
+ * ServiceSpecificException values for ITvInput requests
+ */
+ const int STATUS_UNKNOWN = 1;
+ const int STATUS_NO_RESOURCE = 2;
+ const int STATUS_INVALID_ARGUMENTS = 3;
+ const int STATUS_INVALID_STATE = 4;
+
+ /**
+ * Closes a specific stream in a device.
+ *
+ * @param deviceId Device ID for the stream to close.
+ * @param streamId Stream ID for the stream to close.
+ * @throws ServiceSpecificException with values from the ITvInput::STATUS_* constants
+ */
+ void closeStream(in int deviceId, in int streamId);
+
+ /**
+ * Gets stream configurations for a specific device.
+ *
+ * The configs object is valid only until the next
+ * STREAM_CONFIGURATIONS_CHANGED event.
+ *
+ * @param deviceId Device ID for the configurations.
+ * @return the array of available configurations.
+ * @throws ServiceSpecificException with values from the ITvInput::STATUS_* constants
+ */
+ TvStreamConfig[] getStreamConfigurations(in int deviceId);
+
+ /**
+ * Opens a specific stream in a device.
+ *
+ * @param deviceId Device ID for the stream to open.
+ * @param streamId Stream ID for the stream to open. Must be one of the
+ * stream IDs returned from getStreamConfigurations().
+ * @return the handle for sideband stream.
+ * @throws ServiceSpecificException with values from the ITvInput::STATUS_* constants
+ */
+ NativeHandle openStream(in int deviceId, in int streamId);
+
+ /**
+ * Sets a callback for events.
+ *
+ * Note that initially no device is available in the client side, so the
+ * implementation must notify all the currently available devices including
+ * static devices via callback once callback is set.
+ *
+ * @param callback Callback object to pass events.
+ * @throws ServiceSpecificException with values from the ITvInput::STATUS_* constants
+ */
+ void setCallback(in ITvInputCallback callback);
+}
diff --git a/tv/input/aidl/android/hardware/tv/input/ITvInputCallback.aidl b/tv/input/aidl/android/hardware/tv/input/ITvInputCallback.aidl
new file mode 100644
index 0000000..fc7492d
--- /dev/null
+++ b/tv/input/aidl/android/hardware/tv/input/ITvInputCallback.aidl
@@ -0,0 +1,30 @@
+/*
+ * 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.tv.input;
+
+import android.hardware.tv.input.TvInputEvent;
+
+@VintfStability
+interface ITvInputCallback {
+ /**
+ * Notifies the client that an event has occurred. For possible event types,
+ * check TvInputEventType.
+ *
+ * @param event Event passed to the client.
+ */
+ void notify(in TvInputEvent event);
+}
diff --git a/tv/input/aidl/android/hardware/tv/input/TvInputDeviceInfo.aidl b/tv/input/aidl/android/hardware/tv/input/TvInputDeviceInfo.aidl
new file mode 100644
index 0000000..2782e90
--- /dev/null
+++ b/tv/input/aidl/android/hardware/tv/input/TvInputDeviceInfo.aidl
@@ -0,0 +1,36 @@
+/*
+ * 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.tv.input;
+
+import android.hardware.tv.input.CableConnectionStatus;
+import android.hardware.tv.input.TvInputType;
+import android.media.audio.common.AudioDevice;
+
+@VintfStability
+parcelable TvInputDeviceInfo {
+ int deviceId;
+ TvInputType type;
+
+ /* HDMI port ID number. e.g. 2 for HDMI 2. */
+ int portId;
+
+ /* Cable connection status. */
+ CableConnectionStatus cableConnectionStatus;
+
+ /* Audio device info. */
+ AudioDevice audioDevice;
+}
diff --git a/tv/input/aidl/android/hardware/tv/input/TvInputEvent.aidl b/tv/input/aidl/android/hardware/tv/input/TvInputEvent.aidl
new file mode 100644
index 0000000..66ca7aa
--- /dev/null
+++ b/tv/input/aidl/android/hardware/tv/input/TvInputEvent.aidl
@@ -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.
+ */
+
+package android.hardware.tv.input;
+
+import android.hardware.tv.input.TvInputDeviceInfo;
+import android.hardware.tv.input.TvInputEventType;
+
+@VintfStability
+parcelable TvInputEvent {
+ TvInputEventType type;
+
+ /**
+ * TvInputEventType::DEVICE_AVAILABLE: all fields are relevant.
+ * TvInputEventType::DEVICE_UNAVAILABLE: only deviceId is relevant.
+ * TvInputEventType::STREAM_CONFIGURATIONS_CHANGED: only deviceId is relevant.
+ */
+ TvInputDeviceInfo deviceInfo;
+}
diff --git a/tv/input/aidl/android/hardware/tv/input/TvInputEventType.aidl b/tv/input/aidl/android/hardware/tv/input/TvInputEventType.aidl
new file mode 100644
index 0000000..fcbc3c2
--- /dev/null
+++ b/tv/input/aidl/android/hardware/tv/input/TvInputEventType.aidl
@@ -0,0 +1,77 @@
+/*
+ * 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.tv.input;
+
+@VintfStability
+@Backing(type="int")
+enum TvInputEventType {
+ /**
+ * Hardware notifies the framework that a device is available.
+ *
+ * Note that DEVICE_AVAILABLE and DEVICE_UNAVAILABLE events do not represent
+ * hotplug events (i.e. plugging cable into or out of the physical port).
+ * These events notify the framework whether the port is available or not.
+ * For a concrete example, when a user plugs in or pulls out the HDMI cable
+ * from a HDMI port, it does not generate DEVICE_AVAILABLE and/or
+ * DEVICE_UNAVAILABLE events. However, if a user inserts a pluggable USB
+ * tuner into the Android device, it must generate a DEVICE_AVAILABLE event
+ * and when the port is removed, it must generate a DEVICE_UNAVAILABLE
+ * event.
+ *
+ * For hotplug events, please see STREAM_CONFIGURATION_CHANGED for more
+ * details.
+ *
+ * HAL implementation must register devices by using this event when the
+ * device boots up. The framework must recognize device reported via this
+ * event only.
+ */
+ DEVICE_AVAILABLE = 1,
+
+ /**
+ * Hardware notifies the framework that a device is unavailable.
+ *
+ * HAL implementation must generate this event when a device registered
+ * by DEVICE_AVAILABLE is no longer available. For example,
+ * the event can indicate that a USB tuner is plugged out from the Android
+ * device.
+ *
+ * Note that this event is not for indicating cable plugged out of the port;
+ * for that purpose, the implementation must use
+ * STREAM_CONFIGURATION_CHANGED event. This event represents the port itself
+ * being no longer available.
+ */
+ DEVICE_UNAVAILABLE = 2,
+
+ /**
+ * Stream configurations are changed. Client must regard all open streams
+ * at the specific device are closed, and must call
+ * getStreamConfigurations() again, opening some of them if necessary.
+ *
+ * HAL implementation must generate this event when the available stream
+ * configurations change for any reason. A typical use case of this event
+ * is to notify the framework that the input signal has changed resolution,
+ * or that the cable is plugged out so that the number of available streams
+ * is 0.
+ *
+ * The implementation must use this event to indicate hotplug status of the
+ * port. the framework regards input devices with no available streams as
+ * disconnected, so the implementation can generate this event with no
+ * available streams to indicate that this device is disconnected, and vice
+ * versa.
+ */
+ STREAM_CONFIGURATIONS_CHANGED = 3,
+}
diff --git a/tv/input/aidl/android/hardware/tv/input/TvInputType.aidl b/tv/input/aidl/android/hardware/tv/input/TvInputType.aidl
new file mode 100644
index 0000000..a0f8270
--- /dev/null
+++ b/tv/input/aidl/android/hardware/tv/input/TvInputType.aidl
@@ -0,0 +1,35 @@
+/*
+ * 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.tv.input;
+
+/**
+ * Type of physical TV input.
+ */
+@VintfStability
+@Backing(type="int")
+enum TvInputType {
+ OTHER = 1,
+ TUNER = 2,
+ COMPOSITE = 3,
+ SVIDEO = 4,
+ SCART = 5,
+ COMPONENT = 6,
+ VGA = 7,
+ DVI = 8,
+ HDMI = 9,
+ DISPLAY_PORT = 10,
+}
diff --git a/tv/input/aidl/android/hardware/tv/input/TvStreamConfig.aidl b/tv/input/aidl/android/hardware/tv/input/TvStreamConfig.aidl
new file mode 100644
index 0000000..af86953
--- /dev/null
+++ b/tv/input/aidl/android/hardware/tv/input/TvStreamConfig.aidl
@@ -0,0 +1,28 @@
+/*
+ * 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.tv.input;
+
+@VintfStability
+parcelable TvStreamConfig {
+ int streamId;
+
+ /* Maximum video width in pixel. */
+ int maxVideoWidth;
+
+ /* Maximum video height in pixel. */
+ int maxVideoHeight;
+}
diff --git a/tv/input/aidl/default/Android.bp b/tv/input/aidl/default/Android.bp
new file mode 100644
index 0000000..66148c8
--- /dev/null
+++ b/tv/input/aidl/default/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_binary {
+ name: "android.hardware.tv.input-service.example",
+ relative_install_path: "hw",
+ init_rc: ["input-default.rc"],
+ vintf_fragments: ["input-default.xml"],
+ vendor: true,
+ srcs: [
+ "TvInput.cpp",
+ "service.cpp",
+ ],
+ static_libs: [
+ "libaidlcommonsupport",
+ ],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libutils",
+ "libcutils",
+ "libbinder_ndk",
+ "android.hardware.tv.input-V1-ndk",
+ ],
+}
diff --git a/tv/input/aidl/default/TvInput.cpp b/tv/input/aidl/default/TvInput.cpp
new file mode 100644
index 0000000..6c3a138
--- /dev/null
+++ b/tv/input/aidl/default/TvInput.cpp
@@ -0,0 +1,143 @@
+/*
+ * 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.tv.input-service.example"
+
+#include <utils/Log.h>
+
+#include "TvInput.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace tv {
+namespace input {
+
+TvInput::TvInput() {}
+
+void TvInput::init() {
+ // Set up TvInputDeviceInfo and TvStreamConfig
+ mDeviceInfos[0] = shared_ptr<TvInputDeviceInfoWrapper>(
+ new TvInputDeviceInfoWrapper(0, TvInputType::TUNER, true));
+ mDeviceInfos[1] = shared_ptr<TvInputDeviceInfoWrapper>(
+ new TvInputDeviceInfoWrapper(1, TvInputType::HDMI, true));
+ mDeviceInfos[3] = shared_ptr<TvInputDeviceInfoWrapper>(
+ new TvInputDeviceInfoWrapper(3, TvInputType::DISPLAY_PORT, true));
+
+ mStreamConfigs[0] = {
+ {1, shared_ptr<TvStreamConfigWrapper>(new TvStreamConfigWrapper(1, 720, 1080, false))}};
+ mStreamConfigs[1] = {{11, shared_ptr<TvStreamConfigWrapper>(
+ new TvStreamConfigWrapper(11, 360, 480, false))}};
+ mStreamConfigs[3] = {{5, shared_ptr<TvStreamConfigWrapper>(
+ new TvStreamConfigWrapper(5, 1080, 1920, false))}};
+}
+
+::ndk::ScopedAStatus TvInput::setCallback(const shared_ptr<ITvInputCallback>& in_callback) {
+ ALOGV("%s", __FUNCTION__);
+
+ mCallback = in_callback;
+
+ TvInputEvent event;
+ event.type = TvInputEventType::DEVICE_AVAILABLE;
+
+ event.deviceInfo = mDeviceInfos[0]->deviceInfo;
+ mCallback->notify(event);
+
+ event.deviceInfo = mDeviceInfos[1]->deviceInfo;
+ mCallback->notify(event);
+
+ event.deviceInfo = mDeviceInfos[3]->deviceInfo;
+ mCallback->notify(event);
+
+ return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TvInput::getStreamConfigurations(int32_t in_deviceId,
+ vector<TvStreamConfig>* _aidl_return) {
+ ALOGV("%s", __FUNCTION__);
+
+ if (mStreamConfigs.count(in_deviceId) == 0) {
+ ALOGW("Device with id %d isn't available", in_deviceId);
+ return ::ndk::ScopedAStatus::fromServiceSpecificError(STATUS_INVALID_ARGUMENTS);
+ }
+
+ for (auto const& iconfig : mStreamConfigs[in_deviceId]) {
+ _aidl_return->push_back(iconfig.second->streamConfig);
+ }
+
+ return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TvInput::openStream(int32_t in_deviceId, int32_t in_streamId,
+ NativeHandle* _aidl_return) {
+ ALOGV("%s", __FUNCTION__);
+
+ if (mStreamConfigs.count(in_deviceId) == 0 ||
+ mStreamConfigs[in_deviceId].count(in_streamId) == 0) {
+ ALOGW("Stream with device id %d, stream id %d isn't available", in_deviceId, in_streamId);
+ return ::ndk::ScopedAStatus::fromServiceSpecificError(STATUS_INVALID_ARGUMENTS);
+ }
+ if (mStreamConfigs[in_deviceId][in_streamId]->isOpen) {
+ ALOGW("Stream with device id %d, stream id %d is already opened", in_deviceId, in_streamId);
+ return ::ndk::ScopedAStatus::fromServiceSpecificError(STATUS_INVALID_STATE);
+ }
+ mStreamConfigs[in_deviceId][in_streamId]->handle = createNativeHandle(in_streamId);
+ mStreamConfigs[in_deviceId][in_streamId]->isOpen = true;
+ NativeHandle aidlHandle = makeToAidl(mStreamConfigs[in_deviceId][in_streamId]->handle);
+ _aidl_return = &aidlHandle;
+ return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TvInput::closeStream(int32_t in_deviceId, int32_t in_streamId) {
+ ALOGV("%s", __FUNCTION__);
+
+ if (mStreamConfigs.count(in_deviceId) == 0 ||
+ mStreamConfigs[in_deviceId].count(in_streamId) == 0) {
+ ALOGW("Stream with device id %d, stream id %d isn't available", in_deviceId, in_streamId);
+ return ::ndk::ScopedAStatus::fromServiceSpecificError(STATUS_INVALID_ARGUMENTS);
+ }
+ if (!mStreamConfigs[in_deviceId][in_streamId]->isOpen) {
+ ALOGW("Stream with device id %d, stream id %d is already closed", in_deviceId, in_streamId);
+ return ::ndk::ScopedAStatus::fromServiceSpecificError(STATUS_INVALID_STATE);
+ }
+ releaseNativeHandle(mStreamConfigs[in_deviceId][in_streamId]->handle);
+ mStreamConfigs[in_deviceId][in_streamId]->handle = nullptr;
+ mStreamConfigs[in_deviceId][in_streamId]->isOpen = false;
+ return ::ndk::ScopedAStatus::ok();
+}
+
+native_handle_t* TvInput::createNativeHandle(int fd) {
+ native_handle_t* nativeHandle = native_handle_create(1, 0);
+ if (nativeHandle == nullptr) {
+ ALOGE("[TVInput] Failed to create native_handle %d", errno);
+ return nullptr;
+ }
+ if (nativeHandle->numFds > 0) {
+ nativeHandle->data[0] = dup(fd);
+ }
+ return nativeHandle;
+}
+
+void TvInput::releaseNativeHandle(native_handle_t* handle) {
+ native_handle_close(handle);
+ native_handle_delete(handle);
+}
+
+} // namespace input
+} // namespace tv
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/tv/input/aidl/default/TvInput.h b/tv/input/aidl/default/TvInput.h
new file mode 100644
index 0000000..a72bca3
--- /dev/null
+++ b/tv/input/aidl/default/TvInput.h
@@ -0,0 +1,62 @@
+/*
+ * 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/tv/input/BnTvInput.h>
+#include <utils/KeyedVector.h>
+
+#include <map>
+#include "TvInputDeviceInfoWrapper.h"
+#include "TvStreamConfigWrapper.h"
+
+using namespace android;
+using namespace std;
+using ::aidl::android::hardware::common::NativeHandle;
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace tv {
+namespace input {
+
+class TvInput : public BnTvInput {
+ public:
+ TvInput();
+
+ ::ndk::ScopedAStatus setCallback(const shared_ptr<ITvInputCallback>& in_callback) override;
+ ::ndk::ScopedAStatus getStreamConfigurations(int32_t in_deviceId,
+ vector<TvStreamConfig>* _aidl_return) override;
+ ::ndk::ScopedAStatus openStream(int32_t in_deviceId, int32_t in_streamId,
+ NativeHandle* _aidl_return) override;
+ ::ndk::ScopedAStatus closeStream(int32_t in_deviceId, int32_t in_streamId) override;
+
+ void init();
+
+ private:
+ native_handle_t* createNativeHandle(int fd);
+ void releaseNativeHandle(native_handle_t* handle);
+
+ shared_ptr<ITvInputCallback> mCallback;
+ map<int32_t, shared_ptr<TvInputDeviceInfoWrapper>> mDeviceInfos;
+ map<int32_t, map<int32_t, shared_ptr<TvStreamConfigWrapper>>> mStreamConfigs;
+};
+
+} // namespace input
+} // namespace tv
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/tv/input/aidl/default/TvInputDeviceInfoWrapper.h b/tv/input/aidl/default/TvInputDeviceInfoWrapper.h
new file mode 100644
index 0000000..d844cc8
--- /dev/null
+++ b/tv/input/aidl/default/TvInputDeviceInfoWrapper.h
@@ -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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/tv/input/TvInputDeviceInfo.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace tv {
+namespace input {
+
+class TvInputDeviceInfoWrapper {
+ public:
+ TvInputDeviceInfoWrapper() {}
+ TvInputDeviceInfoWrapper(int32_t deviceId_, TvInputType type_, bool isAvailable_) {
+ deviceInfo.deviceId = deviceId_;
+ deviceInfo.type = type_;
+ isAvailable = isAvailable_;
+ }
+
+ TvInputDeviceInfo deviceInfo;
+ bool isAvailable;
+};
+} // namespace input
+} // namespace tv
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/tv/input/aidl/default/TvStreamConfigWrapper.h b/tv/input/aidl/default/TvStreamConfigWrapper.h
new file mode 100644
index 0000000..05c7ca3
--- /dev/null
+++ b/tv/input/aidl/default/TvStreamConfigWrapper.h
@@ -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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/tv/input/TvStreamConfig.h>
+#include <aidlcommonsupport/NativeHandle.h>
+
+using namespace std;
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace tv {
+namespace input {
+
+class TvStreamConfigWrapper {
+ public:
+ TvStreamConfigWrapper() {}
+ TvStreamConfigWrapper(int32_t streamId_, int32_t maxVideoWidth_, int32_t maxVideoHeight_,
+ bool isOpen_) {
+ streamConfig.streamId = streamId_;
+ streamConfig.maxVideoWidth = maxVideoWidth_;
+ streamConfig.maxVideoHeight = maxVideoHeight_;
+ isOpen = isOpen_;
+ handle = nullptr;
+ }
+
+ TvStreamConfig streamConfig;
+ bool isOpen;
+ native_handle_t* handle;
+};
+} // namespace input
+} // namespace tv
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/tv/input/aidl/default/input-default.rc b/tv/input/aidl/default/input-default.rc
new file mode 100644
index 0000000..1958b5c
--- /dev/null
+++ b/tv/input/aidl/default/input-default.rc
@@ -0,0 +1,5 @@
+service vendor.input-default /vendor/bin/hw/android.hardware.tv.input-service.example
+ interface aidl android.hardware.tv.input.ITvInput/default
+ class hal
+ user system
+ group system
diff --git a/tv/input/aidl/default/input-default.xml b/tv/input/aidl/default/input-default.xml
new file mode 100644
index 0000000..38ba151
--- /dev/null
+++ b/tv/input/aidl/default/input-default.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.tv.input</name>
+ <fqname>ITvInput/default</fqname>
+ </hal>
+</manifest>
\ No newline at end of file
diff --git a/tv/input/aidl/default/service.cpp b/tv/input/aidl/default/service.cpp
new file mode 100644
index 0000000..1021206
--- /dev/null
+++ b/tv/input/aidl/default/service.cpp
@@ -0,0 +1,40 @@
+/*
+ * 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.tv.input-service.example"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <utils/Log.h>
+
+#include "TvInput.h"
+
+using ::aidl::android::hardware::tv::input::TvInput;
+
+int main() {
+ ABinderProcess_setThreadPoolMaxThreadCount(8);
+ std::shared_ptr<TvInput> tvInput = ndk::SharedRefBase::make<TvInput>();
+ tvInput->init();
+
+ const std::string instance = std::string() + TvInput::descriptor + "/default";
+ binder_status_t status =
+ AServiceManager_addService(tvInput->asBinder().get(), instance.c_str());
+ CHECK(status == STATUS_OK);
+
+ ABinderProcess_joinThreadPool();
+ return EXIT_FAILURE; // should not reached
+}
diff --git a/tv/input/aidl/vts/functional/Android.bp b/tv/input/aidl/vts/functional/Android.bp
new file mode 100644
index 0000000..9829b6d
--- /dev/null
+++ b/tv/input/aidl/vts/functional/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"],
+}
+
+cc_test {
+ name: "VtsHalTvInputTargetTest",
+ defaults: ["VtsHalTargetTestDefaults","use_libaidlvintf_gtest_helper_static",],
+ srcs: ["VtsHalTvInputTargetTest.cpp"],
+ static_libs: [
+ "android.hardware.tv.input-V1-ndk",
+ "android.media.audio.common.types-V1-ndk",
+ "android.hardware.common-V2-ndk",
+ "libaidlcommonsupport",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+ shared_libs: [
+ "libbinder_ndk",
+ "libvndksupport",
+ ],
+ require_root: true,
+}
diff --git a/tv/input/aidl/vts/functional/VtsHalTvInputTargetTest.cpp b/tv/input/aidl/vts/functional/VtsHalTvInputTargetTest.cpp
new file mode 100644
index 0000000..ec83e29
--- /dev/null
+++ b/tv/input/aidl/vts/functional/VtsHalTvInputTargetTest.cpp
@@ -0,0 +1,296 @@
+/*
+ * 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 "VtsHalTvInputTargetTest.h"
+
+#include <android-base/properties.h>
+#include <android/binder_ibinder.h>
+#include <android/binder_process.h>
+#include <android/binder_status.h>
+
+using namespace VtsHalTvInputTargetTest;
+
+TvInputAidlTest::TvInputCallback::TvInputCallback(shared_ptr<TvInputAidlTest> parent)
+ : parent_(parent) {}
+
+::ndk::ScopedAStatus TvInputAidlTest::TvInputCallback::notify(const TvInputEvent& in_event) {
+ unique_lock<mutex> lock(parent_->mutex_);
+
+ switch (in_event.type) {
+ case TvInputEventType::DEVICE_AVAILABLE:
+ parent_->onDeviceAvailable(in_event.deviceInfo);
+ break;
+ case TvInputEventType::DEVICE_UNAVAILABLE:
+ parent_->onDeviceUnavailable(in_event.deviceInfo.deviceId);
+ break;
+ case TvInputEventType::STREAM_CONFIGURATIONS_CHANGED:
+ parent_->onStreamConfigurationsChanged(in_event.deviceInfo.deviceId);
+ break;
+ }
+ return ::ndk::ScopedAStatus::ok();
+}
+
+void TvInputAidlTest::SetUp() {
+ if (AServiceManager_isDeclared(GetParam().c_str())) {
+ ::ndk::SpAIBinder binder(AServiceManager_waitForService(GetParam().c_str()));
+ tv_input_ = ITvInput::fromBinder(binder);
+ } else {
+ tv_input_ = nullptr;
+ }
+ ASSERT_NE(tv_input_, nullptr);
+
+ tv_input_callback_ =
+ ::ndk::SharedRefBase::make<TvInputCallback>(shared_ptr<TvInputAidlTest>(this));
+ ASSERT_NE(tv_input_callback_, nullptr);
+
+ tv_input_->setCallback(tv_input_callback_);
+ // All events received within the timeout should be handled.
+ sleep(WAIT_FOR_EVENT_TIMEOUT);
+}
+
+void TvInputAidlTest::TearDown() {
+ tv_input_ = nullptr;
+}
+
+void TvInputAidlTest::onDeviceAvailable(const TvInputDeviceInfo& deviceInfo) {
+ ALOGD("onDeviceAvailable for device id %d", deviceInfo.deviceId);
+ device_info_.add(deviceInfo.deviceId, deviceInfo);
+}
+
+void TvInputAidlTest::onDeviceUnavailable(int32_t deviceId) {
+ ALOGD("onDeviceUnavailable for device id %d", deviceId);
+ device_info_.removeItem(deviceId);
+ stream_config_.removeItem(deviceId);
+}
+
+::ndk::ScopedAStatus TvInputAidlTest::onStreamConfigurationsChanged(int32_t deviceId) {
+ ALOGD("onStreamConfigurationsChanged for device id %d", deviceId);
+ return updateStreamConfigurations(deviceId);
+}
+
+::ndk::ScopedAStatus TvInputAidlTest::updateStreamConfigurations(int32_t deviceId) {
+ stream_config_.removeItem(deviceId);
+ vector<TvStreamConfig> list;
+ ::ndk::ScopedAStatus status = tv_input_->getStreamConfigurations(deviceId, &list);
+ if (status.isOk()) {
+ stream_config_.add(deviceId, list);
+ }
+ return status;
+}
+
+void TvInputAidlTest::updateAllStreamConfigurations() {
+ for (size_t i = 0; i < device_info_.size(); i++) {
+ int32_t device_id = device_info_.keyAt(i);
+ updateStreamConfigurations(device_id);
+ }
+}
+
+vector<size_t> TvInputAidlTest::getConfigIndices() {
+ vector<size_t> indices;
+ for (size_t i = 0; i < stream_config_.size(); i++) {
+ if (stream_config_.valueAt(i).size() != 0) {
+ indices.push_back(i);
+ }
+ }
+ return indices;
+}
+
+int32_t TvInputAidlTest::getNumNotIn(vector<int32_t>& nums) {
+ int32_t result = DEFAULT_ID;
+ int32_t size = static_cast<int32_t>(nums.size());
+ for (int32_t i = 0; i < size; i++) {
+ // Put every element to its target position, if possible.
+ int32_t target_pos = nums[i];
+ while (target_pos >= 0 && target_pos < size && i != target_pos &&
+ nums[i] != nums[target_pos]) {
+ swap(nums[i], nums[target_pos]);
+ target_pos = nums[i];
+ }
+ }
+
+ for (int32_t i = 0; i < size; i++) {
+ if (nums[i] != i) {
+ return i;
+ }
+ }
+ return result;
+}
+
+/*
+ * GetStreamConfigTest:
+ * Calls updateStreamConfigurations() for each existing device
+ * Checks returned results
+ */
+TEST_P(TvInputAidlTest, GetStreamConfigTest) {
+ unique_lock<mutex> lock(mutex_);
+
+ for (size_t i = 0; i < device_info_.size(); i++) {
+ int32_t device_id = device_info_.keyAt(i);
+ ALOGD("GetStreamConfigTest: device_id=%d", device_id);
+ ASSERT_TRUE(updateStreamConfigurations(device_id).isOk());
+ }
+}
+
+/*
+ * OpenAndCloseStreamTest:
+ * Calls openStream() and then closeStream() for each existing stream
+ * Checks returned results
+ */
+TEST_P(TvInputAidlTest, OpenAndCloseStreamTest) {
+ unique_lock<mutex> lock(mutex_);
+
+ updateAllStreamConfigurations();
+
+ for (size_t j = 0; j < stream_config_.size(); j++) {
+ int32_t device_id = stream_config_.keyAt(j);
+ vector<TvStreamConfig> config = stream_config_.valueAt(j);
+ for (size_t i = 0; i < config.size(); i++) {
+ int32_t stream_id = config[i].streamId;
+ ALOGD("OpenAndCloseStreamTest: open stream, device_id=%d, stream_id=%d", device_id,
+ stream_id);
+ ASSERT_TRUE(tv_input_->openStream(device_id, stream_id, &handle_).isOk());
+ ALOGD("OpenAndCloseStreamTest: close stream, device_id=%d, stream_id=%d", device_id,
+ stream_id);
+ ASSERT_TRUE(tv_input_->closeStream(device_id, stream_id).isOk());
+ }
+ }
+}
+
+/*
+ * InvalidDeviceIdTest:
+ * Calls updateStreamConfigurations(), openStream(), and closeStream()
+ * for a non-existing device
+ * Checks returned results
+ * The results should be ITvInput::STATUS_INVALID_ARGUMENTS
+ */
+TEST_P(TvInputAidlTest, InvalidDeviceIdTest) {
+ unique_lock<mutex> lock(mutex_);
+
+ vector<int32_t> device_ids;
+ for (size_t i = 0; i < device_info_.size(); i++) {
+ device_ids.push_back(device_info_.keyAt(i));
+ }
+ // Get a non-existing device ID.
+ int32_t id = getNumNotIn(device_ids);
+ ALOGD("InvalidDeviceIdTest: update stream config, device_id=%d", id);
+ ASSERT_TRUE(updateStreamConfigurations(id).getServiceSpecificError() ==
+ ITvInput::STATUS_INVALID_ARGUMENTS);
+
+ int32_t stream_id = 0;
+
+ ALOGD("InvalidDeviceIdTest: open stream, device_id=%d, stream_id=%d", id, stream_id);
+ ASSERT_TRUE(tv_input_->openStream(id, stream_id, &handle_).getServiceSpecificError() ==
+ ITvInput::STATUS_INVALID_ARGUMENTS);
+
+ ALOGD("InvalidDeviceIdTest: close stream, device_id=%d, stream_id=%d", id, stream_id);
+ ASSERT_TRUE(tv_input_->closeStream(id, stream_id).getServiceSpecificError() ==
+ ITvInput::STATUS_INVALID_ARGUMENTS);
+}
+
+/*
+ * InvalidStreamIdTest:
+ * Calls openStream(), and closeStream() for a non-existing stream
+ * Checks returned results
+ * The results should be ITvInput::STATUS_INVALID_ARGUMENTS
+ */
+TEST_P(TvInputAidlTest, InvalidStreamIdTest) {
+ unique_lock<mutex> lock(mutex_);
+
+ if (device_info_.isEmpty()) {
+ return;
+ }
+ updateAllStreamConfigurations();
+
+ int32_t device_id = device_info_.keyAt(0);
+ // Get a non-existing stream ID.
+ int32_t id = DEFAULT_ID;
+ if (stream_config_.indexOfKey(device_id) >= 0) {
+ vector<int32_t> stream_ids;
+ vector<TvStreamConfig> config = stream_config_.valueFor(device_id);
+ for (size_t i = 0; i < config.size(); i++) {
+ stream_ids.push_back(config[i].streamId);
+ }
+ id = getNumNotIn(stream_ids);
+ }
+
+ ALOGD("InvalidStreamIdTest: open stream, device_id=%d, stream_id=%d", device_id, id);
+ ASSERT_TRUE(tv_input_->openStream(device_id, id, &handle_).getServiceSpecificError() ==
+ ITvInput::STATUS_INVALID_ARGUMENTS);
+
+ ALOGD("InvalidStreamIdTest: close stream, device_id=%d, stream_id=%d", device_id, id);
+ ASSERT_TRUE(tv_input_->closeStream(device_id, id).getServiceSpecificError() ==
+ ITvInput::STATUS_INVALID_ARGUMENTS);
+}
+
+/*
+ * OpenAnOpenedStreamsTest:
+ * Calls openStream() twice for a stream (if any)
+ * Checks returned results
+ * The result of the second call should be ITvInput::STATUS_INVALID_STATE
+ */
+TEST_P(TvInputAidlTest, OpenAnOpenedStreamsTest) {
+ unique_lock<mutex> lock(mutex_);
+
+ updateAllStreamConfigurations();
+ vector<size_t> indices = getConfigIndices();
+ if (indices.empty()) {
+ return;
+ }
+ int32_t device_id = stream_config_.keyAt(indices[0]);
+ int32_t stream_id = stream_config_.valueAt(indices[0])[0].streamId;
+
+ ALOGD("OpenAnOpenedStreamsTest: open stream, device_id=%d, stream_id=%d", device_id, stream_id);
+ ASSERT_TRUE(tv_input_->openStream(device_id, stream_id, &handle_).isOk());
+
+ ALOGD("OpenAnOpenedStreamsTest: open stream, device_id=%d, stream_id=%d", device_id, stream_id);
+ ASSERT_TRUE(tv_input_->openStream(device_id, stream_id, &handle_).getServiceSpecificError() ==
+ ITvInput::STATUS_INVALID_STATE);
+
+ // close stream as subsequent tests assume no open streams
+ ALOGD("OpenAnOpenedStreamsTest: close stream, device_id=%d, stream_id=%d", device_id,
+ stream_id);
+ ASSERT_TRUE(tv_input_->closeStream(device_id, stream_id).isOk());
+}
+
+/*
+ * CloseStreamBeforeOpenTest:
+ * Calls closeStream() without calling openStream() for a stream (if any)
+ * Checks the returned result
+ * The result should be ITvInput::STATUS_INVALID_STATE
+ */
+TEST_P(TvInputAidlTest, CloseStreamBeforeOpenTest) {
+ unique_lock<mutex> lock(mutex_);
+
+ updateAllStreamConfigurations();
+ vector<size_t> indices = getConfigIndices();
+ if (indices.empty()) {
+ return;
+ }
+ int32_t device_id = stream_config_.keyAt(indices[0]);
+ int32_t stream_id = stream_config_.valueAt(indices[0])[0].streamId;
+
+ ALOGD("CloseStreamBeforeOpenTest: close stream, device_id=%d, stream_id=%d", device_id,
+ stream_id);
+ ASSERT_TRUE(tv_input_->closeStream(device_id, stream_id).getServiceSpecificError() ==
+ ITvInput::STATUS_INVALID_STATE);
+}
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, TvInputAidlTest,
+ testing::ValuesIn(android::getAidlHalInstanceNames(ITvInput::descriptor)),
+ android::PrintInstanceNameToString);
+
+// TODO remove from the allow list once the cf tv target is enabled for testing
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TvInputAidlTest);
diff --git a/tv/input/aidl/vts/functional/VtsHalTvInputTargetTest.h b/tv/input/aidl/vts/functional/VtsHalTvInputTargetTest.h
new file mode 100644
index 0000000..c76e568
--- /dev/null
+++ b/tv/input/aidl/vts/functional/VtsHalTvInputTargetTest.h
@@ -0,0 +1,90 @@
+/*
+ * 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 <android/binder_manager.h>
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+
+#include <aidl/android/hardware/tv/input/BnTvInputCallback.h>
+#include <aidl/android/hardware/tv/input/ITvInput.h>
+#include <aidl/android/hardware/tv/input/TvInputDeviceInfo.h>
+#include <aidl/android/hardware/tv/input/TvInputEvent.h>
+#include <aidl/android/hardware/tv/input/TvStreamConfig.h>
+
+#include <log/log.h>
+#include <utils/KeyedVector.h>
+
+using namespace aidl::android::hardware::tv::input;
+using namespace std;
+
+using ::aidl::android::hardware::common::NativeHandle;
+
+#define WAIT_FOR_EVENT_TIMEOUT 5
+#define DEFAULT_ID INT32_MIN
+
+namespace VtsHalTvInputTargetTest {
+
+class TvInputAidlTest : public testing::TestWithParam<string> {
+ public:
+ class TvInputCallback : public BnTvInputCallback {
+ public:
+ TvInputCallback(shared_ptr<TvInputAidlTest> parent);
+ ::ndk::ScopedAStatus notify(const TvInputEvent& in_event) override;
+
+ private:
+ shared_ptr<TvInputAidlTest> parent_;
+ };
+
+ virtual void SetUp() override;
+ virtual void TearDown() override;
+
+ /* Called when a DEVICE_AVAILABLE event is received. */
+ void onDeviceAvailable(const TvInputDeviceInfo& deviceInfo);
+
+ /* Called when a DEVICE_UNAVAILABLE event is received. */
+ void onDeviceUnavailable(int32_t deviceId);
+
+ /* Called when a STREAM_CONFIGURATIONS_CHANGED event is received. */
+ ::ndk::ScopedAStatus onStreamConfigurationsChanged(int32_t deviceId);
+
+ /* Gets and updates the stream configurations for a device. */
+ ::ndk::ScopedAStatus updateStreamConfigurations(int32_t deviceId);
+
+ /* Gets and updates the stream configurations for all existing devices. */
+ void updateAllStreamConfigurations();
+
+ /* Returns a list of indices of stream_config_ whose corresponding values are not empty. */
+ vector<size_t> getConfigIndices();
+
+ /*
+ * Returns DEFAULT_ID if there is no missing integer in the range [0, the size of nums).
+ * Otherwise, returns the smallest missing non-negative integer.
+ */
+ int32_t getNumNotIn(vector<int32_t>& nums);
+
+ protected:
+ shared_ptr<ITvInput> tv_input_;
+ shared_ptr<TvInputCallback> tv_input_callback_;
+ android::KeyedVector<int32_t, TvInputDeviceInfo> device_info_;
+ android::KeyedVector<int32_t, vector<TvStreamConfig>> stream_config_;
+ mutex mutex_;
+ NativeHandle handle_;
+};
+
+} // namespace VtsHalTvInputTargetTest
diff --git a/tv/tuner/aidl/default/Android.bp b/tv/tuner/aidl/default/Android.bp
index cb8f87b..c10ad22 100644
--- a/tv/tuner/aidl/default/Android.bp
+++ b/tv/tuner/aidl/default/Android.bp
@@ -7,10 +7,9 @@
default_applicable_licenses: ["hardware_interfaces_license"],
}
-cc_binary {
- name: "android.hardware.tv.tuner-service.example",
+cc_defaults {
+ name: "tuner_hal_example_defaults",
relative_install_path: "hw",
- init_rc: ["tuner-default.rc"],
vintf_fragments: ["tuner-default.xml"],
vendor: true,
compile_multilib: "first",
@@ -44,3 +43,18 @@
"media_plugin_headers",
],
}
+
+cc_binary {
+ name: "android.hardware.tv.tuner-service.example",
+ defaults: ["tuner_hal_example_defaults"],
+ init_rc: ["tuner-default.rc"],
+}
+
+cc_binary {
+ name: "android.hardware.tv.tuner-service.example-lazy",
+ defaults: ["tuner_hal_example_defaults"],
+ init_rc: ["tuner-default-lazy.rc"],
+ cflags: [
+ "-DLAZY_HAL",
+ ],
+}
diff --git a/tv/tuner/aidl/default/Demux.cpp b/tv/tuner/aidl/default/Demux.cpp
index a94b4ad..60fd899 100644
--- a/tv/tuner/aidl/default/Demux.cpp
+++ b/tv/tuner/aidl/default/Demux.cpp
@@ -37,6 +37,7 @@
}
Demux::~Demux() {
+ ALOGV("%s", __FUNCTION__);
close();
}
@@ -180,7 +181,10 @@
mRecordFilterIds.clear();
mFilters.clear();
mLastUsedFilterId = -1;
- mTuner->removeDemux(mDemuxId);
+ if (mTuner != nullptr) {
+ mTuner->removeDemux(mDemuxId);
+ mTuner = nullptr;
+ }
return ::ndk::ScopedAStatus::ok();
}
diff --git a/tv/tuner/aidl/default/Filter.h b/tv/tuner/aidl/default/Filter.h
index b638f0c..f2d9248 100644
--- a/tv/tuner/aidl/default/Filter.h
+++ b/tv/tuner/aidl/default/Filter.h
@@ -50,8 +50,7 @@
using ::android::hardware::EventFlag;
using FilterMQ = AidlMessageQueue<int8_t, SynchronizedReadWrite>;
-// Large buffer size can lead to sudden crashes due to being de-allocated
-// by the memory management system. Change the buffer size when needed.
+
const uint32_t BUFFER_SIZE = 0x800000; // 8 MB
class Demux;
diff --git a/tv/tuner/aidl/default/Frontend.cpp b/tv/tuner/aidl/default/Frontend.cpp
index 3f7797c..0573d08 100644
--- a/tv/tuner/aidl/default/Frontend.cpp
+++ b/tv/tuner/aidl/default/Frontend.cpp
@@ -28,10 +28,10 @@
namespace tv {
namespace tuner {
-Frontend::Frontend(FrontendType type, int32_t id, std::shared_ptr<Tuner> tuner) {
+Frontend::Frontend(FrontendType type, int32_t id) {
mType = type;
mId = id;
- mTuner = tuner;
+ mTuner = nullptr;
// Init callback to nullptr
mCallback = nullptr;
@@ -170,7 +170,12 @@
}
}
-Frontend::~Frontend() {}
+Frontend::~Frontend() {
+ ALOGV("%s", __FUNCTION__);
+ mCallback = nullptr;
+ mIsLocked = false;
+ mTuner = nullptr;
+}
::ndk::ScopedAStatus Frontend::close() {
ALOGV("%s", __FUNCTION__);
@@ -178,6 +183,7 @@
mCallback = nullptr;
mIsLocked = false;
mTuner->removeFrontend(mId);
+ mTuner = nullptr;
return ::ndk::ScopedAStatus::ok();
}
@@ -233,6 +239,10 @@
return ::ndk::ScopedAStatus::ok();
}
+void Frontend::setTunerService(std::shared_ptr<Tuner> tuner) {
+ mTuner = tuner;
+}
+
void Frontend::scanThreadLoop() {
if (mIsLocked) {
FrontendScanMessage msg;
diff --git a/tv/tuner/aidl/default/Frontend.h b/tv/tuner/aidl/default/Frontend.h
index 1d9ab53..85bd636 100644
--- a/tv/tuner/aidl/default/Frontend.h
+++ b/tv/tuner/aidl/default/Frontend.h
@@ -34,7 +34,7 @@
class Frontend : public BnFrontend {
public:
- Frontend(FrontendType type, int32_t id, std::shared_ptr<Tuner> tuner);
+ Frontend(FrontendType type, int32_t id);
::ndk::ScopedAStatus setCallback(
const std::shared_ptr<IFrontendCallback>& in_callback) override;
@@ -62,6 +62,7 @@
string getSourceFile();
bool isLocked();
void getFrontendInfo(FrontendInfo* _aidl_return);
+ void setTunerService(std::shared_ptr<Tuner> tuner);
private:
virtual ~Frontend();
diff --git a/tv/tuner/aidl/default/Tuner.cpp b/tv/tuner/aidl/default/Tuner.cpp
index fa74288..591f936 100644
--- a/tv/tuner/aidl/default/Tuner.cpp
+++ b/tv/tuner/aidl/default/Tuner.cpp
@@ -38,16 +38,16 @@
// Static Frontends array to maintain local frontends information
// Array index matches their FrontendId in the default impl
mFrontendSize = 10;
- mFrontends[0] = ndk::SharedRefBase::make<Frontend>(FrontendType::ISDBS, 0, this->ref<Tuner>());
- mFrontends[1] = ndk::SharedRefBase::make<Frontend>(FrontendType::ATSC3, 1, this->ref<Tuner>());
- mFrontends[2] = ndk::SharedRefBase::make<Frontend>(FrontendType::DVBC, 2, this->ref<Tuner>());
- mFrontends[3] = ndk::SharedRefBase::make<Frontend>(FrontendType::DVBS, 3, this->ref<Tuner>());
- mFrontends[4] = ndk::SharedRefBase::make<Frontend>(FrontendType::DVBT, 4, this->ref<Tuner>());
- mFrontends[5] = ndk::SharedRefBase::make<Frontend>(FrontendType::ISDBT, 5, this->ref<Tuner>());
- mFrontends[6] = ndk::SharedRefBase::make<Frontend>(FrontendType::ANALOG, 6, this->ref<Tuner>());
- mFrontends[7] = ndk::SharedRefBase::make<Frontend>(FrontendType::ATSC, 7, this->ref<Tuner>());
- mFrontends[8] = ndk::SharedRefBase::make<Frontend>(FrontendType::ISDBS3, 8, this->ref<Tuner>());
- mFrontends[9] = ndk::SharedRefBase::make<Frontend>(FrontendType::DTMB, 9, this->ref<Tuner>());
+ mFrontends[0] = ndk::SharedRefBase::make<Frontend>(FrontendType::ISDBS, 0);
+ mFrontends[1] = ndk::SharedRefBase::make<Frontend>(FrontendType::ATSC3, 1);
+ mFrontends[2] = ndk::SharedRefBase::make<Frontend>(FrontendType::DVBC, 2);
+ mFrontends[3] = ndk::SharedRefBase::make<Frontend>(FrontendType::DVBS, 3);
+ mFrontends[4] = ndk::SharedRefBase::make<Frontend>(FrontendType::DVBT, 4);
+ mFrontends[5] = ndk::SharedRefBase::make<Frontend>(FrontendType::ISDBT, 5);
+ mFrontends[6] = ndk::SharedRefBase::make<Frontend>(FrontendType::ANALOG, 6);
+ mFrontends[7] = ndk::SharedRefBase::make<Frontend>(FrontendType::ATSC, 7);
+ mFrontends[8] = ndk::SharedRefBase::make<Frontend>(FrontendType::ISDBS3, 8);
+ mFrontends[9] = ndk::SharedRefBase::make<Frontend>(FrontendType::DTMB, 9);
mMaxUsableFrontends[FrontendType::ISDBS] = 1;
mMaxUsableFrontends[FrontendType::ATSC3] = 1;
@@ -89,6 +89,7 @@
static_cast<int32_t>(Result::INVALID_ARGUMENT));
}
+ mFrontends[in_frontendId]->setTunerService(this->ref<Tuner>());
*_aidl_return = mFrontends[in_frontendId];
return ::ndk::ScopedAStatus::ok();
}
diff --git a/tv/tuner/aidl/default/service.cpp b/tv/tuner/aidl/default/service.cpp
index ac8d779..f980f4a 100644
--- a/tv/tuner/aidl/default/service.cpp
+++ b/tv/tuner/aidl/default/service.cpp
@@ -30,8 +30,15 @@
std::shared_ptr<Tuner> tuner = ndk::SharedRefBase::make<Tuner>();
tuner->init();
+ binder_status_t status;
const std::string instance = std::string() + Tuner::descriptor + "/default";
- binder_status_t status = AServiceManager_addService(tuner->asBinder().get(), instance.c_str());
+#ifdef LAZY_HAL
+ ALOGD("Start as a lazy HAL");
+ status = AServiceManager_registerLazyService(tuner->asBinder().get(), instance.c_str());
+#else
+ ALOGD("Start as a normal HAL");
+ status = AServiceManager_addService(tuner->asBinder().get(), instance.c_str());
+#endif
CHECK(status == STATUS_OK);
ABinderProcess_joinThreadPool();
diff --git a/tv/tuner/aidl/default/tuner-default-lazy.rc b/tv/tuner/aidl/default/tuner-default-lazy.rc
new file mode 100644
index 0000000..6b3b183
--- /dev/null
+++ b/tv/tuner/aidl/default/tuner-default-lazy.rc
@@ -0,0 +1,9 @@
+service vendor.tuner-default-lazy /vendor/bin/hw/android.hardware.tv.tuner-service.example-lazy
+ class hal
+ user media
+ group mediadrm drmrpc
+ ioprio rt 4
+ task_profiles ProcessCapacityHigh
+ interface aidl android.hardware.tv.tuner.ITuner/default
+ oneshot
+ disabled
diff --git a/tv/tuner/aidl/default/tuner-default.rc b/tv/tuner/aidl/default/tuner-default.rc
index 661c219..f9315ae 100644
--- a/tv/tuner/aidl/default/tuner-default.rc
+++ b/tv/tuner/aidl/default/tuner-default.rc
@@ -5,3 +5,4 @@
ioprio rt 4
task_profiles ProcessCapacityHigh
onrestart restart media.tuner
+ interface aidl android.hardware.tv.tuner.ITuner/default
diff --git a/tv/tuner/aidl/vts/functional/LnbTests.h b/tv/tuner/aidl/vts/functional/LnbTests.h
index d6b5a25..a21e68d 100644
--- a/tv/tuner/aidl/vts/functional/LnbTests.h
+++ b/tv/tuner/aidl/vts/functional/LnbTests.h
@@ -25,6 +25,8 @@
#include <utils/Mutex.h>
#include <map>
+#define INVALID_LNB_ID -1
+
using android::Condition;
using android::Mutex;
diff --git a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp
index e6c6691..9a17d05 100644
--- a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp
+++ b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp
@@ -129,8 +129,8 @@
mFrontendTests.getFrontendIdByType(frontendConf.type, feId);
ASSERT_TRUE(mFrontendTests.openFrontendById(feId));
ASSERT_TRUE(mFrontendTests.setFrontendCallback());
- if (mLnbId) {
- ASSERT_TRUE(mFrontendTests.setLnb(*mLnbId));
+ if (mLnbId != INVALID_LNB_ID) {
+ ASSERT_TRUE(mFrontendTests.setLnb(mLnbId));
}
if (frontendConf.isSoftwareFe) {
mFrontendTests.setSoftwareFrontendDvrConfig(dvrMap[live.dvrSoftwareFeId]);
@@ -162,18 +162,19 @@
ASSERT_TRUE(mLnbTests.getLnbIds(ids));
ASSERT_TRUE(ids.size() > 0);
ASSERT_TRUE(mLnbTests.openLnbById(ids[0]));
- mLnbId = &ids[0];
+ mLnbId = ids[0];
} else {
- mLnbId = (int32_t*)malloc(sizeof(int32_t));
- ASSERT_TRUE(mLnbTests.openLnbByName(lnbConf.name, *mLnbId));
+ ASSERT_TRUE(mLnbTests.openLnbByName(lnbConf.name, mLnbId));
}
ASSERT_TRUE(mLnbTests.setLnbCallback());
ASSERT_TRUE(mLnbTests.setVoltage(lnbConf.voltage));
ASSERT_TRUE(mLnbTests.setTone(lnbConf.tone));
ASSERT_TRUE(mLnbTests.setSatellitePosition(lnbConf.position));
- broadcastSingleFilterTest(filterConf, frontendConf);
+ if (!frontendConf.isSoftwareFe) {
+ broadcastSingleFilterTest(filterConf, frontendConf);
+ }
ASSERT_TRUE(mLnbTests.closeLnb());
- mLnbId = nullptr;
+ mLnbId = INVALID_LNB_ID;
}
void TunerBroadcastAidlTest::mediaFilterUsingSharedMemoryTest(FilterConfig filterConf,
@@ -248,10 +249,9 @@
ASSERT_TRUE(mLnbTests.getLnbIds(ids));
ASSERT_TRUE(ids.size() > 0);
ASSERT_TRUE(mLnbTests.openLnbById(ids[0]));
- mLnbId = &ids[0];
+ mLnbId = ids[0];
} else {
- mLnbId = (int32_t*)malloc(sizeof(int32_t));
- ASSERT_TRUE(mLnbTests.openLnbByName(lnbConf.name, *mLnbId));
+ ASSERT_TRUE(mLnbTests.openLnbByName(lnbConf.name, mLnbId));
}
ASSERT_TRUE(mLnbTests.setLnbCallback());
ASSERT_TRUE(mLnbTests.setVoltage(lnbConf.voltage));
@@ -260,9 +260,11 @@
for (auto msgName : lnbRecord.diseqcMsgs) {
ASSERT_TRUE(mLnbTests.sendDiseqcMessage(diseqcMsgMap[msgName]));
}
- recordSingleFilterTest(filterConf, frontendConf, dvrConf);
+ if (!frontendConf.isSoftwareFe) {
+ recordSingleFilterTest(filterConf, frontendConf, dvrConf, Dataflow_Context::LNBRECORD);
+ }
ASSERT_TRUE(mLnbTests.closeLnb());
- mLnbId = nullptr;
+ mLnbId = INVALID_LNB_ID;
}
void TunerRecordAidlTest::attachSingleFilterToRecordDvrTest(FilterConfig filterConf,
@@ -318,29 +320,47 @@
}
void TunerRecordAidlTest::recordSingleFilterTest(FilterConfig filterConf,
- FrontendConfig frontendConf, DvrConfig dvrConf) {
+ FrontendConfig frontendConf, DvrConfig dvrConf,
+ Dataflow_Context context) {
int32_t demuxId;
std::shared_ptr<IDemux> demux;
ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
mDvrTests.setDemux(demux);
DvrConfig dvrSourceConfig;
- if (record.hasFrontendConnection) {
+ if (context == Dataflow_Context::RECORD) {
+ if (record.hasFrontendConnection) {
+ int32_t feId;
+ mFrontendTests.getFrontendIdByType(frontendConf.type, feId);
+ ASSERT_TRUE(feId != INVALID_ID);
+ ASSERT_TRUE(mFrontendTests.openFrontendById(feId));
+ ASSERT_TRUE(mFrontendTests.setFrontendCallback());
+ if (frontendConf.isSoftwareFe) {
+ mFrontendTests.setSoftwareFrontendDvrConfig(dvrMap[record.dvrSoftwareFeId]);
+ }
+ ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
+ mFrontendTests.setDvrTests(&mDvrTests);
+ } else {
+ dvrSourceConfig = dvrMap[record.dvrSourceId];
+ ASSERT_TRUE(mDvrTests.openDvrInDemux(dvrSourceConfig.type, dvrSourceConfig.bufferSize));
+ ASSERT_TRUE(mDvrTests.configDvrPlayback(dvrSourceConfig.settings));
+ ASSERT_TRUE(mDvrTests.getDvrPlaybackMQDescriptor());
+ }
+ } else if (context == Dataflow_Context::LNBRECORD) {
+ // If function arrives here, frontend should not be software, so no need to configure a dvr
+ // source or dvr fe connection that might be used for recording without an Lnb
int32_t feId;
mFrontendTests.getFrontendIdByType(frontendConf.type, feId);
ASSERT_TRUE(feId != INVALID_ID);
ASSERT_TRUE(mFrontendTests.openFrontendById(feId));
ASSERT_TRUE(mFrontendTests.setFrontendCallback());
- if (frontendConf.isSoftwareFe) {
- mFrontendTests.setSoftwareFrontendDvrConfig(dvrMap[record.dvrSoftwareFeId]);
+ if (mLnbId != INVALID_LNB_ID) {
+ ASSERT_TRUE(mFrontendTests.setLnb(mLnbId));
+ } else {
+ FAIL();
}
ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
mFrontendTests.setDvrTests(&mDvrTests);
- } else {
- dvrSourceConfig = dvrMap[record.dvrSourceId];
- ASSERT_TRUE(mDvrTests.openDvrInDemux(dvrSourceConfig.type, dvrSourceConfig.bufferSize));
- ASSERT_TRUE(mDvrTests.configDvrPlayback(dvrSourceConfig.settings));
- ASSERT_TRUE(mDvrTests.getDvrPlaybackMQDescriptor());
}
int64_t filterId;
@@ -360,24 +380,31 @@
ASSERT_TRUE(mDvrTests.startDvrRecord());
ASSERT_TRUE(mFilterTests.startFilter(filterId));
- if (record.hasFrontendConnection) {
+ if (context == Dataflow_Context::RECORD) {
+ if (record.hasFrontendConnection) {
+ ASSERT_TRUE(mFrontendTests.tuneFrontend(frontendConf, true /*testWithDemux*/));
+ } else {
+ // Start DVR Source
+ mDvrTests.startPlaybackInputThread(
+ dvrSourceConfig.playbackInputFile,
+ dvrSourceConfig.settings.get<DvrSettings::Tag::playback>());
+ ASSERT_TRUE(mDvrTests.startDvrPlayback());
+ }
+ } else if (context == Dataflow_Context::LNBRECORD) {
ASSERT_TRUE(mFrontendTests.tuneFrontend(frontendConf, true /*testWithDemux*/));
- } else {
- // Start DVR Source
- mDvrTests.startPlaybackInputThread(
- dvrSourceConfig.playbackInputFile,
- dvrSourceConfig.settings.get<DvrSettings::Tag::playback>());
- ASSERT_TRUE(mDvrTests.startDvrPlayback());
}
-
mDvrTests.testRecordOutput();
mDvrTests.stopRecordThread();
- if (record.hasFrontendConnection) {
+ if (context == Dataflow_Context::RECORD) {
+ if (record.hasFrontendConnection) {
+ ASSERT_TRUE(mFrontendTests.stopTuneFrontend(true /*testWithDemux*/));
+ } else {
+ mDvrTests.stopPlaybackThread();
+ ASSERT_TRUE(mDvrTests.stopDvrPlayback());
+ }
+ } else if (context == Dataflow_Context::LNBRECORD) {
ASSERT_TRUE(mFrontendTests.stopTuneFrontend(true /*testWithDemux*/));
- } else {
- mDvrTests.stopPlaybackThread();
- ASSERT_TRUE(mDvrTests.stopDvrPlayback());
}
ASSERT_TRUE(mFilterTests.stopFilter(filterId));
@@ -386,10 +413,14 @@
ASSERT_TRUE(mFilterTests.closeFilter(filterId));
mDvrTests.closeDvrRecord();
- if (record.hasFrontendConnection) {
+ if (context == Dataflow_Context::RECORD) {
+ if (record.hasFrontendConnection) {
+ ASSERT_TRUE(mFrontendTests.closeFrontend());
+ } else {
+ mDvrTests.closeDvrPlayback();
+ }
+ } else if (context == Dataflow_Context::LNBRECORD) {
ASSERT_TRUE(mFrontendTests.closeFrontend());
- } else {
- mDvrTests.closeDvrPlayback();
}
ASSERT_TRUE(mDemuxTests.closeDemux());
@@ -397,28 +428,45 @@
void TunerDescramblerAidlTest::scrambledBroadcastTest(set<struct FilterConfig> mediaFilterConfs,
FrontendConfig frontendConf,
- DescramblerConfig descConfig) {
+ DescramblerConfig descConfig,
+ Dataflow_Context context) {
int32_t demuxId;
std::shared_ptr<IDemux> demux;
ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
DvrConfig dvrSourceConfig;
- if (descrambling.hasFrontendConnection) {
+ if (context == Dataflow_Context::DESCRAMBLING) {
+ if (descrambling.hasFrontendConnection) {
+ int32_t feId;
+ mFrontendTests.getFrontendIdByType(frontendConf.type, feId);
+ ASSERT_TRUE(mFrontendTests.openFrontendById(feId));
+ ASSERT_TRUE(mFrontendTests.setFrontendCallback());
+ if (frontendConf.isSoftwareFe) {
+ mFrontendTests.setSoftwareFrontendDvrConfig(dvrMap[descrambling.dvrSoftwareFeId]);
+ }
+ ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
+ mFrontendTests.setDemux(demux);
+ } else {
+ dvrSourceConfig = dvrMap[descrambling.dvrSourceId];
+ mDvrTests.setDemux(demux);
+ ASSERT_TRUE(mDvrTests.openDvrInDemux(dvrSourceConfig.type, dvrSourceConfig.bufferSize));
+ ASSERT_TRUE(mDvrTests.configDvrPlayback(dvrSourceConfig.settings));
+ ASSERT_TRUE(mDvrTests.getDvrPlaybackMQDescriptor());
+ }
+ } else if (context == Dataflow_Context::LNBDESCRAMBLING) {
int32_t feId;
mFrontendTests.getFrontendIdByType(frontendConf.type, feId);
ASSERT_TRUE(mFrontendTests.openFrontendById(feId));
ASSERT_TRUE(mFrontendTests.setFrontendCallback());
- if (frontendConf.isSoftwareFe) {
- mFrontendTests.setSoftwareFrontendDvrConfig(dvrMap[descrambling.dvrSoftwareFeId]);
+ if (mLnbId != INVALID_LNB_ID) {
+ ASSERT_TRUE(mFrontendTests.setLnb(mLnbId));
+ } else {
+ // If, for some reason, the test got here without failing. We fail it here.
+ ALOGD("mLnbId is null. Something went wrong. Exiting ScrambledBroadcastWithLnbId.");
+ FAIL();
}
ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
mFrontendTests.setDemux(demux);
- } else {
- dvrSourceConfig = dvrMap[descrambling.dvrSourceId];
- mDvrTests.setDemux(demux);
- ASSERT_TRUE(mDvrTests.openDvrInDemux(dvrSourceConfig.type, dvrSourceConfig.bufferSize));
- ASSERT_TRUE(mDvrTests.configDvrPlayback(dvrSourceConfig.settings));
- ASSERT_TRUE(mDvrTests.getDvrPlaybackMQDescriptor());
}
set<int64_t> filterIds;
@@ -449,24 +497,32 @@
ASSERT_TRUE(mFilterTests.startFilter(*id));
}
- if (descrambling.hasFrontendConnection) {
- // tune test
+ if (context == Dataflow_Context::DESCRAMBLING) {
+ if (descrambling.hasFrontendConnection) {
+ // tune test
+ ASSERT_TRUE(mFrontendTests.tuneFrontend(frontendConf, true /*testWithDemux*/));
+ } else {
+ // Start DVR Source
+ mDvrTests.startPlaybackInputThread(
+ dvrSourceConfig.playbackInputFile,
+ dvrSourceConfig.settings.get<DvrSettings::Tag::playback>());
+ ASSERT_TRUE(mDvrTests.startDvrPlayback());
+ }
+ } else if (context == Dataflow_Context::LNBDESCRAMBLING) {
ASSERT_TRUE(mFrontendTests.tuneFrontend(frontendConf, true /*testWithDemux*/));
- } else {
- // Start DVR Source
- mDvrTests.startPlaybackInputThread(
- dvrSourceConfig.playbackInputFile,
- dvrSourceConfig.settings.get<DvrSettings::Tag::playback>());
- ASSERT_TRUE(mDvrTests.startDvrPlayback());
}
ASSERT_TRUE(filterDataOutputTest());
- if (descrambling.hasFrontendConnection) {
+ if (context == Dataflow_Context::DESCRAMBLING) {
+ if (descrambling.hasFrontendConnection) {
+ ASSERT_TRUE(mFrontendTests.stopTuneFrontend(true /*testWithDemux*/));
+ } else {
+ mDvrTests.stopPlaybackThread();
+ ASSERT_TRUE(mDvrTests.stopDvrPlayback());
+ }
+ } else if (context == Dataflow_Context::LNBDESCRAMBLING) {
ASSERT_TRUE(mFrontendTests.stopTuneFrontend(true /*testWithDemux*/));
- } else {
- mDvrTests.stopPlaybackThread();
- ASSERT_TRUE(mDvrTests.stopDvrPlayback());
}
for (id = filterIds.begin(); id != filterIds.end(); id++) {
@@ -480,15 +536,50 @@
ASSERT_TRUE(mFilterTests.closeFilter(*id));
}
- if (descrambling.hasFrontendConnection) {
+ if (context == Dataflow_Context::DESCRAMBLING) {
+ if (descrambling.hasFrontendConnection) {
+ ASSERT_TRUE(mFrontendTests.closeFrontend());
+ } else {
+ mDvrTests.closeDvrPlayback();
+ }
+ } else if (context == Dataflow_Context::LNBDESCRAMBLING) {
ASSERT_TRUE(mFrontendTests.closeFrontend());
- } else {
- mDvrTests.closeDvrPlayback();
}
ASSERT_TRUE(mDemuxTests.closeDemux());
}
+void TunerDescramblerAidlTest::scrambledBroadcastTestWithLnb(
+ set<struct FilterConfig>& mediaFilterConfs, FrontendConfig& frontendConf,
+ DescramblerConfig& descConfig, LnbConfig& lnbConfig) {
+ // We can test the Lnb individually and make sure it functions properly. If the frontend is
+ // software, we cannot test the whole dataflow. If the frontend is hardware, we can
+ if (lnbConfig.name.compare(emptyHardwareId) == 0) {
+ vector<int32_t> ids;
+ ASSERT_TRUE(mLnbTests.getLnbIds(ids));
+ ASSERT_TRUE(ids.size() > 0);
+ ASSERT_TRUE(mLnbTests.openLnbById(ids[0]));
+ mLnbId = ids[0];
+ } else {
+ ASSERT_TRUE(mLnbTests.openLnbByName(lnbConfig.name, mLnbId));
+ }
+ // Once Lnb is opened, test some of its basic functionality
+ ASSERT_TRUE(mLnbTests.setLnbCallback());
+ ASSERT_TRUE(mLnbTests.setVoltage(lnbConfig.voltage));
+ ASSERT_TRUE(mLnbTests.setTone(lnbConfig.tone));
+ ASSERT_TRUE(mLnbTests.setSatellitePosition(lnbConfig.position));
+ if (!frontendConf.isSoftwareFe) {
+ ALOGD("Frontend is not software, testing entire dataflow.");
+ scrambledBroadcastTest(mediaFilterConfs, frontendConf, descConfig,
+ Dataflow_Context::LNBDESCRAMBLING);
+ } else {
+ ALOGD("Frontend is software, did not test the entire dataflow, but tested the Lnb "
+ "individually.");
+ }
+ ASSERT_TRUE(mLnbTests.closeLnb());
+ mLnbId = INVALID_LNB_ID;
+}
+
TEST_P(TunerLnbAidlTest, SendDiseqcMessageToLnb) {
description("Open and configure an Lnb with specific settings then send a diseqc msg to it.");
if (!lnbLive.support) {
@@ -501,7 +592,6 @@
}
for (auto& combination : lnbLive_configs) {
lnbLive = combination;
-
if (lnbMap[lnbLive.lnbId].name.compare(emptyHardwareId) == 0) {
vector<int32_t> ids;
ASSERT_TRUE(mLnbTests.getLnbIds(ids));
@@ -527,17 +617,21 @@
if (!live.hasFrontendConnection) {
return;
}
- int32_t feId;
- int32_t demuxId;
- std::shared_ptr<IDemux> demux;
- mFrontendTests.getFrontendIdByType(frontendMap[live.frontendId].type, feId);
- ASSERT_TRUE(feId != INVALID_ID);
- ASSERT_TRUE(mFrontendTests.openFrontendById(feId));
- ASSERT_TRUE(mFrontendTests.setFrontendCallback());
- ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
- ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
- ASSERT_TRUE(mDemuxTests.closeDemux());
- ASSERT_TRUE(mFrontendTests.closeFrontend());
+ auto live_configs = generateLiveConfigurations();
+ for (auto& configuration : live_configs) {
+ live = configuration;
+ int32_t feId;
+ int32_t demuxId;
+ std::shared_ptr<IDemux> demux;
+ mFrontendTests.getFrontendIdByType(frontendMap[live.frontendId].type, feId);
+ ASSERT_TRUE(feId != INVALID_ID);
+ ASSERT_TRUE(mFrontendTests.openFrontendById(feId));
+ ASSERT_TRUE(mFrontendTests.setFrontendCallback());
+ ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
+ ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
+ ASSERT_TRUE(mDemuxTests.closeDemux());
+ ASSERT_TRUE(mFrontendTests.closeFrontend());
+ }
}
TEST_P(TunerDemuxAidlTest, getAvSyncTime) {
@@ -545,40 +639,45 @@
if (!live.hasFrontendConnection) {
return;
}
- if (live.pcrFilterId.compare(emptyHardwareId) == 0) {
- return;
- }
- int32_t feId;
- int32_t demuxId;
- std::shared_ptr<IDemux> demux;
- int64_t mediaFilterId;
- int64_t pcrFilterId;
- int32_t avSyncHwId;
- std::shared_ptr<IFilter> mediaFilter;
+ auto live_configs = generateLiveConfigurations();
+ for (auto& configuration : live_configs) {
+ live = configuration;
+ if (live.pcrFilterId.compare(emptyHardwareId) == 0) {
+ continue;
+ }
+ int32_t feId;
+ int32_t demuxId;
+ std::shared_ptr<IDemux> demux;
+ int64_t mediaFilterId;
+ int64_t pcrFilterId;
+ int32_t avSyncHwId;
+ std::shared_ptr<IFilter> mediaFilter;
- mFrontendTests.getFrontendIdByType(frontendMap[live.frontendId].type, feId);
- ASSERT_TRUE(feId != INVALID_ID);
- ASSERT_TRUE(mFrontendTests.openFrontendById(feId));
- ASSERT_TRUE(mFrontendTests.setFrontendCallback());
- ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
- ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
- mFilterTests.setDemux(demux);
- ASSERT_TRUE(mFilterTests.openFilterInDemux(filterMap[live.videoFilterId].type,
- filterMap[live.videoFilterId].bufferSize));
- ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId_64bit(mediaFilterId));
- ASSERT_TRUE(mFilterTests.configFilter(filterMap[live.videoFilterId].settings, mediaFilterId));
- mediaFilter = mFilterTests.getFilterById(mediaFilterId);
- ASSERT_TRUE(mFilterTests.openFilterInDemux(filterMap[live.pcrFilterId].type,
- filterMap[live.pcrFilterId].bufferSize));
- ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId_64bit(pcrFilterId));
- ASSERT_TRUE(mFilterTests.configFilter(filterMap[live.pcrFilterId].settings, pcrFilterId));
- ASSERT_TRUE(mDemuxTests.getAvSyncId(mediaFilter, avSyncHwId));
- ASSERT_TRUE(pcrFilterId == avSyncHwId);
- ASSERT_TRUE(mDemuxTests.getAvSyncTime(pcrFilterId));
- ASSERT_TRUE(mFilterTests.closeFilter(pcrFilterId));
- ASSERT_TRUE(mFilterTests.closeFilter(mediaFilterId));
- ASSERT_TRUE(mDemuxTests.closeDemux());
- ASSERT_TRUE(mFrontendTests.closeFrontend());
+ mFrontendTests.getFrontendIdByType(frontendMap[live.frontendId].type, feId);
+ ASSERT_TRUE(feId != INVALID_ID);
+ ASSERT_TRUE(mFrontendTests.openFrontendById(feId));
+ ASSERT_TRUE(mFrontendTests.setFrontendCallback());
+ ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
+ ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
+ mFilterTests.setDemux(demux);
+ ASSERT_TRUE(mFilterTests.openFilterInDemux(filterMap[live.videoFilterId].type,
+ filterMap[live.videoFilterId].bufferSize));
+ ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId_64bit(mediaFilterId));
+ ASSERT_TRUE(
+ mFilterTests.configFilter(filterMap[live.videoFilterId].settings, mediaFilterId));
+ mediaFilter = mFilterTests.getFilterById(mediaFilterId);
+ ASSERT_TRUE(mFilterTests.openFilterInDemux(filterMap[live.pcrFilterId].type,
+ filterMap[live.pcrFilterId].bufferSize));
+ ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId_64bit(pcrFilterId));
+ ASSERT_TRUE(mFilterTests.configFilter(filterMap[live.pcrFilterId].settings, pcrFilterId));
+ ASSERT_TRUE(mDemuxTests.getAvSyncId(mediaFilter, avSyncHwId));
+ ASSERT_TRUE(pcrFilterId == avSyncHwId);
+ ASSERT_TRUE(mDemuxTests.getAvSyncTime(pcrFilterId));
+ ASSERT_TRUE(mFilterTests.closeFilter(pcrFilterId));
+ ASSERT_TRUE(mFilterTests.closeFilter(mediaFilterId));
+ ASSERT_TRUE(mDemuxTests.closeDemux());
+ ASSERT_TRUE(mFrontendTests.closeFrontend());
+ }
}
TEST_P(TunerFilterAidlTest, StartFilterInDemux) {
@@ -587,7 +686,11 @@
return;
}
// TODO use parameterized tests
- configSingleFilterInDemuxTest(filterMap[live.videoFilterId], frontendMap[live.frontendId]);
+ auto live_configs = generateLiveConfigurations();
+ for (auto& configuration : live_configs) {
+ live = configuration;
+ configSingleFilterInDemuxTest(filterMap[live.videoFilterId], frontendMap[live.frontendId]);
+ }
}
TEST_P(TunerFilterAidlTest, ConfigIpFilterInDemuxWithCid) {
@@ -596,10 +699,14 @@
if (!live.hasFrontendConnection) {
return;
}
- if (live.ipFilterId.compare(emptyHardwareId) == 0) {
- return;
+ auto live_configs = generateLiveConfigurations();
+ for (auto& configuration : live_configs) {
+ live = configuration;
+ if (live.ipFilterId.compare(emptyHardwareId) == 0) {
+ continue;
+ }
+ configSingleFilterInDemuxTest(filterMap[live.ipFilterId], frontendMap[live.frontendId]);
}
- configSingleFilterInDemuxTest(filterMap[live.ipFilterId], frontendMap[live.frontendId]);
}
TEST_P(TunerFilterAidlTest, ReconfigFilterToReceiveStartId) {
@@ -608,8 +715,13 @@
return;
}
// TODO use parameterized tests
- reconfigSingleFilterInDemuxTest(filterMap[live.videoFilterId], filterMap[live.videoFilterId],
- frontendMap[live.frontendId]);
+ auto live_configs = generateLiveConfigurations();
+ for (auto& configuration : live_configs) {
+ live = configuration;
+ reconfigSingleFilterInDemuxTest(filterMap[live.videoFilterId],
+ filterMap[live.videoFilterId],
+ frontendMap[live.frontendId]);
+ }
}
TEST_P(TunerFilterAidlTest, SetFilterLinkage) {
@@ -646,7 +758,11 @@
return;
}
// TODO use parameterized tests
- testTimeFilter(timeFilterMap[timeFilter.timeFilterId]);
+ auto timeFilter_configs = generateTimeFilterConfigurations();
+ for (auto& configuration : timeFilter_configs) {
+ timeFilter = configuration;
+ testTimeFilter(timeFilterMap[timeFilter.timeFilterId]);
+ }
}
static bool isEventProducingFilter(const FilterConfig& filterConfig) {
@@ -889,8 +1005,12 @@
if (!record.support) {
return;
}
- recordSingleFilterTest(filterMap[record.recordFilterId], frontendMap[record.frontendId],
- dvrMap[record.dvrRecordId]);
+ auto record_configs = generateRecordConfigurations();
+ for (auto& configuration : record_configs) {
+ record = configuration;
+ recordSingleFilterTest(filterMap[record.recordFilterId], frontendMap[record.frontendId],
+ dvrMap[record.dvrRecordId], Dataflow_Context::RECORD);
+ }
}
TEST_P(TunerRecordAidlTest, AttachFiltersToRecordTest) {
@@ -899,8 +1019,13 @@
if (!record.support) {
return;
}
- attachSingleFilterToRecordDvrTest(filterMap[record.recordFilterId],
- frontendMap[record.frontendId], dvrMap[record.dvrRecordId]);
+ auto record_configs = generateRecordConfigurations();
+ for (auto& configuration : record_configs) {
+ record = configuration;
+ attachSingleFilterToRecordDvrTest(filterMap[record.recordFilterId],
+ frontendMap[record.frontendId],
+ dvrMap[record.dvrRecordId]);
+ }
}
TEST_P(TunerRecordAidlTest, LnbRecordDataFlowWithTsRecordFilterTest) {
@@ -926,7 +1051,11 @@
if (!live.hasFrontendConnection) {
return;
}
- mFrontendTests.tuneTest(frontendMap[live.frontendId]);
+ auto live_configs = generateLiveConfigurations();
+ for (auto& configuration : live_configs) {
+ live = configuration;
+ mFrontendTests.tuneTest(frontendMap[live.frontendId]);
+ }
}
TEST_P(TunerFrontendAidlTest, AutoScanFrontend) {
@@ -958,7 +1087,11 @@
if (!live.hasFrontendConnection) {
return;
}
- mFrontendTests.tuneTest(frontendMap[live.frontendId]);
+ auto live_configs = generateLiveConfigurations();
+ for (auto& configuration : live_configs) {
+ live = configuration;
+ mFrontendTests.tuneTest(frontendMap[live.frontendId]);
+ }
}
TEST_P(TunerFrontendAidlTest, BlindScanFrontendWithEndFrequency) {
@@ -978,10 +1111,14 @@
if (!live.hasFrontendConnection) {
return;
}
- if (!frontendMap[live.frontendId].canConnectToCiCam) {
- return;
+ auto live_configs = generateLiveConfigurations();
+ for (auto& configuration : live_configs) {
+ live = configuration;
+ if (!frontendMap[live.frontendId].canConnectToCiCam) {
+ continue;
+ }
+ mFrontendTests.tuneTest(frontendMap[live.frontendId]);
}
- mFrontendTests.tuneTest(frontendMap[live.frontendId]);
}
TEST_P(TunerFrontendAidlTest, getHardwareInfo) {
@@ -989,7 +1126,11 @@
if (!live.hasFrontendConnection) {
return;
}
- mFrontendTests.debugInfoTest(frontendMap[live.frontendId]);
+ auto live_configs = generateLiveConfigurations();
+ for (auto& configuration : live_configs) {
+ live = configuration;
+ mFrontendTests.debugInfoTest(frontendMap[live.frontendId]);
+ }
}
TEST_P(TunerFrontendAidlTest, maxNumberOfFrontends) {
@@ -1005,7 +1146,11 @@
if (!live.hasFrontendConnection) {
return;
}
- mFrontendTests.statusReadinessTest(frontendMap[live.frontendId]);
+ auto live_configs = generateLiveConfigurations();
+ for (auto& configuration : live_configs) {
+ live = configuration;
+ mFrontendTests.statusReadinessTest(frontendMap[live.frontendId]);
+ }
}
TEST_P(TunerBroadcastAidlTest, BroadcastDataFlowVideoFilterTest) {
@@ -1013,7 +1158,11 @@
if (!live.hasFrontendConnection) {
return;
}
- broadcastSingleFilterTest(filterMap[live.videoFilterId], frontendMap[live.frontendId]);
+ auto live_configs = generateLiveConfigurations();
+ for (auto& configuration : live_configs) {
+ live = configuration;
+ broadcastSingleFilterTest(filterMap[live.videoFilterId], frontendMap[live.frontendId]);
+ }
}
TEST_P(TunerBroadcastAidlTest, BroadcastDataFlowAudioFilterTest) {
@@ -1021,7 +1170,11 @@
if (!live.hasFrontendConnection) {
return;
}
- broadcastSingleFilterTest(filterMap[live.audioFilterId], frontendMap[live.frontendId]);
+ auto live_configs = generateLiveConfigurations();
+ for (auto& configuration : live_configs) {
+ live = configuration;
+ broadcastSingleFilterTest(filterMap[live.audioFilterId], frontendMap[live.frontendId]);
+ }
}
TEST_P(TunerBroadcastAidlTest, BroadcastDataFlowSectionFilterTest) {
@@ -1029,10 +1182,14 @@
if (!live.hasFrontendConnection) {
return;
}
- if (live.sectionFilterId.compare(emptyHardwareId) == 0) {
- return;
+ auto live_configs = generateLiveConfigurations();
+ for (auto& configuration : live_configs) {
+ live = configuration;
+ if (live.sectionFilterId.compare(emptyHardwareId) == 0) {
+ continue;
+ }
+ broadcastSingleFilterTest(filterMap[live.sectionFilterId], frontendMap[live.frontendId]);
}
- broadcastSingleFilterTest(filterMap[live.sectionFilterId], frontendMap[live.frontendId]);
}
TEST_P(TunerBroadcastAidlTest, IonBufferTest) {
@@ -1040,7 +1197,11 @@
if (!live.hasFrontendConnection) {
return;
}
- broadcastSingleFilterTest(filterMap[live.videoFilterId], frontendMap[live.frontendId]);
+ auto live_configs = generateLiveConfigurations();
+ for (auto& configuration : live_configs) {
+ live = configuration;
+ broadcastSingleFilterTest(filterMap[live.videoFilterId], frontendMap[live.frontendId]);
+ }
}
TEST_P(TunerBroadcastAidlTest, LnbBroadcastDataFlowVideoFilterTest) {
@@ -1065,7 +1226,12 @@
if (!live.hasFrontendConnection) {
return;
}
- mediaFilterUsingSharedMemoryTest(filterMap[live.videoFilterId], frontendMap[live.frontendId]);
+ auto live_configs = generateLiveConfigurations();
+ for (auto& configuration : live_configs) {
+ live = configuration;
+ mediaFilterUsingSharedMemoryTest(filterMap[live.videoFilterId],
+ frontendMap[live.frontendId]);
+ }
}
TEST_P(TunerDescramblerAidlTest, CreateDescrambler) {
@@ -1121,7 +1287,29 @@
filterConfs.insert(static_cast<FilterConfig>(filterMap[descrambling.audioFilterId]));
filterConfs.insert(static_cast<FilterConfig>(filterMap[descrambling.videoFilterId]));
scrambledBroadcastTest(filterConfs, frontendMap[descrambling.frontendId],
- descramblerMap[descrambling.descramblerId]);
+ descramblerMap[descrambling.descramblerId],
+ Dataflow_Context::DESCRAMBLING);
+ }
+}
+
+TEST_P(TunerDescramblerAidlTest, ScrambledBroadcastDataFlowMediaFiltersTestWithLnb) {
+ description("Test media filters in scrambled broadcast use case with Lnb");
+ if (!lnbDescrambling.support) {
+ return;
+ }
+ auto lnbDescrambling_configs = generateLnbDescramblingConfigurations();
+ if (lnbDescrambling_configs.empty()) {
+ ALOGD("No frontends that support satellites.");
+ return;
+ }
+ for (auto& configuration : lnbDescrambling_configs) {
+ lnbDescrambling = configuration;
+ set<FilterConfig> filterConfs;
+ filterConfs.insert(static_cast<FilterConfig>(filterMap[lnbDescrambling.audioFilterId]));
+ filterConfs.insert(static_cast<FilterConfig>(filterMap[lnbDescrambling.videoFilterId]));
+ scrambledBroadcastTestWithLnb(filterConfs, frontendMap[lnbDescrambling.frontendId],
+ descramblerMap[lnbDescrambling.descramblerId],
+ lnbMap[lnbDescrambling.lnbId]);
}
}
diff --git a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.h b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.h
index 6ffa18f..f68e1ec 100644
--- a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.h
+++ b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.h
@@ -68,7 +68,10 @@
lnbIds.clear();
diseqcMsgs.clear();
frontendIds.clear();
+ ipFilterIds.clear();
+ pcrFilterIds.clear();
recordDvrIds.clear();
+ timeFilterIds.clear();
descramblerIds.clear();
audioFilterIds.clear();
videoFilterIds.clear();
@@ -77,6 +80,8 @@
sectionFilterIds.clear();
}
+enum class Dataflow_Context { LNBRECORD, RECORD, DESCRAMBLING, LNBDESCRAMBLING };
+
class TunerLnbAidlTest : public testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
@@ -153,7 +158,7 @@
mService = nullptr;
}
ASSERT_NE(mService, nullptr);
- initConfiguration();
+ ASSERT_TRUE(initConfiguration());
mFrontendTests.setService(mService);
mDemuxTests.setService(mService);
@@ -264,7 +269,7 @@
mService = nullptr;
}
ASSERT_NE(mService, nullptr);
- initConfiguration();
+ ASSERT_TRUE(initConfiguration());
mFrontendTests.setService(mService);
mDemuxTests.setService(mService);
@@ -276,7 +281,6 @@
virtual void TearDown() override {
clearIds();
mService = nullptr;
- mLnbId = nullptr;
}
protected:
@@ -289,7 +293,7 @@
void recordSingleFilterTestWithLnb(FilterConfig filterConf, FrontendConfig frontendConf,
DvrConfig dvrConf, LnbConfig lnbConf);
void recordSingleFilterTest(FilterConfig filterConf, FrontendConfig frontendConf,
- DvrConfig dvrConf);
+ DvrConfig dvrConf, Dataflow_Context context);
std::shared_ptr<ITuner> mService;
FrontendTests mFrontendTests;
@@ -299,7 +303,7 @@
LnbTests mLnbTests;
private:
- int32_t* mLnbId = nullptr;
+ int32_t mLnbId = INVALID_LNB_ID;
};
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TunerRecordAidlTest);
@@ -314,7 +318,7 @@
mService = nullptr;
}
ASSERT_NE(mService, nullptr);
- initConfiguration();
+ ASSERT_TRUE(initConfiguration());
mFrontendTests.setService(mService);
}
@@ -345,7 +349,7 @@
mService = nullptr;
}
ASSERT_NE(mService, nullptr);
- initConfiguration();
+ ASSERT_TRUE(initConfiguration());
mFrontendTests.setService(mService);
mDemuxTests.setService(mService);
@@ -357,7 +361,6 @@
virtual void TearDown() override {
clearIds();
mService = nullptr;
- mLnbId = nullptr;
}
protected:
@@ -380,7 +383,7 @@
void mediaFilterUsingSharedMemoryTest(FilterConfig filterConf, FrontendConfig frontendConf);
private:
- int32_t* mLnbId = nullptr;
+ int32_t mLnbId = INVALID_LNB_ID;
};
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TunerBroadcastAidlTest);
@@ -404,6 +407,7 @@
mDvrTests.setService(mService);
mDescramblerTests.setService(mService);
mDescramblerTests.setCasService(mCasService);
+ mLnbTests.setService(mService);
}
virtual void TearDown() override {
@@ -417,7 +421,11 @@
}
void scrambledBroadcastTest(set<struct FilterConfig> mediaFilterConfs,
- FrontendConfig frontendConf, DescramblerConfig descConfig);
+ FrontendConfig frontendConf, DescramblerConfig descConfig,
+ Dataflow_Context context);
+ void scrambledBroadcastTestWithLnb(set<struct FilterConfig>& mediaFilterConfs,
+ FrontendConfig& frontendConf, DescramblerConfig& descConfig,
+ LnbConfig& lnbConfig);
AssertionResult filterDataOutputTest();
std::shared_ptr<ITuner> mService;
@@ -427,6 +435,10 @@
FilterTests mFilterTests;
DescramblerTests mDescramblerTests;
DvrTests mDvrTests;
+ LnbTests mLnbTests;
+
+ private:
+ int32_t mLnbId = INVALID_LNB_ID;
};
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TunerDescramblerAidlTest);
diff --git a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTestConfigurations.h b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTestConfigurations.h
index de12dc0..fea5f83 100644
--- a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTestConfigurations.h
+++ b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTestConfigurations.h
@@ -74,6 +74,7 @@
static LnbLiveHardwareConnections lnbLive;
static LnbRecordHardwareConnections lnbRecord;
static TimeFilterHardwareConnections timeFilter;
+static LnbDescramblingHardwareConnections lnbDescrambling;
/*
* This function takes in a 2d vector of device Id's
@@ -131,28 +132,28 @@
/*
* index 0 - playback dvr
* index 1 - audio filters
- * index 2 - video filters
- * index 3 - optional section filters
+ * index 2 - optional section filters
*/
static inline vector<DvrPlaybackHardwareConnections> generatePlaybackCombinations() {
vector<DvrPlaybackHardwareConnections> combinations;
vector<string> sectionFilterIds_optional = sectionFilterIds;
sectionFilterIds_optional.push_back(emptyHardwareId);
- vector<vector<string>> deviceIds{playbackDvrIds, audioFilterIds, videoFilterIds,
- sectionFilterIds_optional};
+ vector<vector<string>> deviceIds{playbackDvrIds, audioFilterIds, sectionFilterIds_optional};
const int dvrIndex = 0;
const int audioFilterIndex = 1;
- const int videoFilterIndex = 2;
- const int sectionFilterIndex = 3;
+ const int sectionFilterIndex = 2;
auto idCombinations = generateIdCombinations(deviceIds);
for (auto& combo : idCombinations) {
DvrPlaybackHardwareConnections mPlayback;
mPlayback.dvrId = combo[dvrIndex];
mPlayback.audioFilterId = combo[audioFilterIndex];
- mPlayback.videoFilterId = combo[videoFilterIndex];
mPlayback.sectionFilterId = combo[sectionFilterIndex];
+ const int videoFilterIndex =
+ find(audioFilterIds.begin(), audioFilterIds.end(), mPlayback.audioFilterId) -
+ audioFilterIds.begin();
+ mPlayback.videoFilterId = videoFilterIds[videoFilterIndex];
combinations.push_back(mPlayback);
}
@@ -176,17 +177,15 @@
/*
* index 0 - frontends
* index 1 - audio filters
- * index 2 - video filters
- * index 3 - lnbs
+ * index 2 - lnbs
*/
static inline vector<LnbLiveHardwareConnections> generateLnbLiveCombinations() {
vector<LnbLiveHardwareConnections> combinations;
- vector<vector<string>> deviceIds{frontendIds, audioFilterIds, videoFilterIds, lnbIds};
+ vector<vector<string>> deviceIds{frontendIds, audioFilterIds, lnbIds};
const int frontendIndex = 0;
const int audioFilterIndex = 1;
- const int videoFilterIndex = 2;
- const int lnbIndex = 3;
+ const int lnbIndex = 2;
// TODO: Find a better way to vary diseqcMsgs, if at all
auto idCombinations = generateIdCombinations(deviceIds);
@@ -198,7 +197,10 @@
LnbLiveHardwareConnections mLnbLive;
mLnbLive.frontendId = feId;
mLnbLive.audioFilterId = combo[audioFilterIndex];
- mLnbLive.videoFilterId = combo[videoFilterIndex];
+ const int videoFilterIndex =
+ find(audioFilterIds.begin(), audioFilterIds.end(), mLnbLive.audioFilterId) -
+ audioFilterIds.begin();
+ mLnbLive.videoFilterId = videoFilterIds[videoFilterIndex];
mLnbLive.lnbId = combo[lnbIndex];
mLnbLive.diseqcMsgs = diseqcMsgs;
combinations.push_back(mLnbLive);
@@ -301,9 +303,8 @@
* index 0 - decramblers
* index 1 - frontends
* index 2 - audio filters
- * index 3 - video filters
- * index 4 - Dvr SW Fe Connections
- * index 5 - DVR Source Connections
+ * index 3 - Dvr SW Fe Connections
+ * index 4 - DVR Source Connections
*/
static inline vector<DescramblingHardwareConnections> generateDescramblingCombinations() {
vector<DescramblingHardwareConnections> combinations;
@@ -320,12 +321,11 @@
const int descramblerIndex = 0;
const int frontendIndex = 1;
const int audioFilterIndex = 2;
- const int videoFilterIndex = 3;
- const int dvrFeIdIndex = 4;
- const int dvrSourceIdIndex = 5;
+ const int dvrFeIdIndex = 3;
+ const int dvrSourceIdIndex = 4;
- vector<vector<string>> deviceIds{descramblerIds, mfrontendIds, audioFilterIds,
- videoFilterIds, mDvrFeConnectionIds, mDvrSourceConnectionIds};
+ vector<vector<string>> deviceIds{descramblerIds, mfrontendIds, audioFilterIds,
+ mDvrFeConnectionIds, mDvrSourceConnectionIds};
auto idCombinations = generateIdCombinations(deviceIds);
for (auto& combo : idCombinations) {
DescramblingHardwareConnections mDescrambling;
@@ -353,7 +353,10 @@
}
mDescrambling.frontendId = feId;
mDescrambling.audioFilterId = combo[audioFilterIndex];
- mDescrambling.videoFilterId = combo[videoFilterIndex];
+ const int videoFilterIndex =
+ find(audioFilterIds.begin(), audioFilterIds.end(), mDescrambling.audioFilterId) -
+ audioFilterIds.begin();
+ mDescrambling.videoFilterId = videoFilterIds[videoFilterIndex];
mDescrambling.dvrSoftwareFeId = dvrSwFeId;
mDescrambling.dvrSourceId = dvrSourceId;
mDescrambling.descramblerId = combo[descramblerIndex];
@@ -378,6 +381,206 @@
return descrambling_configs;
}
+static inline vector<TimeFilterHardwareConnections> generateTimeFilterCombinations() {
+ vector<TimeFilterHardwareConnections> combinations;
+
+ for (auto& id : timeFilterIds) {
+ TimeFilterHardwareConnections mTimeFilter;
+ mTimeFilter.timeFilterId = id;
+ combinations.push_back(mTimeFilter);
+ }
+
+ return combinations;
+}
+
+static inline vector<TimeFilterHardwareConnections> generateTimeFilterConfigurations() {
+ vector<TimeFilterHardwareConnections> timeFilter_configs;
+ if (configuredTimeFilter) {
+ ALOGD("Using TimeFilter configuration provided.");
+ timeFilter_configs = {timeFilter};
+ } else {
+ ALOGD("TimeFilter not provided. Generating possible combinations. Consider adding it to "
+ "the "
+ "configuration file.");
+ timeFilter_configs = generateTimeFilterCombinations();
+ }
+
+ return timeFilter_configs;
+}
+
+/*
+ * index 0 - frontends
+ * index 1 - record dvrs
+ * index 2 - record filters
+ */
+static inline vector<DvrRecordHardwareConnections> generateRecordCombinations() {
+ vector<DvrRecordHardwareConnections> combinations;
+
+ const int frontendIdIndex = 0;
+ const int recordDvrIndex = 1;
+ const int recordFilterIndex = 2;
+
+ vector<vector<string>> deviceIds{frontendIds, recordDvrIds, recordFilterIds};
+
+ auto idCombinations = generateIdCombinations(deviceIds);
+ for (auto& combo : idCombinations) {
+ DvrRecordHardwareConnections mRecord;
+ const string feId = combo[frontendIdIndex];
+ mRecord.hasFrontendConnection = true;
+ if (frontendMap[feId].isSoftwareFe) {
+ // If we have a software frontend, do not include configuration for testing.
+ continue;
+ }
+ mRecord.frontendId = feId;
+ mRecord.support = true;
+ mRecord.dvrSourceId = emptyHardwareId;
+ mRecord.dvrSoftwareFeId = emptyHardwareId;
+ mRecord.recordFilterId = combo[recordFilterIndex];
+ mRecord.dvrRecordId = combo[recordDvrIndex];
+ combinations.push_back(mRecord);
+ }
+
+ return combinations;
+}
+
+static inline vector<DvrRecordHardwareConnections> generateRecordConfigurations() {
+ vector<DvrRecordHardwareConnections> record_configs;
+ if (configuredRecord) {
+ ALOGD("Using Record configuration provided.");
+ record_configs = {record};
+ } else {
+ ALOGD("Record not provided. Generating possible combinations. Consider adding it to "
+ "the "
+ "configuration file.");
+ record_configs = generateRecordCombinations();
+ }
+
+ return record_configs;
+}
+
+/*
+ * index 0 - frontends
+ * index 1 - audio filters
+ * index 2 - playback dvrs
+ * index 3 - section Filters
+ */
+static inline vector<LiveBroadcastHardwareConnections> generateLiveCombinations() {
+ vector<LiveBroadcastHardwareConnections> combinations;
+ vector<string> mSectionFilterIds = sectionFilterIds;
+ vector<string> mDvrSwConnectionIds = playbackDvrIds;
+
+ // Adding the empty hardware id to cover cases where fields are optional
+ mSectionFilterIds.push_back(emptyHardwareId);
+ mDvrSwConnectionIds.push_back(emptyHardwareId);
+
+ const int frontendIdIndex = 0;
+ const int audioFilterIdIndex = 1;
+ const int dvrSwConnectionIdIndex = 2;
+ const int sectionFilterIdIndex = 3;
+
+ vector<vector<string>> deviceIds{frontendIds, audioFilterIds, mDvrSwConnectionIds,
+ mSectionFilterIds};
+
+ auto idCombinations = generateIdCombinations(deviceIds);
+ for (auto& combo : idCombinations) {
+ LiveBroadcastHardwareConnections mLive;
+ const string feId = combo[frontendIdIndex];
+ const string dvrSwConnectionId = combo[dvrSwConnectionIdIndex];
+ mLive.hasFrontendConnection = true;
+
+ if (frontendMap[feId].isSoftwareFe && dvrSwConnectionId.compare(emptyHardwareId) == 0) {
+ // If the frontend is a software frontend and there is no dvr playback connected, do not
+ // include configuration
+ continue;
+ }
+ mLive.frontendId = feId;
+ mLive.dvrSoftwareFeId = dvrSwConnectionId;
+ mLive.audioFilterId = combo[audioFilterIdIndex];
+ const int videoFilterIdIndex =
+ find(audioFilterIds.begin(), audioFilterIds.end(), mLive.audioFilterId) -
+ audioFilterIds.begin();
+ mLive.videoFilterId = videoFilterIds[videoFilterIdIndex];
+ mLive.sectionFilterId = combo[sectionFilterIdIndex];
+
+ if (pcrFilterIds.empty()) {
+ // If pcr Filters have not been provided, set it to empty hardware id
+ mLive.pcrFilterId = emptyHardwareId;
+ } else {
+ // If pcr Filters have been provided, use the first index if there is only 1, or choose
+ // the filter that corresponds to the correct audio and video filter pair
+ const int pcrFilterIdIndex = pcrFilterIds.size() == 1 ? 0 : videoFilterIdIndex;
+ mLive.pcrFilterId = pcrFilterIds[pcrFilterIdIndex];
+ }
+
+ combinations.push_back(mLive);
+ }
+
+ return combinations;
+}
+
+static inline vector<LiveBroadcastHardwareConnections> generateLiveConfigurations() {
+ vector<LiveBroadcastHardwareConnections> live_configs;
+ if (configuredLive) {
+ ALOGD("Using Live configuration provided.");
+ live_configs = {live};
+ } else {
+ ALOGD("Live not provided. Generating possible combinations. Consider adding it to "
+ "the "
+ "configuration file.");
+ live_configs = generateLiveCombinations();
+ }
+
+ return live_configs;
+}
+
+static inline vector<LnbDescramblingHardwareConnections> generateLnbDescramblingCombinations() {
+ vector<LnbDescramblingHardwareConnections> combinations;
+ vector<vector<string>> deviceIds{frontendIds, audioFilterIds, lnbIds, descramblerIds};
+
+ const int frontendIdIndex = 0;
+ const int audioFilterIdIndex = 1;
+ const int lnbIdIndex = 2;
+ const int descramblerIdIndex = 3;
+
+ auto idCombinations = generateIdCombinations(deviceIds);
+ // TODO : Find a better way to vary diseqcMsgs, if at all
+ for (auto& combo : idCombinations) {
+ const string feId = combo[frontendIdIndex];
+ auto type = frontendMap[feId].type;
+ if (type == FrontendType::DVBS || type == FrontendType::ISDBS ||
+ type == FrontendType::ISDBS3) {
+ LnbDescramblingHardwareConnections mLnbDescrambling;
+ mLnbDescrambling.support = true;
+ mLnbDescrambling.frontendId = feId;
+ mLnbDescrambling.audioFilterId = combo[audioFilterIdIndex];
+ const int videoFilterIdIndex = find(audioFilterIds.begin(), audioFilterIds.end(),
+ mLnbDescrambling.audioFilterId) -
+ audioFilterIds.begin();
+ mLnbDescrambling.videoFilterId = videoFilterIds[videoFilterIdIndex];
+ mLnbDescrambling.lnbId = combo[lnbIdIndex];
+ mLnbDescrambling.descramblerId = combo[descramblerIdIndex];
+ mLnbDescrambling.diseqcMsgs = diseqcMsgs;
+ combinations.push_back(mLnbDescrambling);
+ }
+ }
+
+ return combinations;
+}
+
+static inline vector<LnbDescramblingHardwareConnections> generateLnbDescramblingConfigurations() {
+ vector<LnbDescramblingHardwareConnections> lnbDescrambling_configs;
+ if (configuredLnbDescrambling) {
+ ALOGD("Using LnbDescrambling configuration provided");
+ lnbDescrambling_configs = {lnbDescrambling};
+ } else {
+ ALOGD("LnbDescrambling not provided. Generating possible combinations. Consider adding it "
+ "to the configuration file.");
+ lnbDescrambling_configs = generateLnbDescramblingCombinations();
+ }
+
+ return lnbDescrambling_configs;
+}
+
/** Config all the frontends that would be used in the tests */
inline void initFrontendConfig() {
// The test will use the internal default fe when default fe is connected to any data flow
@@ -566,6 +769,15 @@
record.support = true;
}
+inline void determineLnbDescrambling() {
+ if (frontendIds.empty() || audioFilterIds.empty() || videoFilterIds.empty() || lnbIds.empty() ||
+ descramblerIds.empty()) {
+ return;
+ }
+ ALOGD("Can support LnbDescrambling.");
+ lnbDescrambling.support = true;
+}
+
/** Read the vendor configurations of which hardware to use for each test cases/data flows */
inline void connectHardwaresToTestCases() {
TunerTestingConfigAidlReader1_0::connectLiveBroadcast(live);
@@ -576,6 +788,7 @@
TunerTestingConfigAidlReader1_0::connectLnbLive(lnbLive);
TunerTestingConfigAidlReader1_0::connectLnbRecord(lnbRecord);
TunerTestingConfigAidlReader1_0::connectDvrPlayback(playback);
+ TunerTestingConfigAidlReader1_0::connectLnbDescrambling(lnbDescrambling);
};
inline void determineDataFlows() {
@@ -587,6 +800,7 @@
determineLive();
determineDescrambling();
determineDvrRecord();
+ determineLnbDescrambling();
}
inline bool validateConnections() {
@@ -612,6 +826,10 @@
feIsValid &=
lnbRecord.support ? frontendMap.find(lnbRecord.frontendId) != frontendMap.end() : true;
+ feIsValid &= lnbDescrambling.support
+ ? frontendMap.find(lnbDescrambling.frontendId) != frontendMap.end()
+ : true;
+
if (!feIsValid) {
ALOGW("[vts config] dynamic config fe connection is invalid.");
return false;
@@ -696,11 +914,29 @@
playback.hasExtraFilters ? filterMap.find(filterId) != filterMap.end() : true;
}
+ filterIsValid &=
+ lnbDescrambling.support
+ ? filterMap.find(lnbDescrambling.audioFilterId) != filterMap.end() &&
+ filterMap.find(lnbDescrambling.videoFilterId) != filterMap.end()
+ : true;
+
if (!filterIsValid) {
ALOGW("[vts config] dynamic config filter connection is invalid.");
return false;
}
+ if (audioFilterIds.size() != videoFilterIds.size()) {
+ ALOGW("[vts config] the number of audio and video filters should be equal");
+ return false;
+ }
+
+ if (!pcrFilterIds.empty() && pcrFilterIds.size() != 1 &&
+ pcrFilterIds.size() != audioFilterIds.size()) {
+ ALOGW("[vts config] When more than 1 pcr filter is configured, the number of pcr filters "
+ "must equal the number of audio and video filters.");
+ return false;
+ }
+
bool timeFilterIsValid =
timeFilter.support ? timeFilterMap.find(timeFilter.timeFilterId) != timeFilterMap.end()
: true;
@@ -714,6 +950,11 @@
? descramblerMap.find(descrambling.descramblerId) != descramblerMap.end()
: true;
+ descramblerIsValid &=
+ lnbDescrambling.support
+ ? descramblerMap.find(lnbDescrambling.descramblerId) != descramblerMap.end()
+ : true;
+
if (!descramblerIsValid) {
ALOGW("[vts config] dynamic config descrambler connection is invalid.");
return false;
@@ -723,6 +964,9 @@
lnbIsValid &= lnbRecord.support ? lnbMap.find(lnbRecord.lnbId) != lnbMap.end() : true;
+ lnbIsValid &=
+ lnbDescrambling.support ? lnbMap.find(lnbDescrambling.lnbId) != lnbMap.end() : true;
+
if (!lnbIsValid) {
ALOGW("[vts config] dynamic config lnb connection is invalid.");
return false;
@@ -738,6 +982,10 @@
diseqcMsgsIsValid &= diseqcMsgMap.find(msg) != diseqcMsgMap.end();
}
+ for (auto& msg : lnbDescrambling.diseqcMsgs) {
+ diseqcMsgsIsValid &= diseqcMsgMap.find(msg) != diseqcMsgMap.end();
+ }
+
if (!diseqcMsgsIsValid) {
ALOGW("[vts config] dynamic config diseqcMsg is invalid.");
return false;
diff --git a/tv/tuner/config/TunerTestingConfigAidlReaderV1_0.h b/tv/tuner/config/TunerTestingConfigAidlReaderV1_0.h
index 6fafd59..9517520 100644
--- a/tv/tuner/config/TunerTestingConfigAidlReaderV1_0.h
+++ b/tv/tuner/config/TunerTestingConfigAidlReaderV1_0.h
@@ -73,13 +73,17 @@
static bool configuredLnbRecord = false;
static bool configuredTimeFilter = false;
static bool configuredDescrambling = false;
+static bool configuredLnbDescrambling = false;
const string emptyHardwareId = "";
static string mConfigFilePath;
static vector<string> playbackDvrIds;
+static vector<string> ipFilterIds;
static vector<string> recordDvrIds;
+static vector<string> pcrFilterIds;
+static vector<string> timeFilterIds;
static vector<string> audioFilterIds;
static vector<string> videoFilterIds;
static vector<string> recordFilterIds;
@@ -226,6 +230,16 @@
string timeFilterId;
};
+struct LnbDescramblingHardwareConnections {
+ bool support;
+ string frontendId;
+ string audioFilterId;
+ string videoFilterId;
+ string lnbId;
+ string descramblerId;
+ vector<string> diseqcMsgs;
+};
+
struct TunerTestingConfigAidlReader1_0 {
public:
static void setConfigFilePath(string path) { mConfigFilePath = path; }
@@ -503,6 +517,7 @@
auto timeFilters = *hardwareConfig.getFirstTimeFilters();
for (auto timeFilterConfig : timeFilters.getTimeFilter()) {
string id = timeFilterConfig.getId();
+ timeFilterIds.push_back(id);
timeFilterMap[id].timeStamp = static_cast<int64_t>(timeFilterConfig.getTimeStamp());
}
}
@@ -701,6 +716,28 @@
timeFilter.timeFilterId = timeFilterConfig.getTimeFilterConnection();
}
+ static void connectLnbDescrambling(LnbDescramblingHardwareConnections& lnbDescrambling) {
+ auto dataFlow = getDataFlowConfiguration();
+ if (dataFlow.hasLnbDescrambling()) {
+ lnbDescrambling.support = true;
+ configuredLnbDescrambling = true;
+ } else {
+ lnbDescrambling.support = false;
+ return;
+ }
+ auto lnbDescramblingConfig = *dataFlow.getFirstLnbDescrambling();
+ lnbDescrambling.frontendId = lnbDescramblingConfig.getFrontendConnection();
+ lnbDescrambling.audioFilterId = lnbDescramblingConfig.getAudioFilterConnection();
+ lnbDescrambling.videoFilterId = lnbDescramblingConfig.getVideoFilterConnection();
+ lnbDescrambling.lnbId = lnbDescramblingConfig.getLnbConnection();
+ lnbDescrambling.descramblerId = lnbDescramblingConfig.getDescramblerConnection();
+ if (lnbDescramblingConfig.hasDiseqcMsgSender()) {
+ for (auto& msgName : lnbDescramblingConfig.getDiseqcMsgSender()) {
+ lnbDescrambling.diseqcMsgs.push_back(msgName);
+ }
+ }
+ }
+
private:
static FrontendDvbtSettings readDvbtFrontendSettings(Frontend feConfig) {
ALOGW("[ConfigReader] fe type is dvbt");
@@ -851,6 +888,10 @@
recordFilterIds.push_back(filterConfig.getId());
} else if (subType == FilterSubTypeEnum::SECTION) {
sectionFilterIds.push_back(filterConfig.getId());
+ } else if (subType == FilterSubTypeEnum::PCR) {
+ pcrFilterIds.push_back(filterConfig.getId());
+ } else if (subType == FilterSubTypeEnum::IP) {
+ ipFilterIds.push_back(filterConfig.getId());
}
switch (mainType) {
diff --git a/tv/tuner/config/api/current.txt b/tv/tuner/config/api/current.txt
index 79efb1b..dbd3486 100644
--- a/tv/tuner/config/api/current.txt
+++ b/tv/tuner/config/api/current.txt
@@ -27,6 +27,7 @@
method @Nullable public android.media.tuner.testing.configuration.V1_0.DataFlowConfiguration.Descrambling getDescrambling();
method @Nullable public android.media.tuner.testing.configuration.V1_0.DataFlowConfiguration.DvrPlayback getDvrPlayback();
method @Nullable public android.media.tuner.testing.configuration.V1_0.DataFlowConfiguration.DvrRecord getDvrRecord();
+ method @Nullable public android.media.tuner.testing.configuration.V1_0.DataFlowConfiguration.LnbDescrambling getLnbDescrambling();
method @Nullable public android.media.tuner.testing.configuration.V1_0.DataFlowConfiguration.LnbLive getLnbLive();
method @Nullable public android.media.tuner.testing.configuration.V1_0.DataFlowConfiguration.LnbRecord getLnbRecord();
method @Nullable public android.media.tuner.testing.configuration.V1_0.DataFlowConfiguration.Scan getScan();
@@ -35,6 +36,7 @@
method public void setDescrambling(@Nullable android.media.tuner.testing.configuration.V1_0.DataFlowConfiguration.Descrambling);
method public void setDvrPlayback(@Nullable android.media.tuner.testing.configuration.V1_0.DataFlowConfiguration.DvrPlayback);
method public void setDvrRecord(@Nullable android.media.tuner.testing.configuration.V1_0.DataFlowConfiguration.DvrRecord);
+ method public void setLnbDescrambling(@Nullable android.media.tuner.testing.configuration.V1_0.DataFlowConfiguration.LnbDescrambling);
method public void setLnbLive(@Nullable android.media.tuner.testing.configuration.V1_0.DataFlowConfiguration.LnbLive);
method public void setLnbRecord(@Nullable android.media.tuner.testing.configuration.V1_0.DataFlowConfiguration.LnbRecord);
method public void setScan(@Nullable android.media.tuner.testing.configuration.V1_0.DataFlowConfiguration.Scan);
@@ -111,6 +113,22 @@
method public void setRecordFilterConnection(@Nullable String);
}
+ public static class DataFlowConfiguration.LnbDescrambling {
+ ctor public DataFlowConfiguration.LnbDescrambling();
+ method @Nullable public String getAudioFilterConnection();
+ method @Nullable public String getDescramblerConnection();
+ method @Nullable public java.util.List<java.lang.String> getDiseqcMsgSender();
+ method @Nullable public String getFrontendConnection();
+ method @Nullable public String getLnbConnection();
+ method @Nullable public String getVideoFilterConnection();
+ method public void setAudioFilterConnection(@Nullable String);
+ method public void setDescramblerConnection(@Nullable String);
+ method public void setDiseqcMsgSender(@Nullable java.util.List<java.lang.String>);
+ method public void setFrontendConnection(@Nullable String);
+ method public void setLnbConnection(@Nullable String);
+ method public void setVideoFilterConnection(@Nullable String);
+ }
+
public static class DataFlowConfiguration.LnbLive {
ctor public DataFlowConfiguration.LnbLive();
method @Nullable public String getAudioFilterConnection();
diff --git a/tv/tuner/config/sample_tuner_vts_config_aidl_V1.xml b/tv/tuner/config/sample_tuner_vts_config_aidl_V1.xml
index 1a148a4..f74af7e 100644
--- a/tv/tuner/config/sample_tuner_vts_config_aidl_V1.xml
+++ b/tv/tuner/config/sample_tuner_vts_config_aidl_V1.xml
@@ -196,7 +196,6 @@
videoFilterConnection="FILTER_VIDEO_DEFAULT"
dvrSoftwareFeConnection="DVR_PLAYBACK_0"
dvrSourceConnection="DVR_PLAYBACK_1">
- <optionalFilters>FILTER_TS_RECORD_0 FILTER_IP_IP_0</optionalFilters>
</descrambling>
<timeFilter timeFilterConnection="TIME_FILTER_0"/>
<lnbLive frontendConnection="FE_DVBS_0"
@@ -209,5 +208,11 @@
dvrRecordConnection="DVR_RECORD_0"
lnbConnection="LNB_0"
diseqcMsgSender="DISEQC_POWER_ON"/>
+ <lnbDescrambling frontendConnection="FE_DVBS_0"
+ audioFilterConnection="FILTER_AUDIO_DEFAULT"
+ videoFilterConnection="FILTER_VIDEO_DEFAULT"
+ lnbConnection="LNB_1"
+ descramblerConnection="DESCRAMBLER_0"/>
+
</dataFlowConfiguration>
</TunerConfiguration>
diff --git a/tv/tuner/config/tuner_testing_dynamic_configuration.xsd b/tv/tuner/config/tuner_testing_dynamic_configuration.xsd
index e0f2579..c51ac51 100644
--- a/tv/tuner/config/tuner_testing_dynamic_configuration.xsd
+++ b/tv/tuner/config/tuner_testing_dynamic_configuration.xsd
@@ -726,6 +726,16 @@
<xs:attribute name="timeFilterConnection" type="timeFilterId" use="required"/>
</xs:complexType>
</xs:element>
+ <xs:element name="lnbDescrambling" minOccurs="0" maxOccurs="1">
+ <xs:complexType>
+ <xs:attribute name="frontendConnection" type="frontendId" use="required"/>
+ <xs:attribute name="audioFilterConnection" type="filterId" use="required"/>
+ <xs:attribute name="videoFilterConnection" type="filterId" use="required"/>
+ <xs:attribute name="lnbConnection" type="lnbId" use="required"/>
+ <xs:attribute name="descramblerConnection" type="descramblerId" use="required"/>
+ <xs:attribute name="diseqcMsgSender" type="diseqcMsgSender" use="optional"/>
+ </xs:complexType>
+ </xs:element>
</xs:sequence>
</xs:complexType>
diff --git a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl
index 42d52f1..4768f55 100644
--- a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl
+++ b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl
@@ -30,6 +30,8 @@
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
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/vts/VtsHalVibratorTargetTest.cpp b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
index 791d7e8..f50a5e7 100644
--- a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
+++ b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
@@ -444,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/wifi/1.6/default/Android.bp b/wifi/1.6/default/Android.bp
index d48d183..a132dee 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,121 @@
"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",
+ ],
}
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/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(