Merge "Revert^2 "[Aware] Support set cluster id in AIDL""
diff --git a/audio/OWNERS b/audio/OWNERS
index ede448c..3671685 100644
--- a/audio/OWNERS
+++ b/audio/OWNERS
@@ -1 +1,4 @@
-per-file README.md = elaurent@google.com,mnaganov@google.com
+# Bug component: 48436
+
+elaurent@google.com
+mnaganov@google.com
diff --git a/audio/aidl/Android.bp b/audio/aidl/Android.bp
index ef51361..e69306e 100644
--- a/audio/aidl/Android.bp
+++ b/audio/aidl/Android.bp
@@ -112,6 +112,7 @@
"android/hardware/audio/core/AudioMode.aidl",
"android/hardware/audio/core/AudioPatch.aidl",
"android/hardware/audio/core/AudioRoute.aidl",
+ "android/hardware/audio/core/IBluetooth.aidl",
"android/hardware/audio/core/IConfig.aidl",
"android/hardware/audio/core/IModule.aidl",
"android/hardware/audio/core/IStreamCallback.aidl",
diff --git a/audio/aidl/OWNERS b/audio/aidl/OWNERS
deleted file mode 100644
index f9a2d6b..0000000
--- a/audio/aidl/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 48436
-elaurent@google.com
-mnaganov@google.com
diff --git a/audio/aidl/TEST_MAPPING b/audio/aidl/TEST_MAPPING
index a166e61..6a545c1 100644
--- a/audio/aidl/TEST_MAPPING
+++ b/audio/aidl/TEST_MAPPING
@@ -13,6 +13,9 @@
"name": "VtsHalDownmixTargetTest"
},
{
+ "name": "VtsHalDynamicsProcessingTargetTest"
+ },
+ {
"name": "VtsHalEnvironmentalReverbTargetTest"
},
{
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IBluetooth.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IBluetooth.aidl
new file mode 100644
index 0000000..289c0c2
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IBluetooth.aidl
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.audio.core;
+@VintfStability
+interface IBluetooth {
+ android.hardware.audio.core.IBluetooth.ScoConfig setScoConfig(in android.hardware.audio.core.IBluetooth.ScoConfig config);
+ android.hardware.audio.core.IBluetooth.HfpConfig setHfpConfig(in android.hardware.audio.core.IBluetooth.HfpConfig config);
+ @JavaDerive(equals=true, toString=true) @VintfStability
+ parcelable ScoConfig {
+ @nullable android.media.audio.common.Boolean isEnabled;
+ @nullable android.media.audio.common.Boolean isNrecEnabled;
+ android.hardware.audio.core.IBluetooth.ScoConfig.Mode mode = android.hardware.audio.core.IBluetooth.ScoConfig.Mode.UNSPECIFIED;
+ @nullable @utf8InCpp String debugName;
+ @VintfStability
+ enum Mode {
+ UNSPECIFIED = 0,
+ SCO = 1,
+ SCO_WB = 2,
+ SCO_SWB = 3,
+ }
+ }
+ @JavaDerive(equals=true, toString=true) @VintfStability
+ parcelable HfpConfig {
+ @nullable android.media.audio.common.Boolean isEnabled;
+ @nullable android.media.audio.common.Int sampleRate;
+ @nullable android.media.audio.common.Float volume;
+ const int VOLUME_MIN = 0;
+ const int VOLUME_MAX = 1;
+ }
+}
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 a029d43..4486b66 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
@@ -36,6 +36,7 @@
interface IModule {
void setModuleDebug(in android.hardware.audio.core.ModuleDebug debug);
@nullable android.hardware.audio.core.ITelephony getTelephony();
+ @nullable android.hardware.audio.core.IBluetooth getBluetooth();
android.media.audio.common.AudioPort connectExternalDevice(in android.media.audio.common.AudioPort templateIdAndAdditionalData);
void disconnectExternalDevice(int portId);
android.hardware.audio.core.AudioPatch[] getAudioPatches();
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ITelephony.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ITelephony.aidl
index a8c58c1..77063df 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ITelephony.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ITelephony.aidl
@@ -36,4 +36,21 @@
interface ITelephony {
android.hardware.audio.core.AudioMode[] getSupportedAudioModes();
void switchAudioMode(android.hardware.audio.core.AudioMode mode);
+ android.hardware.audio.core.ITelephony.TelecomConfig setTelecomConfig(in android.hardware.audio.core.ITelephony.TelecomConfig config);
+ @JavaDerive(equals=true, toString=true) @VintfStability
+ parcelable TelecomConfig {
+ @nullable android.media.audio.common.Float voiceVolume;
+ android.hardware.audio.core.ITelephony.TelecomConfig.TtyMode ttyMode = android.hardware.audio.core.ITelephony.TelecomConfig.TtyMode.UNSPECIFIED;
+ @nullable android.media.audio.common.Boolean isHacEnabled;
+ const int VOICE_VOLUME_MIN = 0;
+ const int VOICE_VOLUME_MAX = 1;
+ @Backing(type="int") @VintfStability
+ enum TtyMode {
+ UNSPECIFIED = (-1),
+ OFF = 0,
+ FULL = 1,
+ HCO = 2,
+ VCO = 3,
+ }
+ }
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/CommandId.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/CommandId.aidl
index 79299ee..86b69fa 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/CommandId.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/CommandId.aidl
@@ -37,14 +37,14 @@
START = 0,
STOP = 1,
RESET = 2,
- VENDOR_COMMAND_0 = 256,
- VENDOR_COMMAND_1 = 257,
- VENDOR_COMMAND_2 = 258,
- VENDOR_COMMAND_3 = 259,
- VENDOR_COMMAND_4 = 260,
- VENDOR_COMMAND_5 = 261,
- VENDOR_COMMAND_6 = 262,
- VENDOR_COMMAND_7 = 263,
- VENDOR_COMMAND_8 = 264,
- VENDOR_COMMAND_9 = 265,
+ VENDOR_COMMAND_0 = 0x100,
+ VENDOR_COMMAND_1,
+ VENDOR_COMMAND_2,
+ VENDOR_COMMAND_3,
+ VENDOR_COMMAND_4,
+ VENDOR_COMMAND_5,
+ VENDOR_COMMAND_6,
+ VENDOR_COMMAND_7,
+ VENDOR_COMMAND_8,
+ VENDOR_COMMAND_9,
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Downmix.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Downmix.aidl
index 76f8ce5..402441d 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Downmix.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Downmix.aidl
@@ -47,7 +47,7 @@
}
@VintfStability
enum Type {
- STRIP = 0,
- FOLD = 1,
+ STRIP,
+ FOLD,
}
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/DynamicsProcessing.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/DynamicsProcessing.aidl
index ed4dc80..8e5b719 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/DynamicsProcessing.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/DynamicsProcessing.aidl
@@ -36,14 +36,14 @@
union DynamicsProcessing {
android.hardware.audio.effect.VendorExtension vendorExtension;
android.hardware.audio.effect.DynamicsProcessing.EngineArchitecture engineArchitecture;
- android.hardware.audio.effect.DynamicsProcessing.BandChannelConfig preEq;
- android.hardware.audio.effect.DynamicsProcessing.BandChannelConfig postEq;
- android.hardware.audio.effect.DynamicsProcessing.EqBandConfig preEqBand;
- android.hardware.audio.effect.DynamicsProcessing.EqBandConfig postEqBand;
- android.hardware.audio.effect.DynamicsProcessing.BandChannelConfig mbc;
- android.hardware.audio.effect.DynamicsProcessing.MbcBandConfig mbcBand;
- android.hardware.audio.effect.DynamicsProcessing.LimiterConfig limiter;
- float inputGainDb;
+ android.hardware.audio.effect.DynamicsProcessing.ChannelConfig[] preEq;
+ android.hardware.audio.effect.DynamicsProcessing.ChannelConfig[] postEq;
+ android.hardware.audio.effect.DynamicsProcessing.EqBandConfig[] preEqBand;
+ android.hardware.audio.effect.DynamicsProcessing.EqBandConfig[] postEqBand;
+ android.hardware.audio.effect.DynamicsProcessing.ChannelConfig[] mbc;
+ android.hardware.audio.effect.DynamicsProcessing.MbcBandConfig[] mbcBand;
+ android.hardware.audio.effect.DynamicsProcessing.LimiterConfig[] limiter;
+ android.hardware.audio.effect.DynamicsProcessing.InputGain[] inputGain;
@VintfStability
union Id {
int vendorExtensionTag;
@@ -52,37 +52,39 @@
@VintfStability
parcelable Capability {
ParcelableHolder extension;
+ float minCutOffFreq;
+ float maxCutOffFreq;
}
enum ResolutionPreference {
- FAVOR_FREQUENCY_RESOLUTION = 0,
- FAVOR_TIME_RESOLUTION = 1,
+ FAVOR_FREQUENCY_RESOLUTION,
+ FAVOR_TIME_RESOLUTION,
}
@VintfStability
- parcelable BandEnablement {
+ parcelable StageEnablement {
boolean inUse;
int bandCount;
}
@VintfStability
parcelable EngineArchitecture {
android.hardware.audio.effect.DynamicsProcessing.ResolutionPreference resolutionPreference = android.hardware.audio.effect.DynamicsProcessing.ResolutionPreference.FAVOR_FREQUENCY_RESOLUTION;
- float preferredFrameDurationMs;
- android.hardware.audio.effect.DynamicsProcessing.BandEnablement preEqBand;
- android.hardware.audio.effect.DynamicsProcessing.BandEnablement postEqBand;
- android.hardware.audio.effect.DynamicsProcessing.BandEnablement mbcBand;
+ float preferredProcessingDurationMs;
+ android.hardware.audio.effect.DynamicsProcessing.StageEnablement preEqStage;
+ android.hardware.audio.effect.DynamicsProcessing.StageEnablement postEqStage;
+ android.hardware.audio.effect.DynamicsProcessing.StageEnablement mbcStage;
boolean limiterInUse;
}
@VintfStability
- parcelable BandChannelConfig {
+ parcelable ChannelConfig {
int channel;
- android.hardware.audio.effect.DynamicsProcessing.BandEnablement enablement;
+ boolean enable;
}
@VintfStability
parcelable EqBandConfig {
int channel;
int band;
boolean enable;
- float cutoffFrequency;
- float gain;
+ float cutoffFrequencyHz;
+ float gainDb;
}
@VintfStability
parcelable MbcBandConfig {
@@ -90,7 +92,6 @@
int band;
boolean enable;
float cutoffFrequencyHz;
- float gainDb;
float attackTimeMs;
float releaseTimeMs;
float ratio;
@@ -105,7 +106,6 @@
parcelable LimiterConfig {
int channel;
boolean enable;
- boolean inUse;
int linkGroup;
float attackTimeMs;
float releaseTimeMs;
@@ -113,4 +113,9 @@
float thresholdDb;
float postGainDb;
}
+ @VintfStability
+ parcelable InputGain {
+ int channel;
+ float gainDb;
+ }
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/EnvironmentalReverb.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/EnvironmentalReverb.aidl
index 0e61932..7f34f33 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/EnvironmentalReverb.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/EnvironmentalReverb.aidl
@@ -44,15 +44,15 @@
int diffusionPm;
int densityPm;
boolean bypass;
- const int MIN_ROOM_LEVEL_MB = -6000;
+ const int MIN_ROOM_LEVEL_MB = (-6000);
const int MAX_ROOM_LEVEL_MB = 0;
- const int MIN_ROOM_HF_LEVEL_MB = -4000;
+ const int MIN_ROOM_HF_LEVEL_MB = (-4000);
const int MAX_ROOM_HF_LEVEL_MB = 0;
const int MIN_DECAY_TIME_MS = 100;
const int MAX_DECAY_TIME_MS = 20000;
const int MIN_DECAY_HF_RATIO_PM = 100;
const int MAX_DECAY_HF_RATIO_PM = 1000;
- const int MIN_LEVEL_MB = -6000;
+ const int MIN_LEVEL_MB = (-6000);
const int MAX_LEVEL_MB = 0;
const int MIN_DELAY_MS = 0;
const int MAX_DELAY_MS = 65;
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/HapticGenerator.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/HapticGenerator.aidl
index 40a8d72..20f7e02 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/HapticGenerator.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/HapticGenerator.aidl
@@ -35,7 +35,7 @@
@VintfStability
union HapticGenerator {
android.hardware.audio.effect.VendorExtension vendorExtension;
- android.hardware.audio.effect.HapticGenerator.HapticScale hapticScale;
+ android.hardware.audio.effect.HapticGenerator.HapticScale[] hapticScales;
android.hardware.audio.effect.HapticGenerator.VibratorInformation vibratorInfo;
@VintfStability
union Id {
@@ -48,9 +48,9 @@
}
@Backing(type="int") @VintfStability
enum VibratorScale {
- MUTE = -100,
- VERY_LOW = -2,
- LOW = -1,
+ MUTE = (-100),
+ VERY_LOW = (-2),
+ LOW = (-1),
NONE = 0,
HIGH = 1,
VERY_HIGH = 2,
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/NoiseSuppression.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/NoiseSuppression.aidl
index 223d95a..397f897 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/NoiseSuppression.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/NoiseSuppression.aidl
@@ -47,8 +47,8 @@
}
@Backing(type="int") @VintfStability
enum Level {
- LOW = 0,
- MEDIUM = 1,
- HIGH = 2,
+ LOW,
+ MEDIUM,
+ HIGH,
}
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/PresetReverb.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/PresetReverb.aidl
index 24a9ce1..4651742 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/PresetReverb.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/PresetReverb.aidl
@@ -38,13 +38,13 @@
android.hardware.audio.effect.PresetReverb.Presets preset;
@Backing(type="int") @VintfStability
enum Presets {
- NONE = 0,
- SMALLROOM = 1,
- MEDIUMROOM = 2,
- LARGEROOM = 3,
- MEDIUMHALL = 4,
- LARGEHALL = 5,
- PLATE = 6,
+ NONE,
+ SMALLROOM,
+ MEDIUMROOM,
+ LARGEROOM,
+ MEDIUMHALL,
+ LARGEHALL,
+ PLATE,
}
@VintfStability
union Id {
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/State.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/State.aidl
index 3176b01..17f9814 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/State.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/State.aidl
@@ -34,7 +34,7 @@
package android.hardware.audio.effect;
@Backing(type="byte") @VintfStability
enum State {
- INIT = 0,
- IDLE = 1,
- PROCESSING = 2,
+ INIT,
+ IDLE,
+ PROCESSING,
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Visualizer.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Visualizer.aidl
index 25f0b73..c8cb551 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Visualizer.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Visualizer.aidl
@@ -62,12 +62,12 @@
@VintfStability
enum ScalingMode {
NORMALIZED = 0,
- AS_PLAYED = 1,
+ AS_PLAYED,
}
@VintfStability
enum MeasurementMode {
NONE = 0,
- PEAK_RMS = 1,
+ PEAK_RMS,
}
@VintfStability
union GetOnlyParameters {
diff --git a/audio/aidl/android/hardware/audio/core/IBluetooth.aidl b/audio/aidl/android/hardware/audio/core/IBluetooth.aidl
new file mode 100644
index 0000000..21ac8e2
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/IBluetooth.aidl
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.core;
+
+import android.media.audio.common.Boolean;
+import android.media.audio.common.Float;
+import android.media.audio.common.Int;
+
+/**
+ * An instance of IBluetooth manages settings for the Hands-Free Profile (HFP)
+ * and the SCO Link. This interface is optional to implement and provide by the
+ * vendor. It needs to be provided only if the device actually supports BT SCO
+ * or HFP.
+ */
+@VintfStability
+interface IBluetooth {
+ @JavaDerive(equals=true, toString=true)
+ @VintfStability
+ parcelable ScoConfig {
+ /**
+ * Whether BT SCO is enabled. The client might need to disable it
+ * when another profile (for example, A2DP) is activated.
+ */
+ @nullable Boolean isEnabled;
+ /**
+ * Whether BT SCO Noise Reduction and Echo Cancellation are enabled.
+ */
+ @nullable Boolean isNrecEnabled;
+ @VintfStability enum Mode { UNSPECIFIED, SCO, SCO_WB, SCO_SWB }
+ /**
+ * If set, specifies the SCO mode to use:
+ * regular, wide band (WB), or super wide band (SWB).
+ */
+ Mode mode = Mode.UNSPECIFIED;
+ /**
+ * The name of the BT SCO headset used for debugging purposes. Can be empty.
+ */
+ @nullable @utf8InCpp String debugName;
+ }
+
+ /**
+ * Set the configuration of Bluetooth SCO.
+ *
+ * In the provided parcelable, the client sets zero, one or more parameters
+ * which have to be updated on the HAL side. The parameters that are left
+ * unset must retain their current values. It is allowed to change
+ * parameters while the SCO profile is disabled (isEnabled.value == false).
+ *
+ * In the returned parcelable, all parameter fields known to the HAL module
+ * must be populated to their current values. If the SCO profile is
+ * currently disabled (isEnabled.value == false), the parameters must
+ * reflect the last values that were in use.
+ *
+ * The client can pass an uninitialized parcelable in order to retrieve the
+ * current configuration.
+ *
+ * @return The current configuration (after update). All fields known to
+ * the HAL must be populated.
+ * @param config The configuration to set. Any number of fields may be left
+ * uninitialized.
+ * @throws EX_UNSUPPORTED_OPERATION If BT SCO is not supported.
+ * @throws EX_ILLEGAL_ARGUMENT If the requested combination of parameter
+ * values is invalid.
+ */
+ ScoConfig setScoConfig(in ScoConfig config);
+
+ @JavaDerive(equals=true, toString=true)
+ @VintfStability
+ parcelable HfpConfig {
+ /**
+ * Whether BT HFP is enabled.
+ */
+ @nullable Boolean isEnabled;
+ /**
+ * The sample rate of BT HFP, in Hertz. Must be a positive number.
+ */
+ @nullable Int sampleRate;
+
+ const int VOLUME_MIN = 0;
+ const int VOLUME_MAX = 1;
+ /**
+ * The output volume of BT HFP. 1.0f means unity gain, 0.0f is muted,
+ * see VOLUME_* constants;
+ */
+ @nullable Float volume;
+ }
+
+ /**
+ * Set the configuration of Bluetooth HFP.
+ *
+ * In the provided parcelable, the client sets zero, one or more parameters
+ * which have to be updated on the HAL side. The parameters that are left
+ * unset must retain their current values. It is allowed to change
+ * parameters while the HFP profile is disabled (isEnabled.value == false).
+ *
+ * In the returned parcelable, all parameter fields known to the HAL module
+ * must be populated to their current values. If the HFP profile is
+ * currently disabled (isEnabled.value == false), the parameters must
+ * reflect the last values that were in use.
+ *
+ * The client can pass an uninitialized parcelable in order to retrieve the
+ * current configuration.
+ *
+ * @return The current configuration (after update). All fields known to
+ * the HAL must be populated.
+ * @param config The configuration to set. Any number of fields may be left
+ * uninitialized.
+ * @throws EX_UNSUPPORTED_OPERATION If BT HFP is not supported.
+ * @throws EX_ILLEGAL_ARGUMENT If the requested combination of parameter
+ * values is invalid.
+ */
+ HfpConfig setHfpConfig(in HfpConfig config);
+}
diff --git a/audio/aidl/android/hardware/audio/core/IModule.aidl b/audio/aidl/android/hardware/audio/core/IModule.aidl
index 4779f1f..7bc1b9c 100644
--- a/audio/aidl/android/hardware/audio/core/IModule.aidl
+++ b/audio/aidl/android/hardware/audio/core/IModule.aidl
@@ -21,6 +21,7 @@
import android.hardware.audio.core.AudioMode;
import android.hardware.audio.core.AudioPatch;
import android.hardware.audio.core.AudioRoute;
+import android.hardware.audio.core.IBluetooth;
import android.hardware.audio.core.IStreamCallback;
import android.hardware.audio.core.IStreamIn;
import android.hardware.audio.core.IStreamOut;
@@ -86,6 +87,20 @@
@nullable ITelephony getTelephony();
/**
+ * Retrieve the interface to control Bluetooth SCO and HFP.
+ *
+ * If the HAL module supports either the SCO Link or Hands-Free Profile
+ * functionality (or both) for Bluetooth, it must return an instance of the
+ * IBluetooth interface. The same instance must be returned during the
+ * lifetime of the HAL module. If the HAL module does not support BT SCO and
+ * HFP, a null must be returned, without throwing any errors.
+ *
+ * @return An instance of the IBluetooth interface implementation.
+ * @throws EX_ILLEGAL_STATE If there was an error creating an instance.
+ */
+ @nullable IBluetooth getBluetooth();
+
+ /**
* Set a device port of an external device into connected state.
*
* This method is used to inform the HAL module that an external device has
diff --git a/audio/aidl/android/hardware/audio/core/ITelephony.aidl b/audio/aidl/android/hardware/audio/core/ITelephony.aidl
index a872c7c..a817032 100644
--- a/audio/aidl/android/hardware/audio/core/ITelephony.aidl
+++ b/audio/aidl/android/hardware/audio/core/ITelephony.aidl
@@ -17,6 +17,8 @@
package android.hardware.audio.core;
import android.hardware.audio.core.AudioMode;
+import android.media.audio.common.Boolean;
+import android.media.audio.common.Float;
/**
* An instance of ITelephony manages settings which are specific to voice calls
@@ -53,4 +55,75 @@
* @throws EX_ILLEGAL_STATE If there was an error during switching.
*/
void switchAudioMode(AudioMode mode);
+
+ @JavaDerive(equals=true, toString=true)
+ @VintfStability
+ parcelable TelecomConfig {
+ const int VOICE_VOLUME_MIN = 0;
+ const int VOICE_VOLUME_MAX = 1;
+ /**
+ * Volume of a voice call. 1.0f means unity gain, 0.0f is muted,
+ * see VOLUME_* constants.
+ */
+ @nullable Float voiceVolume;
+ /**
+ * The current mode of teletypewritter (TTY).
+ */
+ @VintfStability
+ @Backing(type="int")
+ enum TtyMode {
+ /**
+ * The default uninitialized value.
+ */
+ UNSPECIFIED = -1,
+ /**
+ * TTY mode is off.
+ */
+ OFF = 0,
+ /**
+ * TTY mode is on. The speaker is off and the microphone is muted. The
+ * user will communicate with the remote party by sending and receiving
+ * text messages.
+ */
+ FULL = 1,
+ /**
+ * TTY mode is in hearing carryover mode (HCO). The microphone is muted
+ * but the speaker is on. The user will communicate with the remote
+ * party by sending text messages and hearing an audible reply.
+ */
+ HCO = 2,
+ /**
+ * TTY mode is in voice carryover mode (VCO). The speaker is off but the
+ * microphone is still on. User will communicate with the remote party
+ * by speaking and receiving text message replies.
+ */
+ VCO = 3,
+ }
+ TtyMode ttyMode = TtyMode.UNSPECIFIED;
+ /**
+ * Whether Hearing Aid Compatibility - Telecoil (HAC-T) mode is enabled.
+ */
+ @nullable Boolean isHacEnabled;
+ }
+
+ /**
+ * Set the configuration of the telephony audio.
+ *
+ * In the provided parcelable, the client sets zero, one or more parameters
+ * which have to be updated on the HAL side. The parameters that are left
+ * unset must retain their current values.
+ *
+ * In the returned parcelable, all parameter fields known to the HAL module
+ * must be populated to their current values.The client can pass an
+ * uninitialized parcelable in order to retrieve the current configuration.
+ *
+ * @return The current configuration (after update). All fields known to
+ * the HAL must be populated.
+ * @param config The configuration to set. Any number of fields may be left
+ * uninitialized.
+ * @throws EX_UNSUPPORTED_OPERATION If telephony is not supported.
+ * @throws EX_ILLEGAL_ARGUMENT If the requested combination of parameter
+ * values is invalid.
+ */
+ TelecomConfig setTelecomConfig(in TelecomConfig config);
}
diff --git a/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv b/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv
index e25b15a..501dc01 100644
--- a/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv
+++ b/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv
@@ -30,6 +30,7 @@
STANDBY -> PAUSED [label="burst"]; // producer -> active
IDLE -> STANDBY [label="standby"]; // consumer -> passive
IDLE -> TRANSFERRING [label="burst"]; // producer -> active
+ IDLE -> ACTIVE [label="burst"]; // full write
ACTIVE -> PAUSED [label="pause"]; // consumer -> passive (not consuming)
ACTIVE -> DRAINING [label="drain"]; // producer -> passive
ACTIVE -> TRANSFERRING [label="burst"]; // early unblocking
@@ -45,6 +46,7 @@
PAUSED -> IDLE [label="flush"]; // producer -> passive, buffer is cleared
DRAINING -> IDLE [label="←IStreamCallback.onDrainReady"];
DRAINING -> TRANSFERRING [label="burst"]; // producer -> active
+ DRAINING -> ACTIVE [label="burst"]; // full write
DRAINING -> DRAIN_PAUSED [label="pause"]; // consumer -> passive (not consuming)
DRAIN_PAUSED -> DRAINING [label="start"]; // consumer -> active
DRAIN_PAUSED -> TRANSFER_PAUSED [label="burst"]; // producer -> active
diff --git a/audio/aidl/android/hardware/audio/core/stream-out-sm.gv b/audio/aidl/android/hardware/audio/core/stream-out-sm.gv
index 6aa5c61..47e7fda 100644
--- a/audio/aidl/android/hardware/audio/core/stream-out-sm.gv
+++ b/audio/aidl/android/hardware/audio/core/stream-out-sm.gv
@@ -31,6 +31,7 @@
ACTIVE -> ACTIVE [label="burst"];
ACTIVE -> PAUSED [label="pause"]; // consumer -> passive (not consuming)
ACTIVE -> DRAINING [label="drain"]; // producer -> passive
+ ACTIVE -> IDLE [label="drain"]; // synchronous drain
PAUSED -> PAUSED [label="burst"];
PAUSED -> ACTIVE [label="start"]; // consumer -> active
PAUSED -> IDLE [label="flush"]; // producer -> passive, buffer is cleared
diff --git a/audio/aidl/android/hardware/audio/effect/DynamicsProcessing.aidl b/audio/aidl/android/hardware/audio/effect/DynamicsProcessing.aidl
index ee5dcad..6db3338 100644
--- a/audio/aidl/android/hardware/audio/effect/DynamicsProcessing.aidl
+++ b/audio/aidl/android/hardware/audio/effect/DynamicsProcessing.aidl
@@ -51,6 +51,14 @@
* capability definition not enough.
*/
ParcelableHolder extension;
+ /**
+ * Min Cut off frequency (in Hz) for all Bands.
+ */
+ float minCutOffFreq;
+ /**
+ * Max Cut off frequency (in Hz) for all Bands.
+ */
+ float maxCutOffFreq;
}
/**
@@ -68,16 +76,16 @@
}
/**
- * Band enablement configuration.
+ * Stage enablement configuration.
*/
@VintfStability
- parcelable BandEnablement {
+ parcelable StageEnablement {
/**
- * True if multi-band stage is in use.
+ * True if stage is in use.
*/
boolean inUse;
/**
- * Number of bands configured for this stage.
+ * Number of bands configured for this stage. Must be positive when inUse is true.
*/
int bandCount;
}
@@ -92,21 +100,22 @@
*/
ResolutionPreference resolutionPreference = ResolutionPreference.FAVOR_FREQUENCY_RESOLUTION;
/**
- * Preferred frame duration in milliseconds (ms).
+ * Preferred processing duration in milliseconds (ms). Must not be negative, 0 means no
+ * preference.
*/
- float preferredFrameDurationMs;
+ float preferredProcessingDurationMs;
/**
* PreEq stage (Multi-band Equalizer) configuration.
*/
- BandEnablement preEqBand;
+ StageEnablement preEqStage;
/**
* PostEq stage (Multi-band Equalizer) configuration.
*/
- BandEnablement postEqBand;
+ StageEnablement postEqStage;
/**
* MBC stage (Multi-band Compressor) configuration.
*/
- BandEnablement mbcBand;
+ StageEnablement mbcStage;
/**
* True if Limiter stage is in use.
*/
@@ -114,18 +123,19 @@
}
/**
- * Band enablement configuration for a specific channel.
+ * Enablement configuration for a specific channel.
*/
@VintfStability
- parcelable BandChannelConfig {
+ parcelable ChannelConfig {
/**
- * Channel index.
+ * Channel index. Must not be negative, and not exceed the channel count calculated from
+ * Parameter.common.input.base.channelMask.
*/
int channel;
/**
- * Channel index.
+ * Channel enablement configuration. Can not be true if corresponding stage is not in use.
*/
- BandEnablement enablement;
+ boolean enable;
}
/**
@@ -134,7 +144,8 @@
@VintfStability
parcelable EqBandConfig {
/**
- * Channel index.
+ * Channel index. Must not be negative, and not exceed the channel count calculated from
+ * Parameter.common.input.base.channelMask.
*/
int channel;
/**
@@ -142,17 +153,20 @@
*/
int band;
/**
- * True if EQ stage is enabled.
+ * True if EQ band is enabled.
+ * If EngineArchitecture EQ stage inUse was set to false, then enable can not be set to
+ * true.
*/
boolean enable;
/**
- * Topmost frequency number (in Hz) this band will process.
+ * Topmost frequency number (in Hz) this band will process. Must be in the range of
+ * [minCutOffFreq, maxCutOffFreq] defined in Capability.
*/
- float cutoffFrequency;
+ float cutoffFrequencyHz;
/**
* Gain factor in decibels (dB).
*/
- float gain;
+ float gainDb;
}
/**
@@ -161,51 +175,53 @@
@VintfStability
parcelable MbcBandConfig {
/**
- * Channel index.
+ * Channel index. Must not be negative, and not exceed the channel count calculated from
+ * Parameter.common.input.base.channelMask.
*/
int channel;
/**
- * Band index, must in the range of [0, bandCount-1].
+ * Band index. Must be in the range of [0, bandCount-1].
*/
int band;
/**
- * True if MBC stage is enabled.
+ * True if MBC band is enabled.
+ * If EngineArchitecture MBC inUse was set to false, then enable here can not be set to
+ * true.
*/
boolean enable;
/**
- * Topmost frequency number (in Hz) this band will process.
+ * Topmost frequency number (in Hz) this band will process. Must be in the range of
+ * [minCutOffFreq, maxCutOffFreq] defined in Capability.
*/
float cutoffFrequencyHz;
/**
- * Gain factor in decibels (dB).
- */
- float gainDb;
- /**
- * Attack Time for compressor in milliseconds (ms).
+ * Attack Time for compressor in milliseconds (ms). Must not be negative.
*/
float attackTimeMs;
/**
- * Release Time for compressor in milliseconds (ms).
+ * Release Time for compressor in milliseconds (ms). Must not be negative.
*/
float releaseTimeMs;
/**
- * Compressor ratio (N:1) (input:output).
+ * Compressor ratio (N:1) (input:output). Must not be negative.
*/
float ratio;
/**
- * Compressor threshold measured in decibels (dB) from 0 dB Full Scale (dBFS).
+ * Compressor threshold measured in decibels (dB) from 0 dB Full Scale (dBFS). Must not be
+ * positive.
*/
float thresholdDb;
/**
- * Width in decibels (dB) around compressor threshold point.
+ * Width in decibels (dB) around compressor threshold point. Must not be negative.
*/
float kneeWidthDb;
/**
- * Noise gate threshold in decibels (dB) from 0 dB Full Scale (dBFS).
+ * Noise gate threshold in decibels (dB) from 0 dB Full Scale (dBFS). Must not be positive.
*/
float noiseGateThresholdDb;
/**
- * Expander ratio (1:N) (input:output) for signals below the Noise Gate Threshold.
+ * Expander ratio (1:N) (input:output) for signals below the Noise Gate Threshold. Must not
+ * be negative.
*/
float expanderRatio;
/**
@@ -224,36 +240,35 @@
@VintfStability
parcelable LimiterConfig {
/**
- * Channel index.
+ * Channel index. Must not be negative, and not exceed the channel count calculated from
+ * Parameter.common.input.base.channelMask.
*/
int channel;
/**
- * True if Limiter stage is enabled.
+ * True if Limiter band is enabled.
+ * If EngineArchitecture limiterInUse was set to false, then enable can not be set to true.
*/
boolean enable;
/**
- * True if Limiter stage is in use.
- */
- boolean inUse;
- /**
* Index of group assigned to this Limiter. Only limiters that share the same linkGroup
* index will react together.
*/
int linkGroup;
/**
- * Attack Time for compressor in milliseconds (ms).
+ * Attack Time for compressor in milliseconds (ms). Must not be negative.
*/
float attackTimeMs;
/**
- * Release Time for compressor in milliseconds (ms).
+ * Release Time for compressor in milliseconds (ms). Must not be negative.
*/
float releaseTimeMs;
/**
- * Compressor ratio (N:1) (input:output).
+ * Compressor ratio (N:1) (input:output). Must not be negative.
*/
float ratio;
/**
- * Compressor threshold measured in decibels (dB) from 0 dB Full Scale (dBFS).
+ * Compressor threshold measured in decibels (dB) from 0 dB Full Scale (dBFS). Must not be
+ * positive.
*/
float thresholdDb;
/**
@@ -263,39 +278,55 @@
}
/**
+ * Input gain for a channel (specified by the channel index).
+ */
+ @VintfStability
+ parcelable InputGain {
+ /**
+ * Channel index. Must not be negative, and not exceed the channel count calculated from
+ * Parameter.common.input.base.channelMask.
+ */
+ int channel;
+ /**
+ * Gain applied to the input signal in decibels (dB). 0 dB means no change in level.
+ */
+ float gainDb;
+ }
+
+ /**
* Effect engine architecture.
*/
EngineArchitecture engineArchitecture;
/**
- * PreEq stage per channel configuration.
+ * PreEq stage per channel configuration. Only valid when pre EQ stage inUse is true.
*/
- BandChannelConfig preEq;
+ ChannelConfig[] preEq;
/**
- * PostEq stage per channel configuration.
+ * PostEq stage per channel configuration. Only valid when post EQ stage inUse is true.
*/
- BandChannelConfig postEq;
+ ChannelConfig[] postEq;
/**
- * PreEq stage per band configuration.
+ * PreEq stage per band configuration. Only valid when pre EQ stage inUse is true.
*/
- EqBandConfig preEqBand;
+ EqBandConfig[] preEqBand;
/**
- * PostEq stage per band configuration.
+ * PostEq stage per band configuration. Only valid when post EQ stage inUse is true.
*/
- EqBandConfig postEqBand;
+ EqBandConfig[] postEqBand;
/**
- * MBC stage per channel configuration.
+ * MBC stage per channel configuration. Only valid when MBC stage inUse is true.
*/
- BandChannelConfig mbc;
+ ChannelConfig[] mbc;
/**
- * PostEq stage per band configuration.
+ * PostEq stage per band configuration. Only valid when MBC stage inUse is true.
*/
- MbcBandConfig mbcBand;
+ MbcBandConfig[] mbcBand;
/**
- * Limiter stage configuration.
+ * Limiter stage configuration. Only valid when limiter stage inUse is true.
*/
- LimiterConfig limiter;
+ LimiterConfig[] limiter;
/**
- * Input gain factor in decibels (dB). 0 dB means no change in level.
+ * Input gain factor.
*/
- float inputGainDb;
+ InputGain[] inputGain;
}
diff --git a/audio/aidl/android/hardware/audio/effect/HapticGenerator.aidl b/audio/aidl/android/hardware/audio/effect/HapticGenerator.aidl
index 944155f..3063ee3 100644
--- a/audio/aidl/android/hardware/audio/effect/HapticGenerator.aidl
+++ b/audio/aidl/android/hardware/audio/effect/HapticGenerator.aidl
@@ -90,6 +90,6 @@
float maxAmplitude;
}
- HapticScale hapticScale;
+ HapticScale[] hapticScales;
VibratorInformation vibratorInfo;
}
diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp
index 8cd56c0..1e6785f 100644
--- a/audio/aidl/default/Android.bp
+++ b/audio/aidl/default/Android.bp
@@ -62,6 +62,7 @@
export_include_dirs: ["include"],
srcs: [
"AudioPolicyConfigXmlConverter.cpp",
+ "Bluetooth.cpp",
"Config.cpp",
"Configuration.cpp",
"EngineConfigXmlConverter.cpp",
@@ -155,7 +156,7 @@
"libbassboostsw",
"libbundleaidl",
"libdownmixaidl",
- "libdynamicsprocessingsw",
+ "libdynamicsprocessingaidl",
"libenvreverbsw",
"libequalizersw",
"libhapticgeneratoraidl",
diff --git a/audio/aidl/default/Bluetooth.cpp b/audio/aidl/default/Bluetooth.cpp
new file mode 100644
index 0000000..38e0c21
--- /dev/null
+++ b/audio/aidl/default/Bluetooth.cpp
@@ -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.
+ */
+
+#define LOG_TAG "AHAL_Bluetooth"
+#include <android-base/logging.h>
+
+#include "core-impl/Bluetooth.h"
+
+using aidl::android::media::audio::common::Boolean;
+using aidl::android::media::audio::common::Float;
+using aidl::android::media::audio::common::Int;
+
+namespace aidl::android::hardware::audio::core {
+
+Bluetooth::Bluetooth() {
+ mScoConfig.isEnabled = Boolean{false};
+ mScoConfig.isNrecEnabled = Boolean{false};
+ mScoConfig.mode = ScoConfig::Mode::SCO;
+ mHfpConfig.isEnabled = Boolean{false};
+ mHfpConfig.sampleRate = Int{8000};
+ mHfpConfig.volume = Float{HfpConfig::VOLUME_MAX};
+}
+
+ndk::ScopedAStatus Bluetooth::setScoConfig(const ScoConfig& in_config, ScoConfig* _aidl_return) {
+ if (in_config.isEnabled.has_value()) {
+ mScoConfig.isEnabled = in_config.isEnabled;
+ }
+ if (in_config.isNrecEnabled.has_value()) {
+ mScoConfig.isNrecEnabled = in_config.isNrecEnabled;
+ }
+ if (in_config.mode != ScoConfig::Mode::UNSPECIFIED) {
+ mScoConfig.mode = in_config.mode;
+ }
+ if (in_config.debugName.has_value()) {
+ mScoConfig.debugName = in_config.debugName;
+ }
+ *_aidl_return = mScoConfig;
+ LOG(DEBUG) << __func__ << ": received " << in_config.toString() << ", returning "
+ << _aidl_return->toString();
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Bluetooth::setHfpConfig(const HfpConfig& in_config, HfpConfig* _aidl_return) {
+ if (in_config.sampleRate.has_value() && in_config.sampleRate.value().value <= 0) {
+ LOG(ERROR) << __func__ << ": invalid sample rate: " << in_config.sampleRate.value().value;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ if (in_config.volume.has_value() && (in_config.volume.value().value < HfpConfig::VOLUME_MIN ||
+ in_config.volume.value().value > HfpConfig::VOLUME_MAX)) {
+ LOG(ERROR) << __func__ << ": invalid volume: " << in_config.volume.value().value;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+
+ if (in_config.isEnabled.has_value()) {
+ mHfpConfig.isEnabled = in_config.isEnabled;
+ }
+ if (in_config.sampleRate.has_value()) {
+ mHfpConfig.sampleRate = in_config.sampleRate;
+ }
+ if (in_config.volume.has_value()) {
+ mHfpConfig.volume = in_config.volume;
+ }
+ *_aidl_return = mHfpConfig;
+ LOG(DEBUG) << __func__ << ": received " << in_config.toString() << ", returning "
+ << _aidl_return->toString();
+ return ndk::ScopedAStatus::ok();
+}
+
+} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp
index b58c562..13b04cd 100644
--- a/audio/aidl/default/Module.cpp
+++ b/audio/aidl/default/Module.cpp
@@ -25,6 +25,7 @@
#include <aidl/android/media/audio/common/AudioInputFlags.h>
#include <aidl/android/media/audio/common/AudioOutputFlags.h>
+#include "core-impl/Bluetooth.h"
#include "core-impl/Module.h"
#include "core-impl/SoundDose.h"
#include "core-impl/Telephony.h"
@@ -45,6 +46,7 @@
using aidl::android::media::audio::common::AudioPortConfig;
using aidl::android::media::audio::common::AudioPortExt;
using aidl::android::media::audio::common::AudioProfile;
+using aidl::android::media::audio::common::Boolean;
using aidl::android::media::audio::common::Int;
using aidl::android::media::audio::common::PcmType;
using android::hardware::audio::common::getFrameSizeInBytes;
@@ -137,12 +139,15 @@
(flags.getTag() == AudioIoFlags::Tag::output &&
!isBitPositionFlagSet(flags.get<AudioIoFlags::Tag::output>(),
AudioOutputFlags::MMAP_NOIRQ))) {
+ StreamContext::DebugParameters params{mDebug.streamTransientStateDelayMs,
+ mVendorDebug.forceTransientBurst,
+ mVendorDebug.forceSynchronousDrain};
StreamContext temp(
std::make_unique<StreamContext::CommandMQ>(1, true /*configureEventFlagWord*/),
std::make_unique<StreamContext::ReplyMQ>(1, true /*configureEventFlagWord*/),
portConfigIt->format.value(), portConfigIt->channelMask.value(),
std::make_unique<StreamContext::DataMQ>(frameSize * in_bufferSizeFrames),
- asyncCallback, mDebug.streamTransientStateDelayMs);
+ asyncCallback, params);
if (temp.isValid()) {
*out_context = std::move(temp);
} else {
@@ -326,6 +331,18 @@
return ndk::ScopedAStatus::ok();
}
+ndk::ScopedAStatus Module::getBluetooth(std::shared_ptr<IBluetooth>* _aidl_return) {
+ if (mBluetooth == nullptr) {
+ mBluetooth = ndk::SharedRefBase::make<Bluetooth>();
+ mBluetoothBinder = mBluetooth->asBinder();
+ AIBinder_setMinSchedulerPolicy(mBluetoothBinder.get(), SCHED_NORMAL,
+ ANDROID_PRIORITY_AUDIO);
+ }
+ *_aidl_return = mBluetooth;
+ LOG(DEBUG) << __func__ << ": returning instance of IBluetooth: " << _aidl_return->get();
+ return ndk::ScopedAStatus::ok();
+}
+
ndk::ScopedAStatus Module::connectExternalDevice(const AudioPort& in_templateIdAndAdditionalData,
AudioPort* _aidl_return) {
const int32_t templateId = in_templateIdAndAdditionalData.id;
@@ -963,18 +980,69 @@
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
+const std::string Module::VendorDebug::kForceTransientBurstName = "aosp.forceTransientBurst";
+const std::string Module::VendorDebug::kForceSynchronousDrainName = "aosp.forceSynchronousDrain";
+
ndk::ScopedAStatus Module::getVendorParameters(const std::vector<std::string>& in_ids,
std::vector<VendorParameter>* _aidl_return) {
LOG(DEBUG) << __func__ << ": id count: " << in_ids.size();
- (void)_aidl_return;
- return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ bool allParametersKnown = true;
+ for (const auto& id : in_ids) {
+ if (id == VendorDebug::kForceTransientBurstName) {
+ VendorParameter forceTransientBurst{.id = id};
+ forceTransientBurst.ext.setParcelable(Boolean{mVendorDebug.forceTransientBurst});
+ _aidl_return->push_back(std::move(forceTransientBurst));
+ } else if (id == VendorDebug::kForceSynchronousDrainName) {
+ VendorParameter forceSynchronousDrain{.id = id};
+ forceSynchronousDrain.ext.setParcelable(Boolean{mVendorDebug.forceSynchronousDrain});
+ _aidl_return->push_back(std::move(forceSynchronousDrain));
+ } else {
+ allParametersKnown = false;
+ LOG(ERROR) << __func__ << ": unrecognized parameter \"" << id << "\"";
+ }
+ }
+ if (allParametersKnown) return ndk::ScopedAStatus::ok();
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
+namespace {
+
+template <typename W>
+bool extractParameter(const VendorParameter& p, decltype(W::value)* v) {
+ std::optional<W> value;
+ binder_status_t result = p.ext.getParcelable(&value);
+ if (result == STATUS_OK && value.has_value()) {
+ *v = value.value().value;
+ return true;
+ }
+ LOG(ERROR) << __func__ << ": failed to read the value of the parameter \"" << p.id
+ << "\": " << result;
+ return false;
+}
+
+} // namespace
+
ndk::ScopedAStatus Module::setVendorParameters(const std::vector<VendorParameter>& in_parameters,
bool in_async) {
LOG(DEBUG) << __func__ << ": parameter count " << in_parameters.size()
<< ", async: " << in_async;
- return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ bool allParametersKnown = true;
+ for (const auto& p : in_parameters) {
+ if (p.id == VendorDebug::kForceTransientBurstName) {
+ if (!extractParameter<Boolean>(p, &mVendorDebug.forceTransientBurst)) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ } else if (p.id == VendorDebug::kForceSynchronousDrainName) {
+ if (!extractParameter<Boolean>(p, &mVendorDebug.forceSynchronousDrain)) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ } else {
+ allParametersKnown = false;
+ LOG(ERROR) << __func__ << ": unrecognized parameter \"" << p.id << "\"";
+ }
+ }
+ if (allParametersKnown) return ndk::ScopedAStatus::ok();
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
ndk::ScopedAStatus Module::addDeviceEffect(
diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp
index a490a2a..0520cba 100644
--- a/audio/aidl/default/Stream.cpp
+++ b/audio/aidl/default/Stream.cpp
@@ -402,7 +402,11 @@
usleep(1000); // Simulate a blocking call into the driver.
populateReply(&reply, mIsConnected);
// Can switch the state to ERROR if a driver error occurs.
- switchToTransientState(StreamDescriptor::State::DRAINING);
+ if (mState == StreamDescriptor::State::ACTIVE && mForceSynchronousDrain) {
+ mState = StreamDescriptor::State::IDLE;
+ } else {
+ switchToTransientState(StreamDescriptor::State::DRAINING);
+ }
} else if (mState == StreamDescriptor::State::TRANSFER_PAUSED) {
mState = StreamDescriptor::State::DRAIN_PAUSED;
populateReply(&reply, mIsConnected);
@@ -467,14 +471,19 @@
bool StreamOutWorkerLogic::write(size_t clientSize, StreamDescriptor::Reply* reply) {
const size_t readByteCount = mDataMQ->availableToRead();
- // Amount of data that the HAL module is going to actually use.
- const size_t byteCount = std::min({clientSize, readByteCount, mDataBufferSize});
bool fatal = false;
if (bool success = readByteCount > 0 ? mDataMQ->read(&mDataBuffer[0], readByteCount) : true) {
const bool isConnected = mIsConnected;
LOG(DEBUG) << __func__ << ": reading of " << readByteCount << " bytes from data MQ"
<< " succeeded; connected? " << isConnected;
- // Frames are consumed and counted regardless of connection status.
+ // Amount of data that the HAL module is going to actually use.
+ size_t byteCount = std::min({clientSize, readByteCount, mDataBufferSize});
+ if (byteCount >= mFrameSize && mForceTransientBurst) {
+ // In order to prevent the state machine from going to ACTIVE state,
+ // simulate partial write.
+ byteCount -= mFrameSize;
+ }
+ // Frames are consumed and counted regardless of the connection status.
reply->fmqByteCount += byteCount;
mFrameCount += byteCount / mFrameSize;
populateReply(reply, isConnected);
diff --git a/audio/aidl/default/Telephony.cpp b/audio/aidl/default/Telephony.cpp
index 1854b35..d873178 100644
--- a/audio/aidl/default/Telephony.cpp
+++ b/audio/aidl/default/Telephony.cpp
@@ -20,8 +20,17 @@
#include "core-impl/Telephony.h"
+using aidl::android::media::audio::common::Boolean;
+using aidl::android::media::audio::common::Float;
+
namespace aidl::android::hardware::audio::core {
+Telephony::Telephony() {
+ mTelecomConfig.voiceVolume = Float{TelecomConfig::VOICE_VOLUME_MAX};
+ mTelecomConfig.ttyMode = TelecomConfig::TtyMode::OFF;
+ mTelecomConfig.isHacEnabled = Boolean{false};
+}
+
ndk::ScopedAStatus Telephony::getSupportedAudioModes(std::vector<AudioMode>* _aidl_return) {
*_aidl_return = mSupportedAudioModes;
LOG(DEBUG) << __func__ << ": returning " << ::android::internal::ToString(*_aidl_return);
@@ -38,4 +47,28 @@
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
+ndk::ScopedAStatus Telephony::setTelecomConfig(const TelecomConfig& in_config,
+ TelecomConfig* _aidl_return) {
+ if (in_config.voiceVolume.has_value() &&
+ (in_config.voiceVolume.value().value < TelecomConfig::VOICE_VOLUME_MIN ||
+ in_config.voiceVolume.value().value > TelecomConfig::VOICE_VOLUME_MAX)) {
+ LOG(ERROR) << __func__
+ << ": voice volume value is invalid: " << in_config.voiceVolume.value().value;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ if (in_config.voiceVolume.has_value()) {
+ mTelecomConfig.voiceVolume = in_config.voiceVolume;
+ }
+ if (in_config.ttyMode != TelecomConfig::TtyMode::UNSPECIFIED) {
+ mTelecomConfig.ttyMode = in_config.ttyMode;
+ }
+ if (in_config.isHacEnabled.has_value()) {
+ mTelecomConfig.isHacEnabled = in_config.isHacEnabled;
+ }
+ *_aidl_return = mTelecomConfig;
+ LOG(DEBUG) << __func__ << ": received " << in_config.toString() << ", returning "
+ << _aidl_return->toString();
+ return ndk::ScopedAStatus::ok();
+}
+
} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.cpp b/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.cpp
index 7f06013..40b46e0 100644
--- a/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.cpp
+++ b/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.cpp
@@ -54,7 +54,6 @@
return EX_ILLEGAL_ARGUMENT;
}
*_aidl_return = AcousticEchoCancelerSw::kDescriptor;
- LOG(ERROR) << __func__ << "xxx " << _aidl_return->toString();
return EX_NONE;
}
diff --git a/audio/aidl/default/audio_effects_config.xml b/audio/aidl/default/audio_effects_config.xml
index 9670e9c..e460f89 100644
--- a/audio/aidl/default/audio_effects_config.xml
+++ b/audio/aidl/default/audio_effects_config.xml
@@ -33,7 +33,7 @@
<library name="bassboostsw" path="libbassboostsw.so"/>
<library name="bundle" path="libbundleaidl.so"/>
<library name="downmix" path="libdownmixaidl.so"/>
- <library name="dynamics_processingsw" path="libdynamicsprocessingsw.so"/>
+ <library name="dynamics_processing" path="libdynamicsprocessingaidl.so"/>
<library name="equalizersw" path="libequalizersw.so"/>
<library name="haptic_generator" path="libhapticgeneratoraidl.so"/>
<library name="loudness_enhancer" path="libloudnessenhanceraidl.so"/>
@@ -72,7 +72,7 @@
<libsw library="bundle" uuid="8631f300-72e2-11df-b57e-0002a5d5c51b"/>
</effectProxy>
<effect name="downmix" library="downmix" uuid="93f04452-e4fe-41cc-91f9-e475b6d1d69f"/>
- <effect name="dynamics_processing" library="dynamics_processingsw" uuid="fa818d78-588b-11ed-9b6a-0242ac120002"/>
+ <effect name="dynamics_processing" library="dynamics_processing" uuid="e0e6539b-1781-7261-676f-6d7573696340"/>
<effect name="haptic_generator" library="haptic_generator" uuid="97c4acd1-8b82-4f2f-832e-c2fe5d7a9931"/>
<effect name="loudness_enhancer" library="loudness_enhancer" uuid="fa415329-2034-4bea-b5dc-5b381c8d1e2c"/>
<effect name="env_reverb" library="env_reverbsw" uuid="fa819886-588b-11ed-9b6a-0242ac120002"/>
diff --git a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp
index 39345a9..0ffbaa1 100644
--- a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp
+++ b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp
@@ -18,6 +18,7 @@
#define LOG_TAG "AHAL_DynamicsProcessingSw"
#include <Utils.h>
#include <algorithm>
+#include <set>
#include <unordered_set>
#include <android-base/logging.h>
@@ -60,7 +61,8 @@
namespace aidl::android::hardware::audio::effect {
const std::string DynamicsProcessingSw::kEffectName = "DynamicsProcessingSw";
-const DynamicsProcessing::Capability DynamicsProcessingSw::kCapability;
+const DynamicsProcessing::Capability DynamicsProcessingSw::kCapability = {.minCutOffFreq = 220,
+ .maxCutOffFreq = 20000};
const Descriptor DynamicsProcessingSw::kDescriptor = {
.common = {.id = {.type = kDynamicsProcessingTypeUUID,
.uuid = kDynamicsProcessingSwImplUUID,
@@ -83,16 +85,143 @@
RETURN_IF(Parameter::Specific::dynamicsProcessing != specific.getTag(), EX_ILLEGAL_ARGUMENT,
"EffectNotSupported");
- mSpecificParam = specific.get<Parameter::Specific::dynamicsProcessing>();
- LOG(DEBUG) << __func__ << " success with: " << specific.toString();
- return ndk::ScopedAStatus::ok();
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+ LOG(INFO) << __func__ << specific.toString();
+ auto& dpParam = specific.get<Parameter::Specific::dynamicsProcessing>();
+ auto tag = dpParam.getTag();
+ switch (tag) {
+ case DynamicsProcessing::engineArchitecture: {
+ RETURN_IF(mContext->setEngineArchitecture(
+ dpParam.get<DynamicsProcessing::engineArchitecture>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setEngineArchitectureFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case DynamicsProcessing::preEq: {
+ RETURN_IF(mContext->setPreEqChannelCfgs(dpParam.get<DynamicsProcessing::preEq>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setPreEqChannelCfgsFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case DynamicsProcessing::postEq: {
+ RETURN_IF(mContext->setPostEqChannelCfgs(dpParam.get<DynamicsProcessing::postEq>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setPostEqChannelCfgsFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case DynamicsProcessing::mbc: {
+ RETURN_IF(mContext->setMbcChannelCfgs(dpParam.get<DynamicsProcessing::mbc>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setMbcChannelCfgsFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case DynamicsProcessing::preEqBand: {
+ RETURN_IF(mContext->setPreEqBandCfgs(dpParam.get<DynamicsProcessing::preEqBand>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setPreEqBandCfgsFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case DynamicsProcessing::postEqBand: {
+ RETURN_IF(mContext->setPostEqBandCfgs(dpParam.get<DynamicsProcessing::postEqBand>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setPostEqBandCfgsFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case DynamicsProcessing::mbcBand: {
+ RETURN_IF(mContext->setMbcBandCfgs(dpParam.get<DynamicsProcessing::mbcBand>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setMbcBandCfgsFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case DynamicsProcessing::limiter: {
+ RETURN_IF(mContext->setLimiterCfgs(dpParam.get<DynamicsProcessing::limiter>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "limiterCfgsFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case DynamicsProcessing::inputGain: {
+ RETURN_IF(mContext->setInputGainCfgs(dpParam.get<DynamicsProcessing::inputGain>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "inputGainCfgFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case DynamicsProcessing::vendorExtension: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_ARGUMENT, "DynamicsProcessingTagNotSupported");
+ }
+ }
}
ndk::ScopedAStatus DynamicsProcessingSw::getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) {
auto tag = id.getTag();
RETURN_IF(Parameter::Id::dynamicsProcessingTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
- specific->set<Parameter::Specific::dynamicsProcessing>(mSpecificParam);
+ auto dpId = id.get<Parameter::Id::dynamicsProcessingTag>();
+ auto dpIdTag = dpId.getTag();
+ switch (dpIdTag) {
+ case DynamicsProcessing::Id::commonTag:
+ return getParameterDynamicsProcessing(dpId.get<DynamicsProcessing::Id::commonTag>(),
+ specific);
+ case DynamicsProcessing::Id::vendorExtensionTag:
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(dpIdTag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_ARGUMENT, "DynamicsProcessingTagNotSupported");
+ }
+}
+
+ndk::ScopedAStatus DynamicsProcessingSw::getParameterDynamicsProcessing(
+ const DynamicsProcessing::Tag& tag, Parameter::Specific* specific) {
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+ DynamicsProcessing dpParam;
+ switch (tag) {
+ case DynamicsProcessing::Tag::engineArchitecture: {
+ dpParam.set<DynamicsProcessing::engineArchitecture>(mContext->getEngineArchitecture());
+ break;
+ }
+ case DynamicsProcessing::Tag::preEq: {
+ dpParam.set<DynamicsProcessing::preEq>(mContext->getPreEqChannelCfgs());
+ break;
+ }
+ case DynamicsProcessing::Tag::postEq: {
+ dpParam.set<DynamicsProcessing::postEq>(mContext->getPostEqChannelCfgs());
+ break;
+ }
+ case DynamicsProcessing::Tag::mbc: {
+ dpParam.set<DynamicsProcessing::mbc>(mContext->getMbcChannelCfgs());
+ break;
+ }
+ case DynamicsProcessing::Tag::preEqBand: {
+ dpParam.set<DynamicsProcessing::preEqBand>(mContext->getPreEqBandCfgs());
+ break;
+ }
+ case DynamicsProcessing::Tag::postEqBand: {
+ dpParam.set<DynamicsProcessing::postEqBand>(mContext->getPostEqBandCfgs());
+ break;
+ }
+ case DynamicsProcessing::Tag::mbcBand: {
+ dpParam.set<DynamicsProcessing::mbcBand>(mContext->getMbcBandCfgs());
+ break;
+ }
+ case DynamicsProcessing::Tag::limiter: {
+ dpParam.set<DynamicsProcessing::limiter>(mContext->getLimiterCfgs());
+ break;
+ }
+ case DynamicsProcessing::Tag::inputGain: {
+ dpParam.set<DynamicsProcessing::inputGain>(mContext->getInputGainCfgs());
+ break;
+ }
+ case DynamicsProcessing::vendorExtension: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_ARGUMENT, "DynamicsProcessingTagNotSupported");
+ }
+ }
+
+ specific->set<Parameter::Specific::dynamicsProcessing>(dpParam);
+ LOG(INFO) << __func__ << specific->toString();
return ndk::ScopedAStatus::ok();
}
@@ -127,4 +256,252 @@
return {STATUS_OK, samples, samples};
}
+RetCode DynamicsProcessingSwContext::setCommon(const Parameter::Common& common) {
+ mCommon = common;
+ mChannelCount =
+ ::android::hardware::audio::common::getChannelCount(common.input.base.channelMask);
+ resizeChannels();
+ resizeBands();
+ LOG(INFO) << __func__ << mCommon.toString();
+ return RetCode::SUCCESS;
+}
+
+RetCode DynamicsProcessingSwContext::setEngineArchitecture(
+ const DynamicsProcessing::EngineArchitecture& cfg) {
+ RETURN_VALUE_IF(!validateEngineConfig(cfg), RetCode::ERROR_ILLEGAL_PARAMETER,
+ "illegalEngineConfig");
+
+ if (mEngineSettings == cfg) {
+ LOG(INFO) << __func__ << " not change in engine, do nothing";
+ return RetCode::SUCCESS;
+ }
+ mEngineSettings = cfg;
+ resizeBands();
+ return RetCode::SUCCESS;
+}
+
+RetCode DynamicsProcessingSwContext::setChannelCfgs(
+ const std::vector<DynamicsProcessing::ChannelConfig>& cfgs,
+ std::vector<DynamicsProcessing::ChannelConfig>& targetCfgs,
+ const DynamicsProcessing::StageEnablement& stage) {
+ RETURN_VALUE_IF(!stage.inUse, RetCode::ERROR_ILLEGAL_PARAMETER, "stageNotInUse");
+
+ RetCode ret = RetCode::SUCCESS;
+ std::unordered_set<int> channelSet;
+ for (auto& cfg : cfgs) {
+ if (cfg.channel < 0 || (size_t)cfg.channel >= mChannelCount) {
+ LOG(ERROR) << __func__ << " skip illegal channel config " << cfg.toString();
+ ret = RetCode::ERROR_ILLEGAL_PARAMETER;
+ continue;
+ }
+ if (0 != channelSet.count(cfg.channel)) {
+ LOG(WARNING) << __func__ << " duplicated channel " << cfg.channel;
+ ret = RetCode::ERROR_ILLEGAL_PARAMETER;
+ } else {
+ channelSet.insert(cfg.channel);
+ }
+ targetCfgs[cfg.channel] = cfg;
+ }
+ return ret;
+}
+
+RetCode DynamicsProcessingSwContext::setPreEqChannelCfgs(
+ const std::vector<DynamicsProcessing::ChannelConfig>& cfgs) {
+ return setChannelCfgs(cfgs, mPreEqChCfgs, mEngineSettings.preEqStage);
+}
+
+RetCode DynamicsProcessingSwContext::setPostEqChannelCfgs(
+ const std::vector<DynamicsProcessing::ChannelConfig>& cfgs) {
+ return setChannelCfgs(cfgs, mPostEqChCfgs, mEngineSettings.postEqStage);
+}
+
+RetCode DynamicsProcessingSwContext::setMbcChannelCfgs(
+ const std::vector<DynamicsProcessing::ChannelConfig>& cfgs) {
+ return setChannelCfgs(cfgs, mMbcChCfgs, mEngineSettings.mbcStage);
+}
+
+RetCode DynamicsProcessingSwContext::setEqBandCfgs(
+ const std::vector<DynamicsProcessing::EqBandConfig>& cfgs,
+ std::vector<DynamicsProcessing::EqBandConfig>& targetCfgs,
+ const DynamicsProcessing::StageEnablement& stage,
+ const std::vector<DynamicsProcessing::ChannelConfig>& channelConfig) {
+ RETURN_VALUE_IF(!stage.inUse, RetCode::ERROR_ILLEGAL_PARAMETER, "eqStageNotInUse");
+
+ RetCode ret = RetCode::SUCCESS;
+ std::set<std::pair<int /* channel */, int /* band */>> bandSet;
+
+ for (auto& cfg : cfgs) {
+ if (0 != bandSet.count({cfg.channel, cfg.band})) {
+ LOG(WARNING) << __func__ << " duplicated band " << cfg.toString();
+ ret = RetCode::ERROR_ILLEGAL_PARAMETER;
+ } else {
+ bandSet.insert({cfg.channel, cfg.band});
+ }
+ if (!validateEqBandConfig(cfg, mChannelCount, stage.bandCount, channelConfig)) {
+ LOG(WARNING) << __func__ << " skip invalid band " << cfg.toString();
+ ret = RetCode::ERROR_ILLEGAL_PARAMETER;
+ continue;
+ ;
+ }
+ targetCfgs[cfg.channel * stage.bandCount + cfg.band] = cfg;
+ }
+ return ret;
+}
+
+RetCode DynamicsProcessingSwContext::setPreEqBandCfgs(
+ const std::vector<DynamicsProcessing::EqBandConfig>& cfgs) {
+ return setEqBandCfgs(cfgs, mPreEqChBands, mEngineSettings.preEqStage, mPreEqChCfgs);
+}
+
+RetCode DynamicsProcessingSwContext::setPostEqBandCfgs(
+ const std::vector<DynamicsProcessing::EqBandConfig>& cfgs) {
+ return setEqBandCfgs(cfgs, mPostEqChBands, mEngineSettings.postEqStage, mPostEqChCfgs);
+}
+
+RetCode DynamicsProcessingSwContext::setMbcBandCfgs(
+ const std::vector<DynamicsProcessing::MbcBandConfig>& cfgs) {
+ RETURN_VALUE_IF(!mEngineSettings.mbcStage.inUse, RetCode::ERROR_ILLEGAL_PARAMETER,
+ "mbcNotInUse");
+
+ RetCode ret = RetCode::SUCCESS;
+ std::set<std::pair<int /* channel */, int /* band */>> bandSet;
+
+ int bandCount = mEngineSettings.mbcStage.bandCount;
+ std::vector<bool> filled(mChannelCount * bandCount, false);
+ for (auto& it : cfgs) {
+ if (0 != bandSet.count({it.channel, it.band})) {
+ LOG(WARNING) << __func__ << " duplicated band " << it.toString();
+ ret = RetCode::ERROR_ILLEGAL_PARAMETER;
+ } else {
+ bandSet.insert({it.channel, it.band});
+ }
+ if (!validateMbcBandConfig(it, mChannelCount, mEngineSettings.mbcStage.bandCount,
+ mMbcChCfgs)) {
+ LOG(WARNING) << __func__ << " skip invalid band " << it.toString();
+ ret = RetCode::ERROR_ILLEGAL_PARAMETER;
+ continue;
+ ;
+ }
+ mMbcChBands[it.channel * bandCount + it.band] = it;
+ }
+ return ret;
+}
+
+RetCode DynamicsProcessingSwContext::setLimiterCfgs(
+ const std::vector<DynamicsProcessing::LimiterConfig>& cfgs) {
+ RETURN_VALUE_IF(!mEngineSettings.limiterInUse, RetCode::ERROR_ILLEGAL_PARAMETER,
+ "limiterNotInUse");
+
+ RetCode ret = RetCode::SUCCESS;
+ std::unordered_set<int> channelSet;
+
+ for (auto& it : cfgs) {
+ if (0 != channelSet.count(it.channel)) {
+ LOG(WARNING) << __func__ << " duplicated channel " << it.channel;
+ ret = RetCode::ERROR_ILLEGAL_PARAMETER;
+ } else {
+ channelSet.insert(it.channel);
+ }
+ if (!validateLimiterConfig(it, mChannelCount)) {
+ LOG(WARNING) << __func__ << " skip invalid limiter " << it.toString();
+ ret = RetCode::ERROR_ILLEGAL_PARAMETER;
+ continue;
+ }
+ mLimiterCfgs[it.channel] = it;
+ }
+ return ret;
+}
+
+void DynamicsProcessingSwContext::resizeChannels() {
+ if (mPreEqChCfgs.size() != mChannelCount) {
+ mPreEqChCfgs.resize(mChannelCount, {.channel = kInvalidChannelId});
+ }
+ if (mPostEqChCfgs.size() != mChannelCount) {
+ mPostEqChCfgs.resize(mChannelCount, {.channel = kInvalidChannelId});
+ }
+ if (mMbcChCfgs.size() != mChannelCount) {
+ mMbcChCfgs.resize(mChannelCount, {.channel = kInvalidChannelId});
+ }
+ if (mLimiterCfgs.size() != mChannelCount) {
+ mLimiterCfgs.resize(mChannelCount, {.channel = kInvalidChannelId});
+ }
+ if (mInputGainCfgs.size() != mChannelCount) {
+ mInputGainCfgs.resize(mChannelCount, {.channel = kInvalidChannelId});
+ }
+}
+
+void DynamicsProcessingSwContext::resizeBands() {
+ if (mPreEqChBands.size() != (size_t)(mChannelCount * mEngineSettings.preEqStage.bandCount)) {
+ mPreEqChBands.resize(mChannelCount * mEngineSettings.preEqStage.bandCount,
+ {.channel = kInvalidChannelId});
+ }
+ if (mPostEqChBands.size() != (size_t)(mChannelCount * mEngineSettings.postEqStage.bandCount)) {
+ mPostEqChBands.resize(mChannelCount * mEngineSettings.postEqStage.bandCount,
+ {.channel = kInvalidChannelId});
+ }
+ if (mMbcChBands.size() != (size_t)(mChannelCount * mEngineSettings.mbcStage.bandCount)) {
+ mMbcChBands.resize(mChannelCount * mEngineSettings.mbcStage.bandCount,
+ {.channel = kInvalidChannelId});
+ }
+}
+
+RetCode DynamicsProcessingSwContext::setInputGainCfgs(
+ const std::vector<DynamicsProcessing::InputGain>& cfgs) {
+ for (const auto& cfg : cfgs) {
+ RETURN_VALUE_IF(cfg.channel < 0 || (size_t)cfg.channel >= mChannelCount,
+ RetCode::ERROR_ILLEGAL_PARAMETER, "invalidChannel");
+ mInputGainCfgs[cfg.channel] = cfg;
+ }
+ return RetCode::SUCCESS;
+}
+
+std::vector<DynamicsProcessing::InputGain> DynamicsProcessingSwContext::getInputGainCfgs() {
+ std::vector<DynamicsProcessing::InputGain> ret;
+ std::copy_if(mInputGainCfgs.begin(), mInputGainCfgs.end(), std::back_inserter(ret),
+ [&](const auto& gain) { return gain.channel != kInvalidChannelId; });
+ return ret;
+}
+
+bool DynamicsProcessingSwContext::validateCutoffFrequency(float freq) {
+ return freq >= DynamicsProcessingSw::kCapability.minCutOffFreq &&
+ freq <= DynamicsProcessingSw::kCapability.maxCutOffFreq;
+}
+
+bool DynamicsProcessingSwContext::validateStageEnablement(
+ const DynamicsProcessing::StageEnablement& enablement) {
+ return !enablement.inUse || (enablement.inUse && enablement.bandCount > 0);
+}
+
+bool DynamicsProcessingSwContext::validateEngineConfig(
+ const DynamicsProcessing::EngineArchitecture& engine) {
+ return engine.preferredProcessingDurationMs >= 0 &&
+ validateStageEnablement(engine.preEqStage) &&
+ validateStageEnablement(engine.postEqStage) && validateStageEnablement(engine.mbcStage);
+}
+
+bool DynamicsProcessingSwContext::validateEqBandConfig(
+ const DynamicsProcessing::EqBandConfig& band, int maxChannel, int maxBand,
+ const std::vector<DynamicsProcessing::ChannelConfig>& channelConfig) {
+ return band.channel >= 0 && band.channel < maxChannel &&
+ (size_t)band.channel < channelConfig.size() && channelConfig[band.channel].enable &&
+ band.band >= 0 && band.band < maxBand && validateCutoffFrequency(band.cutoffFrequencyHz);
+}
+
+bool DynamicsProcessingSwContext::validateMbcBandConfig(
+ const DynamicsProcessing::MbcBandConfig& band, int maxChannel, int maxBand,
+ const std::vector<DynamicsProcessing::ChannelConfig>& channelConfig) {
+ return band.channel >= 0 && band.channel < maxChannel &&
+ (size_t)band.channel < channelConfig.size() && channelConfig[band.channel].enable &&
+ band.band >= 0 && band.band < maxBand &&
+ validateCutoffFrequency(band.cutoffFrequencyHz) && band.attackTimeMs >= 0 &&
+ band.releaseTimeMs >= 0 && band.ratio >= 0 && band.thresholdDb <= 0 &&
+ band.kneeWidthDb <= 0 && band.noiseGateThresholdDb <= 0 && band.expanderRatio >= 0;
+}
+
+bool DynamicsProcessingSwContext::validateLimiterConfig(
+ const DynamicsProcessing::LimiterConfig& limiter, int maxChannel) {
+ return limiter.channel >= 0 && limiter.channel < maxChannel && limiter.attackTimeMs >= 0 &&
+ limiter.releaseTimeMs >= 0 && limiter.ratio >= 0 && limiter.thresholdDb <= 0;
+}
+
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h
index 2ae46c5..e336df7 100644
--- a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h
+++ b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h
@@ -29,11 +29,77 @@
class DynamicsProcessingSwContext final : public EffectContext {
public:
DynamicsProcessingSwContext(int statusDepth, const Parameter::Common& common)
- : EffectContext(statusDepth, common) {
+ : EffectContext(statusDepth, common),
+ mChannelCount(::android::hardware::audio::common::getChannelCount(
+ common.input.base.channelMask)),
+ mPreEqChCfgs(mChannelCount, {.channel = kInvalidChannelId}),
+ mPostEqChCfgs(mChannelCount, {.channel = kInvalidChannelId}),
+ mMbcChCfgs(mChannelCount, {.channel = kInvalidChannelId}),
+ mLimiterCfgs(mChannelCount, {.channel = kInvalidChannelId}) {
LOG(DEBUG) << __func__;
}
- // TODO: add specific context here
-};
+
+ // utils
+ RetCode setChannelCfgs(const std::vector<DynamicsProcessing::ChannelConfig>& cfgs,
+ std::vector<DynamicsProcessing::ChannelConfig>& targetCfgs,
+ const DynamicsProcessing::StageEnablement& engineSetting);
+
+ RetCode setEqBandCfgs(const std::vector<DynamicsProcessing::EqBandConfig>& cfgs,
+ std::vector<DynamicsProcessing::EqBandConfig>& targetCfgs,
+ const DynamicsProcessing::StageEnablement& stage,
+ const std::vector<DynamicsProcessing::ChannelConfig>& channelConfig);
+
+ // set params
+ RetCode setCommon(const Parameter::Common& common) override;
+ RetCode setEngineArchitecture(const DynamicsProcessing::EngineArchitecture& cfg);
+ RetCode setPreEqChannelCfgs(const std::vector<DynamicsProcessing::ChannelConfig>& cfgs);
+ RetCode setPostEqChannelCfgs(const std::vector<DynamicsProcessing::ChannelConfig>& cfgs);
+ RetCode setMbcChannelCfgs(const std::vector<DynamicsProcessing::ChannelConfig>& cfgs);
+ RetCode setPreEqBandCfgs(const std::vector<DynamicsProcessing::EqBandConfig>& cfgs);
+ RetCode setPostEqBandCfgs(const std::vector<DynamicsProcessing::EqBandConfig>& cfgs);
+ RetCode setMbcBandCfgs(const std::vector<DynamicsProcessing::MbcBandConfig>& cfgs);
+ RetCode setLimiterCfgs(const std::vector<DynamicsProcessing::LimiterConfig>& cfgs);
+ RetCode setInputGainCfgs(const std::vector<DynamicsProcessing::InputGain>& cfgs);
+
+ // get params
+ DynamicsProcessing::EngineArchitecture getEngineArchitecture() { return mEngineSettings; }
+ std::vector<DynamicsProcessing::ChannelConfig> getPreEqChannelCfgs() { return mPreEqChCfgs; }
+ std::vector<DynamicsProcessing::ChannelConfig> getPostEqChannelCfgs() { return mPostEqChCfgs; }
+ std::vector<DynamicsProcessing::ChannelConfig> getMbcChannelCfgs() { return mMbcChCfgs; }
+ std::vector<DynamicsProcessing::EqBandConfig> getPreEqBandCfgs() { return mPreEqChBands; }
+ std::vector<DynamicsProcessing::EqBandConfig> getPostEqBandCfgs() { return mPostEqChBands; }
+ std::vector<DynamicsProcessing::MbcBandConfig> getMbcBandCfgs() { return mMbcChBands; }
+ std::vector<DynamicsProcessing::LimiterConfig> getLimiterCfgs() { return mLimiterCfgs; }
+ std::vector<DynamicsProcessing::InputGain> getInputGainCfgs();
+
+ private:
+ static constexpr int32_t kInvalidChannelId = -1;
+ size_t mChannelCount = 0;
+ DynamicsProcessing::EngineArchitecture mEngineSettings;
+ // Channel config vector with size of mChannelCount
+ std::vector<DynamicsProcessing::ChannelConfig> mPreEqChCfgs;
+ std::vector<DynamicsProcessing::ChannelConfig> mPostEqChCfgs;
+ std::vector<DynamicsProcessing::ChannelConfig> mMbcChCfgs;
+ std::vector<DynamicsProcessing::LimiterConfig> mLimiterCfgs;
+ std::vector<DynamicsProcessing::InputGain> mInputGainCfgs;
+ // Band config vector with size of mChannelCount * bandCount
+ std::vector<DynamicsProcessing::EqBandConfig> mPreEqChBands;
+ std::vector<DynamicsProcessing::EqBandConfig> mPostEqChBands;
+ std::vector<DynamicsProcessing::MbcBandConfig> mMbcChBands;
+
+ bool validateCutoffFrequency(float freq);
+ bool validateStageEnablement(const DynamicsProcessing::StageEnablement& enablement);
+ bool validateEngineConfig(const DynamicsProcessing::EngineArchitecture& engine);
+ bool validateEqBandConfig(const DynamicsProcessing::EqBandConfig& band, int maxChannel,
+ int maxBand,
+ const std::vector<DynamicsProcessing::ChannelConfig>& channelConfig);
+ bool validateMbcBandConfig(const DynamicsProcessing::MbcBandConfig& band, int maxChannel,
+ int maxBand,
+ const std::vector<DynamicsProcessing::ChannelConfig>& channelConfig);
+ bool validateLimiterConfig(const DynamicsProcessing::LimiterConfig& limiter, int maxChannel);
+ void resizeChannels();
+ void resizeBands();
+}; // DynamicsProcessingSwContext
class DynamicsProcessingSw final : public EffectImpl {
public:
@@ -60,7 +126,9 @@
private:
std::shared_ptr<DynamicsProcessingSwContext> mContext;
- /* parameters */
- DynamicsProcessing mSpecificParam;
-};
+ ndk::ScopedAStatus getParameterDynamicsProcessing(const DynamicsProcessing::Tag& tag,
+ Parameter::Specific* specific);
+
+}; // DynamicsProcessingSw
+
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp
index f6211c4..3c3b66f 100644
--- a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp
+++ b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp
@@ -90,8 +90,8 @@
auto tag = hgParam.getTag();
switch (tag) {
- case HapticGenerator::hapticScale: {
- RETURN_IF(mContext->setHgHapticScale(hgParam.get<HapticGenerator::hapticScale>()) !=
+ case HapticGenerator::hapticScales: {
+ RETURN_IF(mContext->setHgHapticScales(hgParam.get<HapticGenerator::hapticScales>()) !=
RetCode::SUCCESS,
EX_ILLEGAL_ARGUMENT, "HapticScaleNotSupported");
return ndk::ScopedAStatus::ok();
@@ -133,8 +133,8 @@
HapticGenerator hgParam;
switch (tag) {
- case HapticGenerator::hapticScale: {
- hgParam.set<HapticGenerator::hapticScale>(mContext->getHgHapticScale());
+ case HapticGenerator::hapticScales: {
+ hgParam.set<HapticGenerator::hapticScales>(mContext->getHgHapticScales());
break;
}
case HapticGenerator::vibratorInfo: {
@@ -183,4 +183,20 @@
return {STATUS_OK, samples, samples};
}
+RetCode HapticGeneratorSwContext::setHgHapticScales(
+ const std::vector<HapticGenerator::HapticScale>& hapticScales) {
+ // Assume any audio track ID is valid
+ for (auto& it : hapticScales) {
+ mHapticScales[it.id] = it;
+ }
+ return RetCode::SUCCESS;
+}
+
+std::vector<HapticGenerator::HapticScale> HapticGeneratorSwContext::getHgHapticScales() const {
+ std::vector<HapticGenerator::HapticScale> result;
+ std::transform(mHapticScales.begin(), mHapticScales.end(), std::back_inserter(result),
+ [](auto& scaleIt) { return scaleIt.second; });
+ return result;
+}
+
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h
index d9ec744..7159501 100644
--- a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h
+++ b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h
@@ -33,12 +33,8 @@
LOG(DEBUG) << __func__;
}
- RetCode setHgHapticScale(const HapticGenerator::HapticScale& hapticScale) {
- // All int values are valid for ID
- mHapticScale = hapticScale;
- return RetCode::SUCCESS;
- }
- HapticGenerator::HapticScale getHgHapticScale() const { return mHapticScale; }
+ RetCode setHgHapticScales(const std::vector<HapticGenerator::HapticScale>& hapticScales);
+ std::vector<HapticGenerator::HapticScale> getHgHapticScales() const;
RetCode setHgVibratorInformation(const HapticGenerator::VibratorInformation& vibratorInfo) {
// All float values are valid for resonantFrequencyHz, qFactor, maxAmplitude
@@ -54,7 +50,7 @@
static constexpr float DEFAULT_RESONANT_FREQUENCY = 150.0f;
static constexpr float DEFAULT_Q_FACTOR = 1.0f;
static constexpr float DEFAULT_MAX_AMPLITUDE = 0.0f;
- HapticGenerator::HapticScale mHapticScale = {0, HapticGenerator::VibratorScale::MUTE};
+ std::map<int /* trackID */, HapticGenerator::HapticScale> mHapticScales;
HapticGenerator::VibratorInformation mVibratorInformation = {
DEFAULT_RESONANT_FREQUENCY, DEFAULT_Q_FACTOR, DEFAULT_MAX_AMPLITUDE};
};
diff --git a/audio/aidl/default/include/core-impl/Bluetooth.h b/audio/aidl/default/include/core-impl/Bluetooth.h
new file mode 100644
index 0000000..f2e762d
--- /dev/null
+++ b/audio/aidl/default/include/core-impl/Bluetooth.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/audio/core/BnBluetooth.h>
+
+namespace aidl::android::hardware::audio::core {
+
+class Bluetooth : public BnBluetooth {
+ public:
+ Bluetooth();
+
+ private:
+ ndk::ScopedAStatus setScoConfig(const ScoConfig& in_config, ScoConfig* _aidl_return) override;
+ ndk::ScopedAStatus setHfpConfig(const HfpConfig& in_config, HfpConfig* _aidl_return) override;
+
+ ScoConfig mScoConfig;
+ HfpConfig mHfpConfig;
+};
+
+} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/Module.h b/audio/aidl/default/include/core-impl/Module.h
index faca61e..000a704 100644
--- a/audio/aidl/default/include/core-impl/Module.h
+++ b/audio/aidl/default/include/core-impl/Module.h
@@ -36,9 +36,17 @@
explicit Module(Type type) : mType(type) {}
private:
+ struct VendorDebug {
+ static const std::string kForceTransientBurstName;
+ static const std::string kForceSynchronousDrainName;
+ bool forceTransientBurst = false;
+ bool forceSynchronousDrain = false;
+ };
+
ndk::ScopedAStatus setModuleDebug(
const ::aidl::android::hardware::audio::core::ModuleDebug& in_debug) override;
ndk::ScopedAStatus getTelephony(std::shared_ptr<ITelephony>* _aidl_return) override;
+ ndk::ScopedAStatus getBluetooth(std::shared_ptr<IBluetooth>* _aidl_return) override;
ndk::ScopedAStatus connectExternalDevice(
const ::aidl::android::media::audio::common::AudioPort& in_templateIdAndAdditionalData,
::aidl::android::media::audio::common::AudioPort* _aidl_return) override;
@@ -127,10 +135,13 @@
const Type mType;
std::unique_ptr<internal::Configuration> mConfig;
ModuleDebug mDebug;
- // Since it is required to return the same instance of the ITelephony, even
- // if the client has released it on its side, we need to hold it via a strong pointer.
+ VendorDebug mVendorDebug;
+ // For the interfaces requiring to return the same instance, we need to hold them
+ // via a strong pointer. The binder token is retained for a call to 'setMinSchedulerPolicy'.
std::shared_ptr<ITelephony> mTelephony;
ndk::SpAIBinder mTelephonyBinder;
+ std::shared_ptr<IBluetooth> mBluetooth;
+ ndk::SpAIBinder mBluetoothBinder;
// ids of ports created at runtime via 'connectExternalDevice'.
std::set<int32_t> mConnectedDevicePorts;
Streams mStreams;
diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h
index 5abd4de..2cf5951 100644
--- a/audio/aidl/default/include/core-impl/Stream.h
+++ b/audio/aidl/default/include/core-impl/Stream.h
@@ -62,12 +62,21 @@
// Ensure that this value is not used by any of StreamDescriptor.State enums
static constexpr int32_t STATE_CLOSED = -1;
+ struct DebugParameters {
+ // An extra delay for transient states, in ms.
+ int transientStateDelayMs = 0;
+ // Force the "burst" command to move the SM to the TRANSFERRING state.
+ bool forceTransientBurst = false;
+ // Force the "drain" command to be synchronous, going directly to the IDLE state.
+ bool forceSynchronousDrain = false;
+ };
+
StreamContext() = default;
StreamContext(std::unique_ptr<CommandMQ> commandMQ, std::unique_ptr<ReplyMQ> replyMQ,
const ::aidl::android::media::audio::common::AudioFormatDescription& format,
const ::aidl::android::media::audio::common::AudioChannelLayout& channelLayout,
std::unique_ptr<DataMQ> dataMQ, std::shared_ptr<IStreamCallback> asyncCallback,
- int transientStateDelayMs)
+ DebugParameters debugParameters)
: mCommandMQ(std::move(commandMQ)),
mInternalCommandCookie(std::rand()),
mReplyMQ(std::move(replyMQ)),
@@ -75,7 +84,7 @@
mChannelLayout(channelLayout),
mDataMQ(std::move(dataMQ)),
mAsyncCallback(asyncCallback),
- mTransientStateDelayMs(transientStateDelayMs) {}
+ mDebugParameters(debugParameters) {}
StreamContext(StreamContext&& other)
: mCommandMQ(std::move(other.mCommandMQ)),
mInternalCommandCookie(other.mInternalCommandCookie),
@@ -83,8 +92,8 @@
mFormat(other.mFormat),
mChannelLayout(other.mChannelLayout),
mDataMQ(std::move(other.mDataMQ)),
- mAsyncCallback(other.mAsyncCallback),
- mTransientStateDelayMs(other.mTransientStateDelayMs) {}
+ mAsyncCallback(std::move(other.mAsyncCallback)),
+ mDebugParameters(std::move(other.mDebugParameters)) {}
StreamContext& operator=(StreamContext&& other) {
mCommandMQ = std::move(other.mCommandMQ);
mInternalCommandCookie = other.mInternalCommandCookie;
@@ -92,8 +101,8 @@
mFormat = std::move(other.mFormat);
mChannelLayout = std::move(other.mChannelLayout);
mDataMQ = std::move(other.mDataMQ);
- mAsyncCallback = other.mAsyncCallback;
- mTransientStateDelayMs = other.mTransientStateDelayMs;
+ mAsyncCallback = std::move(other.mAsyncCallback);
+ mDebugParameters = std::move(other.mDebugParameters);
return *this;
}
@@ -107,10 +116,12 @@
::aidl::android::media::audio::common::AudioFormatDescription getFormat() const {
return mFormat;
}
+ bool getForceTransientBurst() const { return mDebugParameters.forceTransientBurst; }
+ bool getForceSynchronousDrain() const { return mDebugParameters.forceSynchronousDrain; }
size_t getFrameSize() const;
int getInternalCommandCookie() const { return mInternalCommandCookie; }
ReplyMQ* getReplyMQ() const { return mReplyMQ.get(); }
- int getTransientStateDelayMs() const { return mTransientStateDelayMs; }
+ int getTransientStateDelayMs() const { return mDebugParameters.transientStateDelayMs; }
bool isValid() const;
void reset();
@@ -122,7 +133,7 @@
::aidl::android::media::audio::common::AudioChannelLayout mChannelLayout;
std::unique_ptr<DataMQ> mDataMQ;
std::shared_ptr<IStreamCallback> mAsyncCallback;
- int mTransientStateDelayMs;
+ DebugParameters mDebugParameters;
};
class StreamWorkerCommonLogic : public ::android::hardware::audio::common::StreamLogic {
@@ -141,7 +152,9 @@
mReplyMQ(context.getReplyMQ()),
mDataMQ(context.getDataMQ()),
mAsyncCallback(context.getAsyncCallback()),
- mTransientStateDelayMs(context.getTransientStateDelayMs()) {}
+ mTransientStateDelayMs(context.getTransientStateDelayMs()),
+ mForceTransientBurst(context.getForceTransientBurst()),
+ mForceSynchronousDrain(context.getForceSynchronousDrain()) {}
std::string init() override;
void populateReply(StreamDescriptor::Reply* reply, bool isConnected) const;
void populateReplyWrongState(StreamDescriptor::Reply* reply,
@@ -164,6 +177,8 @@
std::shared_ptr<IStreamCallback> mAsyncCallback;
const std::chrono::duration<int, std::milli> mTransientStateDelayMs;
std::chrono::time_point<std::chrono::steady_clock> mTransientStateStart;
+ const bool mForceTransientBurst;
+ const bool mForceSynchronousDrain;
// 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;
diff --git a/audio/aidl/default/include/core-impl/Telephony.h b/audio/aidl/default/include/core-impl/Telephony.h
index 597f3d6..0936172 100644
--- a/audio/aidl/default/include/core-impl/Telephony.h
+++ b/audio/aidl/default/include/core-impl/Telephony.h
@@ -23,12 +23,18 @@
namespace aidl::android::hardware::audio::core {
class Telephony : public BnTelephony {
+ public:
+ Telephony();
+
private:
ndk::ScopedAStatus getSupportedAudioModes(std::vector<AudioMode>* _aidl_return) override;
ndk::ScopedAStatus switchAudioMode(AudioMode in_mode) override;
+ ndk::ScopedAStatus setTelecomConfig(const TelecomConfig& in_config,
+ TelecomConfig* _aidl_return) override;
const std::vector<AudioMode> mSupportedAudioModes = {::ndk::enum_range<AudioMode>().begin(),
::ndk::enum_range<AudioMode>().end()};
+ TelecomConfig mTelecomConfig;
};
} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/effect-impl/EffectContext.h b/audio/aidl/default/include/effect-impl/EffectContext.h
index 1f39db0..a3e7ff2 100644
--- a/audio/aidl/default/include/effect-impl/EffectContext.h
+++ b/audio/aidl/default/include/effect-impl/EffectContext.h
@@ -119,11 +119,11 @@
virtual RetCode setCommon(const Parameter::Common& common) {
mCommon = common;
- LOG(ERROR) << __func__ << mCommon.toString();
+ LOG(INFO) << __func__ << mCommon.toString();
return RetCode::SUCCESS;
}
virtual Parameter::Common getCommon() {
- LOG(ERROR) << __func__ << mCommon.toString();
+ LOG(INFO) << __func__ << mCommon.toString();
return mCommon;
}
diff --git a/audio/aidl/default/include/effect-impl/EffectTypes.h b/audio/aidl/default/include/effect-impl/EffectTypes.h
index 58c8672..b100a2e 100644
--- a/audio/aidl/default/include/effect-impl/EffectTypes.h
+++ b/audio/aidl/default/include/effect-impl/EffectTypes.h
@@ -98,12 +98,13 @@
} \
} while (0)
-#define RETURN_VALUE_IF(expr, ret, log) \
- do { \
- if (expr) { \
- LOG(ERROR) << __func__ << ":" << __LINE__ << " return with expr " << #expr << (log); \
- return ret; \
- } \
+#define RETURN_VALUE_IF(expr, ret, log) \
+ do { \
+ if (expr) { \
+ LOG(ERROR) << __func__ << ":" << __LINE__ << " return with expr \"" << #expr \
+ << "\":" << (log); \
+ return ret; \
+ } \
} while (0)
#define RETURN_IF_BINDER_EXCEPTION(functor) \
diff --git a/audio/aidl/default/include/effect-impl/EffectUUID.h b/audio/aidl/default/include/effect-impl/EffectUUID.h
index 6eec29e..1a60829 100644
--- a/audio/aidl/default/include/effect-impl/EffectUUID.h
+++ b/audio/aidl/default/include/effect-impl/EffectUUID.h
@@ -135,6 +135,12 @@
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// e0e6539b-1781-7261-676f-6d7573696340
+static const AudioUuid kDynamicsProcessingImplUUID = {static_cast<int32_t>(0xe0e6539b),
+ 0x1781,
+ 0x7261,
+ 0x676f,
+ {0x6d, 0x75, 0x73, 0x69, 0x63, 0x40}};
// 1411e6d6-aecd-4021-a1cf-a6aceb0d71e5
static const AudioUuid kHapticGeneratorTypeUUID = {static_cast<int32_t>(0x1411e6d6),
0xaecd,
diff --git a/audio/aidl/default/visualizer/VisualizerSw.cpp b/audio/aidl/default/visualizer/VisualizerSw.cpp
index 735180e..614988c 100644
--- a/audio/aidl/default/visualizer/VisualizerSw.cpp
+++ b/audio/aidl/default/visualizer/VisualizerSw.cpp
@@ -241,4 +241,37 @@
return {STATUS_OK, samples, samples};
}
+RetCode VisualizerSwContext::setVsCaptureSize(int captureSize) {
+ if (captureSize < VisualizerSw::kCapability.captureSampleRange.min ||
+ captureSize > VisualizerSw::kCapability.captureSampleRange.max) {
+ LOG(ERROR) << __func__ << " invalid captureSize " << captureSize;
+ return RetCode::ERROR_ILLEGAL_PARAMETER;
+ }
+ // TODO : Add implementation to apply new captureSize
+ mCaptureSize = captureSize;
+ return RetCode::SUCCESS;
+}
+
+RetCode VisualizerSwContext::setVsScalingMode(Visualizer::ScalingMode scalingMode) {
+ // TODO : Add implementation to apply new scalingMode
+ mScalingMode = scalingMode;
+ return RetCode::SUCCESS;
+}
+
+RetCode VisualizerSwContext::setVsMeasurementMode(Visualizer::MeasurementMode measurementMode) {
+ // TODO : Add implementation to apply new measurementMode
+ mMeasurementMode = measurementMode;
+ return RetCode::SUCCESS;
+}
+
+RetCode VisualizerSwContext::setVsLatency(int latency) {
+ if (latency < 0 || latency > VisualizerSw::kCapability.maxLatencyMs) {
+ LOG(ERROR) << __func__ << " invalid latency " << latency;
+ return RetCode::ERROR_ILLEGAL_PARAMETER;
+ }
+ // TODO : Add implementation to modify latency
+ mLatency = latency;
+ return RetCode::SUCCESS;
+}
+
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/visualizer/VisualizerSw.h b/audio/aidl/default/visualizer/VisualizerSw.h
index 3c9e6d2..e9d46d7 100644
--- a/audio/aidl/default/visualizer/VisualizerSw.h
+++ b/audio/aidl/default/visualizer/VisualizerSw.h
@@ -38,40 +38,16 @@
fill(mCaptureSampleBuffer.begin(), mCaptureSampleBuffer.end(), 0x80);
}
- RetCode setVsCaptureSize(int captureSize) {
- if (captureSize < kMinCaptureSize || captureSize > kMaxCaptureSize) {
- LOG(ERROR) << __func__ << " invalid captureSize " << captureSize;
- return RetCode::ERROR_ILLEGAL_PARAMETER;
- }
- // TODO : Add implementation to apply new captureSize
- mCaptureSize = captureSize;
- return RetCode::SUCCESS;
- }
+ RetCode setVsCaptureSize(int captureSize);
int getVsCaptureSize() const { return mCaptureSize; }
- RetCode setVsScalingMode(Visualizer::ScalingMode scalingMode) {
- // TODO : Add implementation to apply new scalingMode
- mScalingMode = scalingMode;
- return RetCode::SUCCESS;
- }
+ RetCode setVsScalingMode(Visualizer::ScalingMode scalingMode);
Visualizer::ScalingMode getVsScalingMode() const { return mScalingMode; }
- RetCode setVsMeasurementMode(Visualizer::MeasurementMode measurementMode) {
- // TODO : Add implementation to apply new measurementMode
- mMeasurementMode = measurementMode;
- return RetCode::SUCCESS;
- }
+ RetCode setVsMeasurementMode(Visualizer::MeasurementMode measurementMode);
Visualizer::MeasurementMode getVsMeasurementMode() const { return mMeasurementMode; }
- RetCode setVsLatency(int latency) {
- if (latency < 0 || latency > kMaxLatencyMs) {
- LOG(ERROR) << __func__ << " invalid latency " << latency;
- return RetCode::ERROR_ILLEGAL_PARAMETER;
- }
- // TODO : Add implementation to modify latency
- mLatency = latency;
- return RetCode::SUCCESS;
- }
+ RetCode setVsLatency(int latency);
Visualizer::GetOnlyParameters::Measurement getVsMeasurement() const { return mMeasurement; }
std::vector<uint8_t> getVsCaptureSampleBuffer() const { return mCaptureSampleBuffer; }
diff --git a/audio/aidl/vts/Android.bp b/audio/aidl/vts/Android.bp
index becdf1b..f9d12dd 100644
--- a/audio/aidl/vts/Android.bp
+++ b/audio/aidl/vts/Android.bp
@@ -81,6 +81,12 @@
}
cc_test {
+ name: "VtsHalDynamicsProcessingTargetTest",
+ defaults: ["VtsHalAudioTargetTestDefaults"],
+ srcs: ["VtsHalDynamicsProcessingTest.cpp"],
+}
+
+cc_test {
name: "VtsHalEnvironmentalReverbTargetTest",
defaults: ["VtsHalAudioTargetTestDefaults"],
srcs: ["VtsHalEnvironmentalReverbTargetTest.cpp"],
diff --git a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
index 50a93ce..d4f2811 100644
--- a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
@@ -18,6 +18,7 @@
#include <chrono>
#include <cmath>
#include <condition_variable>
+#include <forward_list>
#include <limits>
#include <memory>
#include <mutex>
@@ -56,6 +57,7 @@
using aidl::android::hardware::audio::core::AudioMode;
using aidl::android::hardware::audio::core::AudioPatch;
using aidl::android::hardware::audio::core::AudioRoute;
+using aidl::android::hardware::audio::core::IBluetooth;
using aidl::android::hardware::audio::core::IModule;
using aidl::android::hardware::audio::core::IStreamCommon;
using aidl::android::hardware::audio::core::IStreamIn;
@@ -84,6 +86,9 @@
using aidl::android::media::audio::common::AudioPortExt;
using aidl::android::media::audio::common::AudioSource;
using aidl::android::media::audio::common::AudioUsage;
+using aidl::android::media::audio::common::Boolean;
+using aidl::android::media::audio::common::Float;
+using aidl::android::media::audio::common::Int;
using aidl::android::media::audio::common::Void;
using android::hardware::audio::common::getChannelCount;
using android::hardware::audio::common::isBitPositionFlagSet;
@@ -123,7 +128,7 @@
return WithDebugFlags(parent.mFlags);
}
- WithDebugFlags() {}
+ WithDebugFlags() = default;
explicit WithDebugFlags(const ModuleDebug& initial) : mInitial(initial), mFlags(initial) {}
WithDebugFlags(const WithDebugFlags&) = delete;
WithDebugFlags& operator=(const WithDebugFlags&) = delete;
@@ -132,7 +137,10 @@
EXPECT_IS_OK(mModule->setModuleDebug(mInitial));
}
}
- void SetUp(IModule* module) { ASSERT_IS_OK(module->setModuleDebug(mFlags)); }
+ void SetUp(IModule* module) {
+ ASSERT_IS_OK(module->setModuleDebug(mFlags));
+ mModule = module;
+ }
ModuleDebug& flags() { return mFlags; }
private:
@@ -141,13 +149,65 @@
IModule* mModule = nullptr;
};
+template <typename T>
+class WithModuleParameter {
+ public:
+ WithModuleParameter(const std::string parameterId, const T& value)
+ : mParameterId(parameterId), mValue(value) {}
+ WithModuleParameter(const WithModuleParameter&) = delete;
+ WithModuleParameter& operator=(const WithModuleParameter&) = delete;
+ ~WithModuleParameter() {
+ if (mModule != nullptr) {
+ VendorParameter parameter{.id = mParameterId};
+ parameter.ext.setParcelable(mInitial);
+ EXPECT_IS_OK(mModule->setVendorParameters({parameter}, false));
+ }
+ }
+ ScopedAStatus SetUpNoChecks(IModule* module, bool failureExpected) {
+ std::vector<VendorParameter> parameters;
+ ScopedAStatus result = module->getVendorParameters({mParameterId}, ¶meters);
+ if (result.isOk() && parameters.size() == 1) {
+ std::optional<T> maybeInitial;
+ binder_status_t status = parameters[0].ext.getParcelable(&maybeInitial);
+ if (status == STATUS_OK && maybeInitial.has_value()) {
+ mInitial = maybeInitial.value();
+ VendorParameter parameter{.id = mParameterId};
+ parameter.ext.setParcelable(mValue);
+ result = module->setVendorParameters({parameter}, false);
+ if (result.isOk()) {
+ LOG(INFO) << __func__ << ": overriding parameter \"" << mParameterId
+ << "\" with " << mValue.toString()
+ << ", old value: " << mInitial.toString();
+ mModule = module;
+ }
+ } else {
+ LOG(ERROR) << __func__ << ": error while retrieving the value of \"" << mParameterId
+ << "\"";
+ return ScopedAStatus::fromStatus(status);
+ }
+ }
+ if (!result.isOk()) {
+ LOG(failureExpected ? INFO : ERROR)
+ << __func__ << ": can not override vendor parameter \"" << mParameterId << "\""
+ << result;
+ }
+ return result;
+ }
+
+ private:
+ const std::string mParameterId;
+ const T mValue;
+ IModule* mModule = nullptr;
+ T mInitial;
+};
+
// For consistency, WithAudioPortConfig can start both with a non-existent
// port config, and with an existing one. Existence is determined by the
// id of the provided config. If it's not 0, then WithAudioPortConfig is
// essentially a no-op wrapper.
class WithAudioPortConfig {
public:
- WithAudioPortConfig() {}
+ WithAudioPortConfig() = default;
explicit WithAudioPortConfig(const AudioPortConfig& config) : mInitialConfig(config) {}
WithAudioPortConfig(const WithAudioPortConfig&) = delete;
WithAudioPortConfig& operator=(const WithAudioPortConfig&) = delete;
@@ -299,26 +359,31 @@
void SetUpImpl(const std::string& moduleName) {
ASSERT_NO_FATAL_FAILURE(ConnectToService(moduleName));
- debug.flags().simulateDeviceConnections = true;
- ASSERT_NO_FATAL_FAILURE(debug.SetUp(module.get()));
}
- void TearDownImpl() {
- if (module != nullptr) {
- EXPECT_IS_OK(module->setModuleDebug(ModuleDebug{}));
- }
- }
+ void TearDownImpl() { debug.reset(); }
void ConnectToService(const std::string& moduleName) {
+ ASSERT_EQ(module, nullptr);
+ ASSERT_EQ(debug, nullptr);
module = IModule::fromBinder(binderUtil.connectToService(moduleName));
ASSERT_NE(module, nullptr);
+ ASSERT_NO_FATAL_FAILURE(SetUpDebug());
}
void RestartService() {
ASSERT_NE(module, nullptr);
moduleConfig.reset();
+ debug.reset();
module = IModule::fromBinder(binderUtil.restartService());
ASSERT_NE(module, nullptr);
+ ASSERT_NO_FATAL_FAILURE(SetUpDebug());
+ }
+
+ void SetUpDebug() {
+ debug.reset(new WithDebugFlags());
+ debug->flags().simulateDeviceConnections = true;
+ ASSERT_NO_FATAL_FAILURE(debug->SetUp(module.get()));
}
void ApplyEveryConfig(const std::vector<AudioPortConfig>& configs) {
@@ -387,7 +452,7 @@
std::shared_ptr<IModule> module;
std::unique_ptr<ModuleConfig> moduleConfig;
AudioHalBinderServiceUtil binderUtil;
- WithDebugFlags debug;
+ std::unique_ptr<WithDebugFlags> debug;
};
class AudioCoreModule : public AudioCoreModuleBase, public testing::TestWithParam<std::string> {
@@ -462,6 +527,7 @@
size_t getBufferSizeFrames() const { return mBufferSizeFrames; }
CommandMQ* getCommandMQ() const { return mCommandMQ.get(); }
DataMQ* getDataMQ() const { return mDataMQ.get(); }
+ size_t getFrameSizeBytes() const { return mFrameSizeBytes; }
ReplyMQ* getReplyMQ() const { return mReplyMQ.get(); }
private:
@@ -501,10 +567,48 @@
return std::to_string(static_cast<int32_t>(event));
}
+// Note: we use a reference wrapper, not a pointer, because methods of std::*list
+// return references to inserted elements. This way, we can put a returned reference
+// into the children vector without any type conversions, and this makes DAG creation
+// code more clear.
+template <typename T>
+struct DagNode : public std::pair<T, std::vector<std::reference_wrapper<DagNode<T>>>> {
+ using Children = std::vector<std::reference_wrapper<DagNode>>;
+ DagNode(const T& t, const Children& c) : std::pair<T, Children>(t, c) {}
+ DagNode(T&& t, Children&& c) : std::pair<T, Children>(std::move(t), std::move(c)) {}
+ const T& datum() const { return this->first; }
+ Children& children() { return this->second; }
+ const Children& children() const { return this->second; }
+};
+// Since DagNodes do contain references to next nodes, node links provided
+// by the list are not used. Thus, the order of the nodes in the list is not
+// important, except that the starting node must be at the front of the list,
+// which means, it must always be added last.
+template <typename T>
+struct Dag : public std::forward_list<DagNode<T>> {
+ Dag() = default;
+ // We prohibit copying and moving Dag instances because implementing that
+ // is not trivial due to references between nodes.
+ Dag(const Dag&) = delete;
+ Dag(Dag&&) = delete;
+ Dag& operator=(const Dag&) = delete;
+ Dag& operator=(Dag&&) = delete;
+};
+
// Transition to the next state happens either due to a command from the client,
// or after an event received from the server.
using TransitionTrigger = std::variant<StreamDescriptor::Command, StreamEventReceiver::Event>;
-using StateTransition = std::pair<TransitionTrigger, StreamDescriptor::State>;
+std::string toString(const TransitionTrigger& trigger) {
+ if (std::holds_alternative<StreamDescriptor::Command>(trigger)) {
+ return std::string("'")
+ .append(toString(std::get<StreamDescriptor::Command>(trigger).getTag()))
+ .append("' command");
+ }
+ return std::string("'")
+ .append(toString(std::get<StreamEventReceiver::Event>(trigger)))
+ .append("' event");
+}
+
struct StateSequence {
virtual ~StateSequence() = default;
virtual void rewind() = 0;
@@ -514,6 +618,10 @@
virtual void advance(StreamDescriptor::State state) = 0;
};
+// Defines the current state and the trigger to transfer to the next one,
+// thus "state" is the "from" state.
+using StateTransitionFrom = std::pair<StreamDescriptor::State, TransitionTrigger>;
+
static const StreamDescriptor::Command kGetStatusCommand =
StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::getStatus>(Void{});
static const StreamDescriptor::Command kStartCommand =
@@ -539,66 +647,65 @@
StreamEventReceiver::Event::TransferReady;
static const StreamEventReceiver::Event kDrainReadyEvent = StreamEventReceiver::Event::DrainReady;
-// Handle possible bifurcations:
-// - on burst and on start: 'TRANSFERRING' -> {'ACTIVE', 'TRANSFERRING'}
-// - on pause: 'TRANSFER_PAUSED' -> {'PAUSED', 'TRANSFER_PAUSED'}
-// It is assumed that the 'steps' provided on the construction contain the sequence
-// for the async case, which gets corrected in the case when the HAL decided to do
-// a synchronous transfer.
-class SmartStateSequence : public StateSequence {
+struct StateDag : public Dag<StateTransitionFrom> {
+ using Node = StateDag::reference;
+ using NextStates = StateDag::value_type::Children;
+
+ template <typename... Next>
+ Node makeNode(StreamDescriptor::State s, TransitionTrigger t, Next&&... next) {
+ return emplace_front(std::make_pair(s, t), NextStates{std::forward<Next>(next)...});
+ }
+ Node makeNodes(const std::vector<StateTransitionFrom>& v, Node last) {
+ auto helper = [&](auto i, auto&& h) -> Node {
+ if (i == v.end()) return last;
+ return makeNode(i->first, i->second, h(++i, h));
+ };
+ return helper(v.begin(), helper);
+ }
+ Node makeNodes(const std::vector<StateTransitionFrom>& v, StreamDescriptor::State f) {
+ return makeNodes(v, makeFinalNode(f));
+ }
+ Node makeFinalNode(StreamDescriptor::State s) {
+ // The actual command used here is irrelevant. Since it's the final node
+ // in the test sequence, no commands sent after reaching it.
+ return emplace_front(std::make_pair(s, kGetStatusCommand), NextStates{});
+ }
+};
+
+class StateSequenceFollower : public StateSequence {
public:
- explicit SmartStateSequence(const std::vector<StateTransition>& steps) : mSteps(steps) {}
- explicit SmartStateSequence(std::vector<StateTransition>&& steps) : mSteps(std::move(steps)) {}
- void rewind() override { mCurrentStep = 0; }
- bool done() const override { return mCurrentStep >= mSteps.size(); }
- TransitionTrigger getTrigger() override { return mSteps[mCurrentStep].first; }
+ explicit StateSequenceFollower(std::unique_ptr<StateDag> steps)
+ : mSteps(std::move(steps)), mCurrent(mSteps->front()) {}
+ void rewind() override { mCurrent = mSteps->front(); }
+ bool done() const override { return current().children().empty(); }
+ TransitionTrigger getTrigger() override { return current().datum().second; }
std::set<StreamDescriptor::State> getExpectedStates() override {
- std::set<StreamDescriptor::State> result = {getState()};
- if (isBurstBifurcation() || isStartBifurcation()) {
- result.insert(StreamDescriptor::State::ACTIVE);
- } else if (isPauseBifurcation()) {
- result.insert(StreamDescriptor::State::PAUSED);
- }
+ std::set<StreamDescriptor::State> result;
+ std::transform(current().children().cbegin(), current().children().cend(),
+ std::inserter(result, result.begin()),
+ [](const auto& node) { return node.get().datum().first; });
+ LOG(DEBUG) << __func__ << ": " << ::android::internal::ToString(result);
return result;
}
void advance(StreamDescriptor::State state) override {
- if (isBurstBifurcation() && state == StreamDescriptor::State::ACTIVE &&
- mCurrentStep + 1 < mSteps.size() &&
- mSteps[mCurrentStep + 1].first == TransitionTrigger{kTransferReadyEvent}) {
- mCurrentStep++;
+ if (auto it = std::find_if(
+ current().children().cbegin(), current().children().cend(),
+ [&](const auto& node) { return node.get().datum().first == state; });
+ it != current().children().cend()) {
+ LOG(DEBUG) << __func__ << ": " << toString(mCurrent.get().datum().first) << " -> "
+ << toString(it->get().datum().first);
+ mCurrent = *it;
+ } else {
+ LOG(FATAL) << __func__ << ": state " << toString(state) << " is unexpected";
}
- mCurrentStep++;
}
private:
- StreamDescriptor::State getState() const { return mSteps[mCurrentStep].second; }
- bool isBurstBifurcation() {
- return getTrigger() == TransitionTrigger{kBurstCommand} &&
- getState() == StreamDescriptor::State::TRANSFERRING;
- }
- bool isPauseBifurcation() {
- return getTrigger() == TransitionTrigger{kPauseCommand} &&
- getState() == StreamDescriptor::State::TRANSFER_PAUSED;
- }
- bool isStartBifurcation() {
- return getTrigger() == TransitionTrigger{kStartCommand} &&
- getState() == StreamDescriptor::State::TRANSFERRING;
- }
- const std::vector<StateTransition> mSteps;
- size_t mCurrentStep = 0;
+ StateDag::const_reference current() const { return mCurrent.get(); }
+ std::unique_ptr<StateDag> mSteps;
+ std::reference_wrapper<StateDag::value_type> mCurrent;
};
-std::string toString(const TransitionTrigger& trigger) {
- if (std::holds_alternative<StreamDescriptor::Command>(trigger)) {
- return std::string("'")
- .append(toString(std::get<StreamDescriptor::Command>(trigger).getTag()))
- .append("' command");
- }
- return std::string("'")
- .append(toString(std::get<StreamEventReceiver::Event>(trigger)))
- .append("' event");
-}
-
struct StreamLogicDriver {
virtual ~StreamLogicDriver() = default;
// Return 'true' to stop the worker.
@@ -924,7 +1031,7 @@
return common->close();
}
- WithStream() {}
+ WithStream() = default;
explicit WithStream(const AudioPortConfig& portConfig) : mPortConfig(portConfig) {}
WithStream(const WithStream&) = delete;
WithStream& operator=(const WithStream&) = delete;
@@ -1029,7 +1136,7 @@
class WithAudioPatch {
public:
- WithAudioPatch() {}
+ WithAudioPatch() = default;
WithAudioPatch(const AudioPortConfig& srcPortConfig, const AudioPortConfig& sinkPortConfig)
: mSrcPortConfig(srcPortConfig), mSinkPortConfig(sinkPortConfig) {}
WithAudioPatch(bool sinkIsCfg1, const AudioPortConfig& portConfig1,
@@ -1470,7 +1577,7 @@
GTEST_SKIP() << "No external devices in the module.";
}
AudioPort ignored;
- WithDebugFlags doNotSimulateConnections = WithDebugFlags::createNested(debug);
+ WithDebugFlags doNotSimulateConnections = WithDebugFlags::createNested(*debug);
doNotSimulateConnections.flags().simulateDeviceConnections = false;
ASSERT_NO_FATAL_FAILURE(doNotSimulateConnections.SetUp(module.get()));
for (const auto& port : ports) {
@@ -1490,7 +1597,7 @@
}
WithDevicePortConnectedState portConnected(*ports.begin(), GenerateUniqueDeviceAddress());
ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
- ModuleDebug midwayDebugChange = debug.flags();
+ ModuleDebug midwayDebugChange = debug->flags();
midwayDebugChange.simulateDeviceConnections = false;
EXPECT_STATUS(EX_ILLEGAL_STATE, module->setModuleDebug(midwayDebugChange))
<< "when trying to disable connections simulation while having a connected device";
@@ -1775,6 +1882,89 @@
}
}
+class AudioCoreBluetooth : public AudioCoreModuleBase, public testing::TestWithParam<std::string> {
+ public:
+ void SetUp() override {
+ ASSERT_NO_FATAL_FAILURE(SetUpImpl(GetParam()));
+ ASSERT_IS_OK(module->getBluetooth(&bluetooth));
+ }
+
+ void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownImpl()); }
+
+ std::shared_ptr<IBluetooth> bluetooth;
+};
+
+TEST_P(AudioCoreBluetooth, SameInstance) {
+ if (bluetooth == nullptr) {
+ GTEST_SKIP() << "Bluetooth is not supported";
+ }
+ std::shared_ptr<IBluetooth> bluetooth2;
+ EXPECT_IS_OK(module->getBluetooth(&bluetooth2));
+ ASSERT_NE(nullptr, bluetooth2.get());
+ EXPECT_EQ(bluetooth->asBinder(), bluetooth2->asBinder())
+ << "getBluetooth must return the same interface instance across invocations";
+}
+
+TEST_P(AudioCoreBluetooth, ScoConfig) {
+ static const auto kStatuses = {EX_NONE, EX_UNSUPPORTED_OPERATION};
+ if (bluetooth == nullptr) {
+ GTEST_SKIP() << "Bluetooth is not supported";
+ }
+ ndk::ScopedAStatus status;
+ IBluetooth::ScoConfig scoConfig;
+ ASSERT_STATUS(kStatuses, status = bluetooth->setScoConfig({}, &scoConfig));
+ if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+ GTEST_SKIP() << "BT SCO is not supported";
+ }
+ EXPECT_TRUE(scoConfig.isEnabled.has_value());
+ EXPECT_TRUE(scoConfig.isNrecEnabled.has_value());
+ EXPECT_NE(IBluetooth::ScoConfig::Mode::UNSPECIFIED, scoConfig.mode);
+ IBluetooth::ScoConfig scoConfig2;
+ ASSERT_IS_OK(bluetooth->setScoConfig(scoConfig, &scoConfig2));
+ EXPECT_EQ(scoConfig, scoConfig2);
+}
+
+TEST_P(AudioCoreBluetooth, HfpConfig) {
+ static const auto kStatuses = {EX_NONE, EX_UNSUPPORTED_OPERATION};
+ if (bluetooth == nullptr) {
+ GTEST_SKIP() << "Bluetooth is not supported";
+ }
+ ndk::ScopedAStatus status;
+ IBluetooth::HfpConfig hfpConfig;
+ ASSERT_STATUS(kStatuses, status = bluetooth->setHfpConfig({}, &hfpConfig));
+ if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+ GTEST_SKIP() << "BT HFP is not supported";
+ }
+ EXPECT_TRUE(hfpConfig.isEnabled.has_value());
+ EXPECT_TRUE(hfpConfig.sampleRate.has_value());
+ EXPECT_TRUE(hfpConfig.volume.has_value());
+ IBluetooth::HfpConfig hfpConfig2;
+ ASSERT_IS_OK(bluetooth->setHfpConfig(hfpConfig, &hfpConfig2));
+ EXPECT_EQ(hfpConfig, hfpConfig2);
+}
+
+TEST_P(AudioCoreBluetooth, HfpConfigInvalid) {
+ static const auto kStatuses = {EX_NONE, EX_UNSUPPORTED_OPERATION};
+ if (bluetooth == nullptr) {
+ GTEST_SKIP() << "Bluetooth is not supported";
+ }
+ ndk::ScopedAStatus status;
+ IBluetooth::HfpConfig hfpConfig;
+ ASSERT_STATUS(kStatuses, status = bluetooth->setHfpConfig({}, &hfpConfig));
+ if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+ GTEST_SKIP() << "BT HFP is not supported";
+ }
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
+ bluetooth->setHfpConfig({.sampleRate = Int{-1}}, &hfpConfig));
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, bluetooth->setHfpConfig({.sampleRate = Int{0}}, &hfpConfig));
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
+ bluetooth->setHfpConfig({.volume = Float{IBluetooth::HfpConfig::VOLUME_MIN - 1}},
+ &hfpConfig));
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
+ bluetooth->setHfpConfig({.volume = Float{IBluetooth::HfpConfig::VOLUME_MAX + 1}},
+ &hfpConfig));
+}
+
class AudioCoreTelephony : public AudioCoreModuleBase, public testing::TestWithParam<std::string> {
public:
void SetUp() override {
@@ -1787,6 +1977,17 @@
std::shared_ptr<ITelephony> telephony;
};
+TEST_P(AudioCoreTelephony, SameInstance) {
+ if (telephony == nullptr) {
+ GTEST_SKIP() << "Telephony is not supported";
+ }
+ std::shared_ptr<ITelephony> telephony2;
+ EXPECT_IS_OK(module->getTelephony(&telephony2));
+ ASSERT_NE(nullptr, telephony2.get());
+ EXPECT_EQ(telephony->asBinder(), telephony2->asBinder())
+ << "getTelephony must return the same interface instance across invocations";
+}
+
TEST_P(AudioCoreTelephony, GetSupportedAudioModes) {
if (telephony == nullptr) {
GTEST_SKIP() << "Telephony is not supported";
@@ -1828,6 +2029,46 @@
}
}
+TEST_P(AudioCoreTelephony, TelecomConfig) {
+ static const auto kStatuses = {EX_NONE, EX_UNSUPPORTED_OPERATION};
+ if (telephony == nullptr) {
+ GTEST_SKIP() << "Telephony is not supported";
+ }
+ ndk::ScopedAStatus status;
+ ITelephony::TelecomConfig telecomConfig;
+ ASSERT_STATUS(kStatuses, status = telephony->setTelecomConfig({}, &telecomConfig));
+ if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+ GTEST_SKIP() << "Telecom is not supported";
+ }
+ EXPECT_TRUE(telecomConfig.voiceVolume.has_value());
+ EXPECT_NE(ITelephony::TelecomConfig::TtyMode::UNSPECIFIED, telecomConfig.ttyMode);
+ EXPECT_TRUE(telecomConfig.isHacEnabled.has_value());
+ ITelephony::TelecomConfig telecomConfig2;
+ ASSERT_IS_OK(telephony->setTelecomConfig(telecomConfig, &telecomConfig2));
+ EXPECT_EQ(telecomConfig, telecomConfig2);
+}
+
+TEST_P(AudioCoreTelephony, TelecomConfigInvalid) {
+ static const auto kStatuses = {EX_NONE, EX_UNSUPPORTED_OPERATION};
+ if (telephony == nullptr) {
+ GTEST_SKIP() << "Telephony is not supported";
+ }
+ ndk::ScopedAStatus status;
+ ITelephony::TelecomConfig telecomConfig;
+ ASSERT_STATUS(kStatuses, status = telephony->setTelecomConfig({}, &telecomConfig));
+ if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+ GTEST_SKIP() << "Telecom is not supported";
+ }
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
+ telephony->setTelecomConfig(
+ {.voiceVolume = Float{ITelephony::TelecomConfig::VOICE_VOLUME_MIN - 1}},
+ &telecomConfig));
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
+ telephony->setTelecomConfig(
+ {.voiceVolume = Float{ITelephony::TelecomConfig::VOICE_VOLUME_MAX + 1}},
+ &telecomConfig));
+}
+
using CommandSequence = std::vector<StreamDescriptor::Command>;
class StreamLogicDriverInvalidCommand : public StreamLogicDriver {
public:
@@ -2579,8 +2820,8 @@
class StreamLogicDefaultDriver : public StreamLogicDriver {
public:
- explicit StreamLogicDefaultDriver(std::shared_ptr<StateSequence> commands)
- : mCommands(commands) {
+ StreamLogicDefaultDriver(std::shared_ptr<StateSequence> commands, size_t frameSizeBytes)
+ : mCommands(commands), mFrameSizeBytes(frameSizeBytes) {
mCommands->rewind();
}
@@ -2599,7 +2840,10 @@
if (actualSize != nullptr) {
// In the output scenario, reduce slightly the fmqByteCount to verify
// that the HAL module always consumes all data from the MQ.
- if (maxDataSize > 1) maxDataSize--;
+ if (maxDataSize > static_cast<int>(mFrameSizeBytes)) {
+ LOG(DEBUG) << __func__ << ": reducing data size by " << mFrameSizeBytes;
+ maxDataSize -= mFrameSizeBytes;
+ }
*actualSize = maxDataSize;
}
command->set<StreamDescriptor::Command::Tag::burst>(maxDataSize);
@@ -2645,6 +2889,7 @@
protected:
std::shared_ptr<StateSequence> mCommands;
+ const size_t mFrameSizeBytes;
std::optional<StreamDescriptor::State> mPreviousState;
std::optional<int64_t> mPreviousFrames;
bool mObservablePositionIncrease = false;
@@ -2693,7 +2938,7 @@
(!isNonBlocking && streamType == StreamTypeFilter::ASYNC)) {
continue;
}
- WithDebugFlags delayTransientStates = WithDebugFlags::createNested(debug);
+ WithDebugFlags delayTransientStates = WithDebugFlags::createNested(*debug);
delayTransientStates.flags().streamTransientStateDelayMs =
std::get<NAMED_CMD_DELAY_MS>(std::get<PARAM_CMD_SEQ>(GetParam()));
ASSERT_NO_FATAL_FAILURE(delayTransientStates.SetUp(module.get()));
@@ -2704,6 +2949,40 @@
} else {
ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq2(portConfig, commandsAndStates));
}
+ if (isNonBlocking) {
+ // Also try running the same sequence with "aosp.forceTransientBurst" set.
+ // This will only work with the default implementation. When it works, the stream
+ // tries always to move to the 'TRANSFERRING' state after a burst.
+ // This helps to check more paths for our test scenarios.
+ WithModuleParameter forceTransientBurst("aosp.forceTransientBurst", Boolean{true});
+ if (forceTransientBurst.SetUpNoChecks(module.get(), true /*failureExpected*/)
+ .isOk()) {
+ if (!std::get<PARAM_SETUP_SEQ>(GetParam())) {
+ ASSERT_NO_FATAL_FAILURE(
+ RunStreamIoCommandsImplSeq1(portConfig, commandsAndStates));
+ } else {
+ ASSERT_NO_FATAL_FAILURE(
+ RunStreamIoCommandsImplSeq2(portConfig, commandsAndStates));
+ }
+ }
+ } else if (!IOTraits<Stream>::is_input) {
+ // Also try running the same sequence with "aosp.forceSynchronousDrain" set.
+ // This will only work with the default implementation. When it works, the stream
+ // tries always to move to the 'IDLE' state after a drain.
+ // This helps to check more paths for our test scenarios.
+ WithModuleParameter forceSynchronousDrain("aosp.forceSynchronousDrain",
+ Boolean{true});
+ if (forceSynchronousDrain.SetUpNoChecks(module.get(), true /*failureExpected*/)
+ .isOk()) {
+ if (!std::get<PARAM_SETUP_SEQ>(GetParam())) {
+ ASSERT_NO_FATAL_FAILURE(
+ RunStreamIoCommandsImplSeq1(portConfig, commandsAndStates));
+ } else {
+ ASSERT_NO_FATAL_FAILURE(
+ RunStreamIoCommandsImplSeq2(portConfig, commandsAndStates));
+ }
+ }
+ }
}
}
@@ -2724,7 +3003,8 @@
WithStream<Stream> stream(patch.getPortConfig(IOTraits<Stream>::is_input));
ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
- StreamLogicDefaultDriver driver(commandsAndStates);
+ StreamLogicDefaultDriver driver(commandsAndStates,
+ stream.getContext()->getFrameSizeBytes());
typename IOTraits<Stream>::Worker worker(*stream.getContext(), &driver,
stream.getEventReceiver());
@@ -2745,7 +3025,8 @@
std::shared_ptr<StateSequence> commandsAndStates) {
WithStream<Stream> stream(portConfig);
ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
- StreamLogicDefaultDriver driver(commandsAndStates);
+ StreamLogicDefaultDriver driver(commandsAndStates,
+ stream.getContext()->getFrameSizeBytes());
typename IOTraits<Stream>::Worker worker(*stream.getContext(), &driver,
stream.getEventReceiver());
@@ -2998,6 +3279,17 @@
return ndk::ScopedAStatus::ok();
}
+TEST_P(AudioCoreSoundDose, SameInstance) {
+ if (soundDose == nullptr) {
+ GTEST_SKIP() << "SoundDose is not supported";
+ }
+ std::shared_ptr<ISoundDose> soundDose2;
+ EXPECT_IS_OK(module->getSoundDose(&soundDose2));
+ ASSERT_NE(nullptr, soundDose2.get());
+ EXPECT_EQ(soundDose->asBinder(), soundDose2->asBinder())
+ << "getSoundDose must return the same interface instance across invocations";
+}
+
TEST_P(AudioCoreSoundDose, GetSetOutputRs2) {
if (soundDose == nullptr) {
GTEST_SKIP() << "SoundDose is not supported";
@@ -3044,6 +3336,10 @@
testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
android::PrintInstanceNameToString);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioCoreModule);
+INSTANTIATE_TEST_SUITE_P(AudioCoreBluetoothTest, AudioCoreBluetooth,
+ testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
+ android::PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioCoreBluetooth);
INSTANTIATE_TEST_SUITE_P(AudioCoreTelephonyTest, AudioCoreTelephony,
testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
android::PrintInstanceNameToString);
@@ -3067,38 +3363,52 @@
// TODO: Add async test cases for input once it is implemented.
-std::shared_ptr<StateSequence> makeBurstCommands(bool isSync, size_t burstCount) {
- const auto burst =
- isSync ? std::vector<StateTransition>{std::make_pair(kBurstCommand,
- StreamDescriptor::State::ACTIVE)}
- : std::vector<StateTransition>{
- std::make_pair(kBurstCommand, StreamDescriptor::State::TRANSFERRING),
- std::make_pair(kTransferReadyEvent, StreamDescriptor::State::ACTIVE)};
- std::vector<StateTransition> result{
- std::make_pair(kStartCommand, StreamDescriptor::State::IDLE)};
- for (size_t i = 0; i < burstCount; ++i) {
- result.insert(result.end(), burst.begin(), burst.end());
+std::shared_ptr<StateSequence> makeBurstCommands(bool isSync) {
+ using State = StreamDescriptor::State;
+ auto d = std::make_unique<StateDag>();
+ StateDag::Node last = d->makeFinalNode(State::ACTIVE);
+ StateDag::Node active = d->makeNode(State::ACTIVE, kBurstCommand, last);
+ StateDag::Node idle = d->makeNode(State::IDLE, kBurstCommand, active);
+ if (!isSync) {
+ // Allow optional routing via the TRANSFERRING state on bursts.
+ active.children().push_back(d->makeNode(State::TRANSFERRING, kTransferReadyEvent, last));
+ idle.children().push_back(d->makeNode(State::TRANSFERRING, kTransferReadyEvent, active));
}
- return std::make_shared<SmartStateSequence>(result);
+ d->makeNode(State::STANDBY, kStartCommand, idle);
+ return std::make_shared<StateSequenceFollower>(std::move(d));
}
static const NamedCommandSequence kReadSeq =
- std::make_tuple(std::string("Read"), 0, StreamTypeFilter::ANY, makeBurstCommands(true, 3));
-static const NamedCommandSequence kWriteSyncSeq = std::make_tuple(
- std::string("Write"), 0, StreamTypeFilter::SYNC, makeBurstCommands(true, 3));
-static const NamedCommandSequence kWriteAsyncSeq = std::make_tuple(
- std::string("Write"), 0, StreamTypeFilter::ASYNC, makeBurstCommands(false, 3));
+ std::make_tuple(std::string("Read"), 0, StreamTypeFilter::ANY, makeBurstCommands(true));
+static const NamedCommandSequence kWriteSyncSeq =
+ std::make_tuple(std::string("Write"), 0, StreamTypeFilter::SYNC, makeBurstCommands(true));
+static const NamedCommandSequence kWriteAsyncSeq =
+ std::make_tuple(std::string("Write"), 0, StreamTypeFilter::ASYNC, makeBurstCommands(false));
std::shared_ptr<StateSequence> makeAsyncDrainCommands(bool isInput) {
- return std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
- std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
- std::make_pair(kBurstCommand, isInput ? StreamDescriptor::State::ACTIVE
- : StreamDescriptor::State::TRANSFERRING),
- std::make_pair(isInput ? kDrainInCommand : kDrainOutAllCommand,
- StreamDescriptor::State::DRAINING),
- isInput ? std::make_pair(kStartCommand, StreamDescriptor::State::ACTIVE)
- : std::make_pair(kBurstCommand, StreamDescriptor::State::TRANSFERRING),
- std::make_pair(isInput ? kDrainInCommand : kDrainOutAllCommand,
- StreamDescriptor::State::DRAINING)});
+ using State = StreamDescriptor::State;
+ auto d = std::make_unique<StateDag>();
+ if (isInput) {
+ d->makeNodes({std::make_pair(State::STANDBY, kStartCommand),
+ std::make_pair(State::IDLE, kBurstCommand),
+ std::make_pair(State::ACTIVE, kDrainInCommand),
+ std::make_pair(State::DRAINING, kStartCommand),
+ std::make_pair(State::ACTIVE, kDrainInCommand)},
+ State::DRAINING);
+ } else {
+ StateDag::Node draining =
+ d->makeNodes({std::make_pair(State::DRAINING, kBurstCommand),
+ std::make_pair(State::TRANSFERRING, kDrainOutAllCommand)},
+ State::DRAINING);
+ StateDag::Node idle =
+ d->makeNodes({std::make_pair(State::IDLE, kBurstCommand),
+ std::make_pair(State::TRANSFERRING, kDrainOutAllCommand)},
+ draining);
+ // If we get straight into ACTIVE on burst, no further testing is possible.
+ draining.children().push_back(d->makeFinalNode(State::ACTIVE));
+ idle.children().push_back(d->makeFinalNode(State::ACTIVE));
+ d->makeNode(State::STANDBY, kStartCommand, idle);
+ }
+ return std::make_shared<StateSequenceFollower>(std::move(d));
}
static const NamedCommandSequence kWriteDrainAsyncSeq =
std::make_tuple(std::string("WriteDrain"), kStreamTransientStateTransitionDelayMs,
@@ -3107,58 +3417,92 @@
std::string("Drain"), 0, StreamTypeFilter::ANY, makeAsyncDrainCommands(true));
std::shared_ptr<StateSequence> makeDrainOutCommands(bool isSync) {
- return std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
- std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
- std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
- std::make_pair(kDrainOutAllCommand, StreamDescriptor::State::DRAINING),
- std::make_pair(isSync ? TransitionTrigger(kGetStatusCommand)
- : TransitionTrigger(kDrainReadyEvent),
- StreamDescriptor::State::IDLE)});
+ using State = StreamDescriptor::State;
+ auto d = std::make_unique<StateDag>();
+ StateDag::Node last = d->makeFinalNode(State::IDLE);
+ StateDag::Node active = d->makeNodes(
+ {std::make_pair(State::ACTIVE, kDrainOutAllCommand),
+ std::make_pair(State::DRAINING, isSync ? TransitionTrigger(kGetStatusCommand)
+ : TransitionTrigger(kDrainReadyEvent))},
+ last);
+ StateDag::Node idle = d->makeNode(State::IDLE, kBurstCommand, active);
+ if (!isSync) {
+ idle.children().push_back(d->makeNode(State::TRANSFERRING, kTransferReadyEvent, active));
+ } else {
+ active.children().push_back(last);
+ }
+ d->makeNode(State::STANDBY, kStartCommand, idle);
+ return std::make_shared<StateSequenceFollower>(std::move(d));
}
static const NamedCommandSequence kDrainOutSyncSeq = std::make_tuple(
std::string("Drain"), 0, StreamTypeFilter::SYNC, makeDrainOutCommands(true));
static const NamedCommandSequence kDrainOutAsyncSeq = std::make_tuple(
std::string("Drain"), 0, StreamTypeFilter::ASYNC, makeDrainOutCommands(false));
-std::shared_ptr<StateSequence> makeDrainOutPauseCommands(bool isSync) {
- return std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
- std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
- std::make_pair(kBurstCommand, isSync ? StreamDescriptor::State::ACTIVE
- : StreamDescriptor::State::TRANSFERRING),
- std::make_pair(kDrainOutAllCommand, StreamDescriptor::State::DRAINING),
- std::make_pair(kPauseCommand, StreamDescriptor::State::DRAIN_PAUSED),
- std::make_pair(kStartCommand, StreamDescriptor::State::DRAINING),
- std::make_pair(kPauseCommand, StreamDescriptor::State::DRAIN_PAUSED),
- std::make_pair(kBurstCommand, isSync ? StreamDescriptor::State::PAUSED
- : StreamDescriptor::State::TRANSFER_PAUSED)});
+std::shared_ptr<StateSequence> makeDrainPauseOutCommands(bool isSync) {
+ using State = StreamDescriptor::State;
+ auto d = std::make_unique<StateDag>();
+ StateDag::Node draining = d->makeNodes({std::make_pair(State::DRAINING, kPauseCommand),
+ std::make_pair(State::DRAIN_PAUSED, kStartCommand),
+ std::make_pair(State::DRAINING, kPauseCommand),
+ std::make_pair(State::DRAIN_PAUSED, kBurstCommand)},
+ isSync ? State::PAUSED : State::TRANSFER_PAUSED);
+ StateDag::Node active = d->makeNode(State::ACTIVE, kDrainOutAllCommand, draining);
+ StateDag::Node idle = d->makeNode(State::IDLE, kBurstCommand, active);
+ if (!isSync) {
+ idle.children().push_back(d->makeNode(State::TRANSFERRING, kDrainOutAllCommand, draining));
+ } else {
+ // If we get straight into IDLE on drain, no further testing is possible.
+ active.children().push_back(d->makeFinalNode(State::IDLE));
+ }
+ d->makeNode(State::STANDBY, kStartCommand, idle);
+ return std::make_shared<StateSequenceFollower>(std::move(d));
}
static const NamedCommandSequence kDrainPauseOutSyncSeq =
std::make_tuple(std::string("DrainPause"), kStreamTransientStateTransitionDelayMs,
- StreamTypeFilter::SYNC, makeDrainOutPauseCommands(true));
+ StreamTypeFilter::SYNC, makeDrainPauseOutCommands(true));
static const NamedCommandSequence kDrainPauseOutAsyncSeq =
std::make_tuple(std::string("DrainPause"), kStreamTransientStateTransitionDelayMs,
- StreamTypeFilter::ASYNC, makeDrainOutPauseCommands(false));
+ StreamTypeFilter::ASYNC, makeDrainPauseOutCommands(false));
// This sequence also verifies that the capture / presentation position is not reset on standby.
std::shared_ptr<StateSequence> makeStandbyCommands(bool isInput, bool isSync) {
- return std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
- std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
- std::make_pair(kStandbyCommand, StreamDescriptor::State::STANDBY),
- std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
- std::make_pair(kBurstCommand, isInput || isSync
- ? StreamDescriptor::State::ACTIVE
- : StreamDescriptor::State::TRANSFERRING),
- std::make_pair(kPauseCommand, isInput || isSync
- ? StreamDescriptor::State::PAUSED
- : StreamDescriptor::State::TRANSFER_PAUSED),
- std::make_pair(kFlushCommand, isInput ? StreamDescriptor::State::STANDBY
- : StreamDescriptor::State::IDLE),
- std::make_pair(isInput ? kGetStatusCommand : kStandbyCommand, // no-op for input
- StreamDescriptor::State::STANDBY),
- std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
- std::make_pair(kBurstCommand, isInput || isSync
- ? StreamDescriptor::State::ACTIVE
- : StreamDescriptor::State::TRANSFERRING)});
+ using State = StreamDescriptor::State;
+ auto d = std::make_unique<StateDag>();
+ if (isInput) {
+ d->makeNodes({std::make_pair(State::STANDBY, kStartCommand),
+ std::make_pair(State::IDLE, kStandbyCommand),
+ std::make_pair(State::STANDBY, kStartCommand),
+ std::make_pair(State::IDLE, kBurstCommand),
+ std::make_pair(State::ACTIVE, kPauseCommand),
+ std::make_pair(State::PAUSED, kFlushCommand),
+ std::make_pair(State::STANDBY, kStartCommand),
+ std::make_pair(State::IDLE, kBurstCommand)},
+ State::ACTIVE);
+ } else {
+ StateDag::Node idle3 =
+ d->makeNode(State::IDLE, kBurstCommand, d->makeFinalNode(State::ACTIVE));
+ StateDag::Node idle2 = d->makeNodes({std::make_pair(State::IDLE, kStandbyCommand),
+ std::make_pair(State::STANDBY, kStartCommand)},
+ idle3);
+ StateDag::Node active = d->makeNodes({std::make_pair(State::ACTIVE, kPauseCommand),
+ std::make_pair(State::PAUSED, kFlushCommand)},
+ idle2);
+ StateDag::Node idle = d->makeNode(State::IDLE, kBurstCommand, active);
+ if (!isSync) {
+ idle3.children().push_back(d->makeFinalNode(State::TRANSFERRING));
+ StateDag::Node transferring =
+ d->makeNodes({std::make_pair(State::TRANSFERRING, kPauseCommand),
+ std::make_pair(State::TRANSFER_PAUSED, kFlushCommand)},
+ idle2);
+ idle.children().push_back(transferring);
+ }
+ d->makeNodes({std::make_pair(State::STANDBY, kStartCommand),
+ std::make_pair(State::IDLE, kStandbyCommand),
+ std::make_pair(State::STANDBY, kStartCommand)},
+ idle);
+ }
+ return std::make_shared<StateSequenceFollower>(std::move(d));
}
static const NamedCommandSequence kStandbyInSeq = std::make_tuple(
std::string("Standby"), 0, StreamTypeFilter::ANY, makeStandbyCommands(true, false));
@@ -3168,50 +3512,71 @@
std::make_tuple(std::string("Standby"), kStreamTransientStateTransitionDelayMs,
StreamTypeFilter::ASYNC, makeStandbyCommands(false, false));
-static const NamedCommandSequence kPauseInSeq =
- std::make_tuple(std::string("Pause"), 0, StreamTypeFilter::ANY,
- std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
- std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
- std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
- std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
- std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
- std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
- std::make_pair(kFlushCommand, StreamDescriptor::State::STANDBY)}));
-static const NamedCommandSequence kPauseOutSyncSeq =
- std::make_tuple(std::string("Pause"), 0, StreamTypeFilter::SYNC,
- std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
- std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
- std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
- std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
- std::make_pair(kStartCommand, StreamDescriptor::State::ACTIVE),
- std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
- std::make_pair(kBurstCommand, StreamDescriptor::State::PAUSED),
- std::make_pair(kStartCommand, StreamDescriptor::State::ACTIVE),
- std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED)}));
-/* TODO: Figure out a better way for testing sync/async bursts
-static const NamedCommandSequence kPauseOutAsyncSeq = std::make_tuple(
- std::string("Pause"), kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC,
- std::make_shared<StaticStateSequence>(std::vector<StateTransition>{
- std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
- std::make_pair(kBurstCommand, StreamDescriptor::State::TRANSFERRING),
- std::make_pair(kPauseCommand, StreamDescriptor::State::TRANSFER_PAUSED),
- std::make_pair(kStartCommand, StreamDescriptor::State::TRANSFERRING),
- std::make_pair(kPauseCommand, StreamDescriptor::State::TRANSFER_PAUSED),
- std::make_pair(kDrainOutAllCommand, StreamDescriptor::State::DRAIN_PAUSED),
- std::make_pair(kBurstCommand, StreamDescriptor::State::TRANSFER_PAUSED)}));
-*/
+std::shared_ptr<StateSequence> makePauseCommands(bool isInput, bool isSync) {
+ using State = StreamDescriptor::State;
+ auto d = std::make_unique<StateDag>();
+ if (isInput) {
+ d->makeNodes({std::make_pair(State::STANDBY, kStartCommand),
+ std::make_pair(State::IDLE, kBurstCommand),
+ std::make_pair(State::ACTIVE, kPauseCommand),
+ std::make_pair(State::PAUSED, kBurstCommand),
+ std::make_pair(State::ACTIVE, kPauseCommand),
+ std::make_pair(State::PAUSED, kFlushCommand)},
+ State::STANDBY);
+ } else {
+ StateDag::Node idle = d->makeNodes({std::make_pair(State::IDLE, kBurstCommand),
+ std::make_pair(State::ACTIVE, kPauseCommand),
+ std::make_pair(State::PAUSED, kStartCommand),
+ std::make_pair(State::ACTIVE, kPauseCommand),
+ std::make_pair(State::PAUSED, kBurstCommand),
+ std::make_pair(State::PAUSED, kStartCommand),
+ std::make_pair(State::ACTIVE, kPauseCommand)},
+ State::PAUSED);
+ if (!isSync) {
+ idle.children().push_back(
+ d->makeNodes({std::make_pair(State::TRANSFERRING, kPauseCommand),
+ std::make_pair(State::TRANSFER_PAUSED, kStartCommand),
+ std::make_pair(State::TRANSFERRING, kPauseCommand),
+ std::make_pair(State::TRANSFER_PAUSED, kDrainOutAllCommand),
+ std::make_pair(State::DRAIN_PAUSED, kBurstCommand)},
+ State::TRANSFER_PAUSED));
+ }
+ d->makeNode(State::STANDBY, kStartCommand, idle);
+ }
+ return std::make_shared<StateSequenceFollower>(std::move(d));
+}
+static const NamedCommandSequence kPauseInSeq = std::make_tuple(
+ std::string("Pause"), 0, StreamTypeFilter::ANY, makePauseCommands(true, false));
+static const NamedCommandSequence kPauseOutSyncSeq = std::make_tuple(
+ std::string("Pause"), 0, StreamTypeFilter::SYNC, makePauseCommands(false, true));
+static const NamedCommandSequence kPauseOutAsyncSeq =
+ std::make_tuple(std::string("Pause"), kStreamTransientStateTransitionDelayMs,
+ StreamTypeFilter::ASYNC, makePauseCommands(false, false));
std::shared_ptr<StateSequence> makeFlushCommands(bool isInput, bool isSync) {
- return std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
- std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
- std::make_pair(kBurstCommand, isInput || isSync
- ? StreamDescriptor::State::ACTIVE
- : StreamDescriptor::State::TRANSFERRING),
- std::make_pair(kPauseCommand, isInput || isSync
- ? StreamDescriptor::State::PAUSED
- : StreamDescriptor::State::TRANSFER_PAUSED),
- std::make_pair(kFlushCommand, isInput ? StreamDescriptor::State::STANDBY
- : StreamDescriptor::State::IDLE)});
+ using State = StreamDescriptor::State;
+ auto d = std::make_unique<StateDag>();
+ if (isInput) {
+ d->makeNodes({std::make_pair(State::STANDBY, kStartCommand),
+ std::make_pair(State::IDLE, kBurstCommand),
+ std::make_pair(State::ACTIVE, kPauseCommand),
+ std::make_pair(State::PAUSED, kFlushCommand)},
+ State::STANDBY);
+ } else {
+ StateDag::Node last = d->makeFinalNode(State::IDLE);
+ StateDag::Node idle = d->makeNodes({std::make_pair(State::IDLE, kBurstCommand),
+ std::make_pair(State::ACTIVE, kPauseCommand),
+ std::make_pair(State::PAUSED, kFlushCommand)},
+ last);
+ if (!isSync) {
+ idle.children().push_back(
+ d->makeNodes({std::make_pair(State::TRANSFERRING, kPauseCommand),
+ std::make_pair(State::TRANSFER_PAUSED, kFlushCommand)},
+ last));
+ }
+ d->makeNode(State::STANDBY, kStartCommand, idle);
+ }
+ return std::make_shared<StateSequenceFollower>(std::move(d));
}
static const NamedCommandSequence kFlushInSeq = std::make_tuple(
std::string("Flush"), 0, StreamTypeFilter::ANY, makeFlushCommands(true, false));
@@ -3222,13 +3587,21 @@
StreamTypeFilter::ASYNC, makeFlushCommands(false, false));
std::shared_ptr<StateSequence> makeDrainPauseFlushOutCommands(bool isSync) {
- return std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
- std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
- std::make_pair(kBurstCommand, isSync ? StreamDescriptor::State::ACTIVE
- : StreamDescriptor::State::TRANSFERRING),
- std::make_pair(kDrainOutAllCommand, StreamDescriptor::State::DRAINING),
- std::make_pair(kPauseCommand, StreamDescriptor::State::DRAIN_PAUSED),
- std::make_pair(kFlushCommand, StreamDescriptor::State::IDLE)});
+ using State = StreamDescriptor::State;
+ auto d = std::make_unique<StateDag>();
+ StateDag::Node draining = d->makeNodes({std::make_pair(State::DRAINING, kPauseCommand),
+ std::make_pair(State::DRAIN_PAUSED, kFlushCommand)},
+ State::IDLE);
+ StateDag::Node active = d->makeNode(State::ACTIVE, kDrainOutAllCommand, draining);
+ StateDag::Node idle = d->makeNode(State::IDLE, kBurstCommand, active);
+ if (!isSync) {
+ idle.children().push_back(d->makeNode(State::TRANSFERRING, kDrainOutAllCommand, draining));
+ } else {
+ // If we get straight into IDLE on drain, no further testing is possible.
+ active.children().push_back(d->makeFinalNode(State::IDLE));
+ }
+ d->makeNode(State::STANDBY, kStartCommand, idle);
+ return std::make_shared<StateSequenceFollower>(std::move(d));
}
static const NamedCommandSequence kDrainPauseFlushOutSyncSeq =
std::make_tuple(std::string("DrainPauseFlush"), kStreamTransientStateTransitionDelayMs,
diff --git a/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp b/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp
new file mode 100644
index 0000000..9feff91
--- /dev/null
+++ b/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp
@@ -0,0 +1,1115 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/Vintf.h>
+
+#define LOG_TAG "VtsHalDynamicsProcessingTest"
+
+#include <set>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+
+#include <Utils.h>
+#include "EffectHelper.h"
+
+using namespace android;
+
+using aidl::android::hardware::audio::effect::Capability;
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::DynamicsProcessing;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::kDynamicsProcessingTypeUUID;
+using aidl::android::hardware::audio::effect::Parameter;
+
+/**
+ * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
+ * VtsAudioEffectTargetTest.
+ */
+class DynamicsProcessingTestHelper : public EffectHelper {
+ public:
+ DynamicsProcessingTestHelper(std::pair<std::shared_ptr<IFactory>, Descriptor> pair,
+ int32_t channelLayOut = AudioChannelLayout::LAYOUT_STEREO) {
+ std::tie(mFactory, mDescriptor) = pair;
+ mChannelLayout = channelLayOut;
+ mChannelCount = ::android::hardware::audio::common::getChannelCount(
+ AudioChannelLayout::make<AudioChannelLayout::layoutMask>(mChannelLayout));
+ }
+
+ // setup
+ void SetUpDynamicsProcessingEffect() {
+ ASSERT_NE(nullptr, mFactory);
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+
+ Parameter::Specific specific = getDefaultParamSpecific();
+ Parameter::Common common = EffectHelper::createParamCommon(
+ 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
+ 0x100 /* iFrameCount */, 0x100 /* oFrameCount */,
+ AudioChannelLayout::make<AudioChannelLayout::layoutMask>(mChannelLayout),
+ AudioChannelLayout::make<AudioChannelLayout::layoutMask>(mChannelLayout));
+ IEffect::OpenEffectReturn ret;
+ ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &ret, EX_NONE));
+ ASSERT_NE(nullptr, mEffect);
+ mEngineConfigApplied = mEngineConfigPreset;
+ }
+
+ Parameter::Specific getDefaultParamSpecific() {
+ DynamicsProcessing dp = DynamicsProcessing::make<DynamicsProcessing::engineArchitecture>(
+ mEngineConfigPreset);
+ Parameter::Specific specific =
+ Parameter::Specific::make<Parameter::Specific::dynamicsProcessing>(dp);
+ return specific;
+ }
+
+ // teardown
+ void TearDownDynamicsProcessingEffect() {
+ ASSERT_NO_FATAL_FAILURE(close(mEffect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+ }
+
+ // utils functions for parameter checking
+ bool isParamValid(const DynamicsProcessing::Tag& tag, const DynamicsProcessing& dp,
+ const Descriptor& desc);
+ bool isParamEqual(const DynamicsProcessing::Tag& tag, const DynamicsProcessing& dpRef,
+ const DynamicsProcessing& dpTest);
+
+ bool isEnablementValid(const DynamicsProcessing::StageEnablement& enablement);
+ bool isEngineConfigValid(const DynamicsProcessing::EngineArchitecture& cfg);
+
+ bool isCutoffFrequencyValid(float freq, const DynamicsProcessing::Capability& cap);
+ bool isChannelConfigValid(const std::vector<DynamicsProcessing::ChannelConfig>& cfgs,
+ bool stageInUse);
+
+ bool isPreEqBandConfigValid(const DynamicsProcessing::Capability& cap,
+ const std::vector<DynamicsProcessing::EqBandConfig>& cfgs,
+ bool stageInUse, int bandCount);
+ bool isPostEqBandConfigValid(const DynamicsProcessing::Capability& cap,
+ const std::vector<DynamicsProcessing::EqBandConfig>& cfgs,
+ bool stageInUse, int bandCount);
+ bool isMbcBandConfigValid(const DynamicsProcessing::Capability& cap,
+ const std::vector<DynamicsProcessing::MbcBandConfig>& cfgs,
+ bool stageInUse, int bandCount);
+ bool isLimiterConfigValid(const std::vector<DynamicsProcessing::LimiterConfig>& cfgs,
+ bool stageInUse);
+ bool isInputGainValid(const std::vector<DynamicsProcessing::InputGain>& cfgs);
+
+ bool isEngineConfigEqual(const DynamicsProcessing::EngineArchitecture& refCfg,
+ const DynamicsProcessing::EngineArchitecture& testCfg);
+
+ template <typename T>
+ std::vector<T> filterEnabledVector(const std::vector<T>& vec);
+
+ template <typename T>
+ bool isAidlVectorEqualAfterFilter(const std::vector<T>& source, const std::vector<T>& target);
+
+ template <typename T>
+ bool isAidlVectorEqual(const std::vector<T>& source, const std::vector<T>& target);
+
+ // get set params and validate
+ void SetAndGetDynamicsProcessingParameters();
+
+ // enqueue test parameters
+ void addEngineConfig(const DynamicsProcessing::EngineArchitecture& cfg);
+ void addPreEqChannelConfig(const std::vector<DynamicsProcessing::ChannelConfig>& cfg);
+ void addPostEqChannelConfig(const std::vector<DynamicsProcessing::ChannelConfig>& cfg);
+ void addMbcChannelConfig(const std::vector<DynamicsProcessing::ChannelConfig>& cfg);
+ void addPreEqBandConfigs(const std::vector<DynamicsProcessing::EqBandConfig>& cfgs);
+ void addPostEqBandConfigs(const std::vector<DynamicsProcessing::EqBandConfig>& cfgs);
+ void addMbcBandConfigs(const std::vector<DynamicsProcessing::MbcBandConfig>& cfgs);
+ void addLimiterConfig(const std::vector<DynamicsProcessing::LimiterConfig>& cfg);
+ void addInputGain(const std::vector<DynamicsProcessing::InputGain>& inputGain);
+
+ static constexpr float kPreferredProcessingDurationMs = 10.0f;
+ static constexpr int kBandCount = 5;
+ std::shared_ptr<IFactory> mFactory;
+ std::shared_ptr<IEffect> mEffect;
+ Descriptor mDescriptor;
+ DynamicsProcessing::EngineArchitecture mEngineConfigApplied;
+ DynamicsProcessing::EngineArchitecture mEngineConfigPreset{
+ .resolutionPreference =
+ DynamicsProcessing::ResolutionPreference::FAVOR_FREQUENCY_RESOLUTION,
+ .preferredProcessingDurationMs = kPreferredProcessingDurationMs,
+ .preEqStage = {.inUse = true, .bandCount = kBandCount},
+ .postEqStage = {.inUse = true, .bandCount = kBandCount},
+ .mbcStage = {.inUse = true, .bandCount = kBandCount},
+ .limiterInUse = true,
+ };
+
+ std::unordered_set<int /* channelId */> mPreEqChannelEnable;
+ std::unordered_set<int /* channelId */> mPostEqChannelEnable;
+ std::unordered_set<int /* channelId */> mMbcChannelEnable;
+ std::unordered_set<int /* channelId */> mLimiterChannelEnable;
+ static const std::set<std::vector<DynamicsProcessing::ChannelConfig>> kChannelConfigTestSet;
+ static const std::set<DynamicsProcessing::StageEnablement> kStageEnablementTestSet;
+ static const std::set<std::vector<DynamicsProcessing::InputGain>> kInputGainTestSet;
+
+ private:
+ int32_t mChannelLayout;
+ int mChannelCount;
+ std::vector<std::pair<DynamicsProcessing::Tag, DynamicsProcessing>> mTags;
+ void CleanUp() {
+ mTags.clear();
+ mPreEqChannelEnable.clear();
+ mPostEqChannelEnable.clear();
+ mMbcChannelEnable.clear();
+ mLimiterChannelEnable.clear();
+ }
+};
+
+// test value set for DynamicsProcessing::StageEnablement
+const std::set<DynamicsProcessing::StageEnablement>
+ DynamicsProcessingTestHelper::kStageEnablementTestSet = {
+ {.inUse = true, .bandCount = DynamicsProcessingTestHelper::kBandCount},
+ {.inUse = true, .bandCount = 0},
+ {.inUse = true, .bandCount = -1},
+ {.inUse = false, .bandCount = DynamicsProcessingTestHelper::kBandCount}};
+
+// test value set for DynamicsProcessing::ChannelConfig
+const std::set<std::vector<DynamicsProcessing::ChannelConfig>>
+ DynamicsProcessingTestHelper::kChannelConfigTestSet = {
+ {{.channel = -1, .enable = false},
+ {.channel = 0, .enable = true},
+ {.channel = 1, .enable = false},
+ {.channel = 2, .enable = true}},
+
+ {{.channel = -1, .enable = false}, {.channel = 2, .enable = true}},
+
+ {{.channel = 0, .enable = true}, {.channel = 1, .enable = true}}};
+
+// test value set for DynamicsProcessing::InputGain
+const std::set<std::vector<DynamicsProcessing::InputGain>>
+ DynamicsProcessingTestHelper::kInputGainTestSet = {
+ {{.channel = 0, .gainDb = 10.f},
+ {.channel = 1, .gainDb = 0.f},
+ {.channel = 2, .gainDb = -10.f}},
+
+ {{.channel = -1, .gainDb = -10.f}, {.channel = -2, .gainDb = 10.f}},
+
+ {{.channel = -1, .gainDb = 10.f}, {.channel = 0, .gainDb = -10.f}}};
+
+bool DynamicsProcessingTestHelper::isParamValid(const DynamicsProcessing::Tag& tag,
+ const DynamicsProcessing& dp,
+ const Descriptor& desc) {
+ const DynamicsProcessing::Capability& dpCap =
+ desc.capability.get<Capability::dynamicsProcessing>();
+ switch (tag) {
+ case DynamicsProcessing::engineArchitecture: {
+ return isEngineConfigValid(dp.get<DynamicsProcessing::engineArchitecture>());
+ }
+ case DynamicsProcessing::preEq: {
+ return isChannelConfigValid(dp.get<DynamicsProcessing::preEq>(),
+ mEngineConfigApplied.preEqStage.inUse);
+ }
+ case DynamicsProcessing::postEq: {
+ return isChannelConfigValid(dp.get<DynamicsProcessing::postEq>(),
+ mEngineConfigApplied.postEqStage.inUse);
+ }
+ case DynamicsProcessing::mbc: {
+ return isChannelConfigValid(dp.get<DynamicsProcessing::mbc>(),
+ mEngineConfigApplied.mbcStage.inUse);
+ }
+ case DynamicsProcessing::preEqBand: {
+ return isPreEqBandConfigValid(dpCap, dp.get<DynamicsProcessing::preEqBand>(),
+ mEngineConfigApplied.preEqStage.inUse,
+ mEngineConfigApplied.preEqStage.bandCount);
+ }
+ case DynamicsProcessing::postEqBand: {
+ return isPostEqBandConfigValid(dpCap, dp.get<DynamicsProcessing::postEqBand>(),
+ mEngineConfigApplied.postEqStage.inUse,
+ mEngineConfigApplied.postEqStage.bandCount);
+ }
+ case DynamicsProcessing::mbcBand: {
+ return isMbcBandConfigValid(dpCap, dp.get<DynamicsProcessing::mbcBand>(),
+ mEngineConfigApplied.mbcStage.inUse,
+ mEngineConfigApplied.mbcStage.bandCount);
+ }
+ case DynamicsProcessing::limiter: {
+ return isLimiterConfigValid(dp.get<DynamicsProcessing::limiter>(),
+ mEngineConfigApplied.limiterInUse);
+ }
+ case DynamicsProcessing::inputGain: {
+ return isInputGainValid(dp.get<DynamicsProcessing::inputGain>());
+ }
+ case DynamicsProcessing::vendorExtension: {
+ return true;
+ }
+ }
+ return true;
+}
+
+bool DynamicsProcessingTestHelper::isParamEqual(const DynamicsProcessing::Tag& tag,
+ const DynamicsProcessing& dpRef,
+ const DynamicsProcessing& dpTest) {
+ switch (tag) {
+ case DynamicsProcessing::engineArchitecture: {
+ return isEngineConfigEqual(dpRef.get<DynamicsProcessing::engineArchitecture>(),
+ dpTest.get<DynamicsProcessing::engineArchitecture>());
+ }
+ case DynamicsProcessing::preEq: {
+ const auto& source = dpRef.get<DynamicsProcessing::preEq>();
+ const auto& target = dpTest.get<DynamicsProcessing::preEq>();
+ return isAidlVectorEqualAfterFilter<DynamicsProcessing::ChannelConfig>(source, target);
+ }
+ case DynamicsProcessing::postEq: {
+ return isAidlVectorEqualAfterFilter<DynamicsProcessing::ChannelConfig>(
+ dpRef.get<DynamicsProcessing::postEq>(),
+ dpTest.get<DynamicsProcessing::postEq>());
+ }
+ case DynamicsProcessing::mbc: {
+ return isAidlVectorEqualAfterFilter<DynamicsProcessing::ChannelConfig>(
+ dpRef.get<DynamicsProcessing::mbc>(), dpTest.get<DynamicsProcessing::mbc>());
+ }
+ case DynamicsProcessing::preEqBand: {
+ return isAidlVectorEqualAfterFilter<DynamicsProcessing::EqBandConfig>(
+ dpRef.get<DynamicsProcessing::preEqBand>(),
+ dpTest.get<DynamicsProcessing::preEqBand>());
+ }
+ case DynamicsProcessing::postEqBand: {
+ return isAidlVectorEqualAfterFilter<DynamicsProcessing::EqBandConfig>(
+ dpRef.get<DynamicsProcessing::postEqBand>(),
+ dpTest.get<DynamicsProcessing::postEqBand>());
+ }
+ case DynamicsProcessing::mbcBand: {
+ return isAidlVectorEqualAfterFilter<DynamicsProcessing::MbcBandConfig>(
+ dpRef.get<DynamicsProcessing::mbcBand>(),
+ dpTest.get<DynamicsProcessing::mbcBand>());
+ }
+ case DynamicsProcessing::limiter: {
+ return isAidlVectorEqualAfterFilter<DynamicsProcessing::LimiterConfig>(
+ dpRef.get<DynamicsProcessing::limiter>(),
+ dpTest.get<DynamicsProcessing::limiter>());
+ }
+ case DynamicsProcessing::inputGain: {
+ return isAidlVectorEqual<DynamicsProcessing::InputGain>(
+ dpRef.get<DynamicsProcessing::inputGain>(),
+ dpTest.get<DynamicsProcessing::inputGain>());
+ }
+ case DynamicsProcessing::vendorExtension: {
+ return false;
+ }
+ }
+}
+
+bool DynamicsProcessingTestHelper::isEnablementValid(
+ const DynamicsProcessing::StageEnablement& enablement) {
+ return !enablement.inUse || (enablement.inUse && enablement.bandCount > 0);
+}
+
+bool DynamicsProcessingTestHelper::isEngineConfigValid(
+ const DynamicsProcessing::EngineArchitecture& cfg) {
+ return cfg.preferredProcessingDurationMs >= 0 && isEnablementValid(cfg.preEqStage) &&
+ isEnablementValid(cfg.postEqStage) && isEnablementValid(cfg.mbcStage);
+}
+
+bool DynamicsProcessingTestHelper::isChannelConfigValid(
+ const std::vector<DynamicsProcessing::ChannelConfig>& cfgs, bool stageInUse) {
+ std::unordered_set<int> channelSet;
+ if (!stageInUse) return false;
+ for (auto cfg : cfgs) {
+ if (cfg.channel < 0 || cfg.channel >= mChannelCount || 0 != channelSet.count(cfg.channel)) {
+ return false;
+ }
+ channelSet.insert(cfg.channel);
+ }
+ return true;
+}
+
+bool DynamicsProcessingTestHelper::isCutoffFrequencyValid(
+ float freq, const DynamicsProcessing::Capability& cap) {
+ return freq >= cap.minCutOffFreq && freq <= cap.maxCutOffFreq;
+}
+
+bool DynamicsProcessingTestHelper::isPreEqBandConfigValid(
+ const DynamicsProcessing::Capability& cap,
+ const std::vector<DynamicsProcessing::EqBandConfig>& cfgs, bool stageInUse, int bandCount) {
+ std::set<std::pair<int /* channelID */, int /* bandID */>> bandSet;
+ if (!stageInUse) return false;
+ for (auto cfg : cfgs) {
+ if (0 == mPreEqChannelEnable.count(cfg.channel) || cfg.channel < 0 ||
+ cfg.channel >= mChannelCount || cfg.band < 0 || cfg.band >= bandCount ||
+ !isCutoffFrequencyValid(cfg.cutoffFrequencyHz, cap) ||
+ 0 != bandSet.count({cfg.channel, cfg.band})) {
+ return false;
+ }
+ bandSet.insert({cfg.channel, cfg.band});
+ }
+ return true;
+}
+
+bool DynamicsProcessingTestHelper::isPostEqBandConfigValid(
+ const DynamicsProcessing::Capability& cap,
+ const std::vector<DynamicsProcessing::EqBandConfig>& cfgs, bool stageInUse, int bandCount) {
+ std::set<std::pair<int /* channelID */, int /* bandID */>> bandSet;
+ // not able to set/get parameter when stage not in use.
+ if (!stageInUse) return false;
+ for (auto cfg : cfgs) {
+ if (0 == mPostEqChannelEnable.count(cfg.channel) || cfg.channel < 0 ||
+ cfg.channel >= mChannelCount || cfg.band < 0 || cfg.band >= bandCount ||
+ !isCutoffFrequencyValid(cfg.cutoffFrequencyHz, cap) ||
+ 0 != bandSet.count({cfg.channel, cfg.band})) {
+ return false;
+ }
+ bandSet.insert({cfg.channel, cfg.band});
+ }
+ return true;
+}
+
+bool DynamicsProcessingTestHelper::isMbcBandConfigValid(
+ const DynamicsProcessing::Capability& cap,
+ const std::vector<DynamicsProcessing::MbcBandConfig>& cfgs, bool stageInUse,
+ int bandCount) {
+ std::set<std::pair<int /* channelID */, int /* bandID */>> bandSet;
+ if (!stageInUse) return false;
+ for (auto cfg : cfgs) {
+ if (0 == mMbcChannelEnable.count(cfg.channel) || cfg.channel < 0 ||
+ cfg.channel >= mChannelCount || cfg.band < 0 || cfg.band >= bandCount ||
+ (cfg.attackTimeMs < 0) || cfg.releaseTimeMs < 0 || cfg.ratio < 0 ||
+ cfg.thresholdDb > 0 || cfg.kneeWidthDb < 0 || cfg.noiseGateThresholdDb > 0 ||
+ cfg.expanderRatio < 0 || !isCutoffFrequencyValid(cfg.cutoffFrequencyHz, cap) ||
+ 0 != bandSet.count({cfg.channel, cfg.band})) {
+ return false;
+ }
+ bandSet.insert({cfg.channel, cfg.band});
+ }
+ return true;
+}
+
+bool DynamicsProcessingTestHelper::isLimiterConfigValid(
+ const std::vector<DynamicsProcessing::LimiterConfig>& cfgs, bool stageInUse) {
+ std::set<int> channelSet;
+ if (!stageInUse) return false;
+ for (auto cfg : cfgs) {
+ if (0 == mLimiterChannelEnable.count(cfg.channel) || cfg.channel < 0 ||
+ cfg.channel >= mChannelCount || cfg.attackTimeMs < 0 || cfg.releaseTimeMs < 0 ||
+ cfg.ratio < 0 || cfg.thresholdDb > 0 || 0 != channelSet.count(cfg.channel)) {
+ return false;
+ }
+ channelSet.insert(cfg.channel);
+ }
+ return true;
+}
+
+bool DynamicsProcessingTestHelper::isInputGainValid(
+ const std::vector<DynamicsProcessing::InputGain>& cfgs) {
+ std::set<int> channelSet;
+ for (auto cfg : cfgs) {
+ if (cfg.channel < 0 || cfg.channel >= mChannelCount || 0 != channelSet.count(cfg.channel)) {
+ return false;
+ }
+ channelSet.insert(cfg.channel);
+ }
+ return true;
+}
+
+bool DynamicsProcessingTestHelper::isEngineConfigEqual(
+ const DynamicsProcessing::EngineArchitecture& ref,
+ const DynamicsProcessing::EngineArchitecture& test) {
+ return ref == test;
+}
+
+template <typename T>
+std::vector<T> DynamicsProcessingTestHelper::filterEnabledVector(const std::vector<T>& vec) {
+ std::vector<T> ret;
+ std::copy_if(vec.begin(), vec.end(), std::back_inserter(ret),
+ [](const auto& v) { return v.enable; });
+ return ret;
+}
+
+template <typename T>
+bool DynamicsProcessingTestHelper::isAidlVectorEqual(const std::vector<T>& source,
+ const std::vector<T>& target) {
+ if (source.size() != target.size()) return false;
+
+ auto tempS = source;
+ auto tempT = target;
+ std::sort(tempS.begin(), tempS.end());
+ std::sort(tempT.begin(), tempT.end());
+ return tempS == tempT;
+}
+
+template <typename T>
+bool DynamicsProcessingTestHelper::isAidlVectorEqualAfterFilter(const std::vector<T>& source,
+ const std::vector<T>& target) {
+ return isAidlVectorEqual<T>(filterEnabledVector<T>(source), filterEnabledVector<T>(target));
+}
+
+void DynamicsProcessingTestHelper::SetAndGetDynamicsProcessingParameters() {
+ for (auto& it : mTags) {
+ auto& tag = it.first;
+ auto& dp = it.second;
+
+ // validate parameter
+ Descriptor desc;
+ ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
+ const bool valid = isParamValid(tag, dp, desc);
+ const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
+
+ // set parameter
+ Parameter expectParam;
+ Parameter::Specific specific;
+ specific.set<Parameter::Specific::dynamicsProcessing>(dp);
+ expectParam.set<Parameter::specific>(specific);
+ ASSERT_STATUS(expected, mEffect->setParameter(expectParam)) << expectParam.toString();
+
+ // only get if parameter in range and set success
+ if (expected == EX_NONE) {
+ Parameter getParam;
+ Parameter::Id id;
+ DynamicsProcessing::Id dpId;
+ dpId.set<DynamicsProcessing::Id::commonTag>(tag);
+ id.set<Parameter::Id::dynamicsProcessingTag>(dpId);
+ // if set success, then get should match
+ EXPECT_STATUS(expected, mEffect->getParameter(id, &getParam));
+ Parameter::Specific specificTest = getParam.get<Parameter::specific>();
+ const auto& target = specificTest.get<Parameter::Specific::dynamicsProcessing>();
+ EXPECT_TRUE(isParamEqual(tag, dp, target)) << dp.toString() << "\n"
+ << target.toString();
+ // update mEngineConfigApplied after setting successfully
+ if (tag == DynamicsProcessing::engineArchitecture) {
+ mEngineConfigApplied = target.get<DynamicsProcessing::engineArchitecture>();
+ }
+ }
+ }
+}
+
+void DynamicsProcessingTestHelper::addEngineConfig(
+ const DynamicsProcessing::EngineArchitecture& cfg) {
+ DynamicsProcessing dp;
+ dp.set<DynamicsProcessing::engineArchitecture>(cfg);
+ mTags.push_back({DynamicsProcessing::engineArchitecture, dp});
+}
+
+void DynamicsProcessingTestHelper::addPreEqChannelConfig(
+ const std::vector<DynamicsProcessing::ChannelConfig>& cfgs) {
+ DynamicsProcessing dp;
+ dp.set<DynamicsProcessing::preEq>(cfgs);
+ mTags.push_back({DynamicsProcessing::preEq, dp});
+ for (auto& cfg : cfgs) {
+ if (cfg.enable) mPreEqChannelEnable.insert(cfg.channel);
+ }
+}
+
+void DynamicsProcessingTestHelper::addPostEqChannelConfig(
+ const std::vector<DynamicsProcessing::ChannelConfig>& cfgs) {
+ DynamicsProcessing dp;
+ dp.set<DynamicsProcessing::postEq>(cfgs);
+ mTags.push_back({DynamicsProcessing::postEq, dp});
+ for (auto& cfg : cfgs) {
+ if (cfg.enable) mPostEqChannelEnable.insert(cfg.channel);
+ }
+}
+
+void DynamicsProcessingTestHelper::addMbcChannelConfig(
+ const std::vector<DynamicsProcessing::ChannelConfig>& cfgs) {
+ DynamicsProcessing dp;
+ dp.set<DynamicsProcessing::mbc>(cfgs);
+ mTags.push_back({DynamicsProcessing::mbc, dp});
+ for (auto& cfg : cfgs) {
+ if (cfg.enable) mMbcChannelEnable.insert(cfg.channel);
+ }
+}
+
+void DynamicsProcessingTestHelper::addPreEqBandConfigs(
+ const std::vector<DynamicsProcessing::EqBandConfig>& cfgs) {
+ DynamicsProcessing dp;
+ dp.set<DynamicsProcessing::preEqBand>(cfgs);
+ mTags.push_back({DynamicsProcessing::preEqBand, dp});
+}
+
+void DynamicsProcessingTestHelper::addPostEqBandConfigs(
+ const std::vector<DynamicsProcessing::EqBandConfig>& cfgs) {
+ DynamicsProcessing dp;
+ dp.set<DynamicsProcessing::postEqBand>(cfgs);
+ mTags.push_back({DynamicsProcessing::postEqBand, dp});
+}
+
+void DynamicsProcessingTestHelper::addMbcBandConfigs(
+ const std::vector<DynamicsProcessing::MbcBandConfig>& cfgs) {
+ DynamicsProcessing dp;
+ dp.set<DynamicsProcessing::mbcBand>(cfgs);
+ mTags.push_back({DynamicsProcessing::mbcBand, dp});
+}
+
+void DynamicsProcessingTestHelper::addLimiterConfig(
+ const std::vector<DynamicsProcessing::LimiterConfig>& cfgs) {
+ DynamicsProcessing dp;
+ dp.set<DynamicsProcessing::limiter>(cfgs);
+ mTags.push_back({DynamicsProcessing::limiter, dp});
+ for (auto& cfg : cfgs) {
+ if (cfg.enable) mLimiterChannelEnable.insert(cfg.channel);
+ }
+}
+
+void DynamicsProcessingTestHelper::addInputGain(
+ const std::vector<DynamicsProcessing::InputGain>& inputGains) {
+ DynamicsProcessing dp;
+ dp.set<DynamicsProcessing::inputGain>(inputGains);
+ mTags.push_back({DynamicsProcessing::inputGain, dp});
+}
+
+/**
+ * Test DynamicsProcessing Engine Configuration
+ */
+enum EngineArchitectureTestParamName {
+ ENGINE_TEST_INSTANCE_NAME,
+ ENGINE_TEST_RESOLUTION_PREFERENCE,
+ ENGINE_TEST_PREFERRED_DURATION,
+ ENGINE_TEST_STAGE_ENABLEMENT,
+ ENGINE_TEST_LIMITER_IN_USE
+};
+using EngineArchitectureTestParams = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>,
+ DynamicsProcessing::ResolutionPreference, float,
+ DynamicsProcessing::StageEnablement, bool>;
+
+void fillEngineArchConfig(DynamicsProcessing::EngineArchitecture& cfg,
+ const EngineArchitectureTestParams& params) {
+ cfg.resolutionPreference = std::get<ENGINE_TEST_RESOLUTION_PREFERENCE>(params);
+ cfg.preferredProcessingDurationMs = std::get<ENGINE_TEST_PREFERRED_DURATION>(params);
+ cfg.preEqStage = cfg.postEqStage = cfg.mbcStage =
+ std::get<ENGINE_TEST_STAGE_ENABLEMENT>(params);
+ cfg.limiterInUse = std::get<ENGINE_TEST_LIMITER_IN_USE>(params);
+}
+
+class DynamicsProcessingTestEngineArchitecture
+ : public ::testing::TestWithParam<EngineArchitectureTestParams>,
+ public DynamicsProcessingTestHelper {
+ public:
+ DynamicsProcessingTestEngineArchitecture()
+ : DynamicsProcessingTestHelper(std::get<ENGINE_TEST_INSTANCE_NAME>(GetParam())) {
+ fillEngineArchConfig(mCfg, GetParam());
+ };
+
+ void SetUp() override { SetUpDynamicsProcessingEffect(); }
+
+ void TearDown() override { TearDownDynamicsProcessingEffect(); }
+
+ DynamicsProcessing::EngineArchitecture mCfg;
+};
+
+TEST_P(DynamicsProcessingTestEngineArchitecture, SetAndGetEngineArch) {
+ EXPECT_NO_FATAL_FAILURE(addEngineConfig(mCfg));
+ SetAndGetDynamicsProcessingParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ DynamicsProcessingTest, DynamicsProcessingTestEngineArchitecture,
+ ::testing::Combine(
+ testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+ IFactory::descriptor, kDynamicsProcessingTypeUUID)),
+ testing::Values(DynamicsProcessing::ResolutionPreference::FAVOR_TIME_RESOLUTION,
+ DynamicsProcessing::ResolutionPreference::
+ FAVOR_FREQUENCY_RESOLUTION), // variant
+ testing::Values(-10.f, 0.f, 10.f), // processing duration
+ testing::ValuesIn(
+ DynamicsProcessingTestHelper::kStageEnablementTestSet), // preEQ/postEQ/mbc
+ testing::Bool()), // limiter enable
+ [](const auto& info) {
+ auto descriptor = std::get<ENGINE_TEST_INSTANCE_NAME>(info.param).second;
+ DynamicsProcessing::EngineArchitecture cfg;
+ fillEngineArchConfig(cfg, info.param);
+ std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+ descriptor.common.name + "_UUID_" +
+ descriptor.common.id.uuid.toString() + "_Cfg_" + cfg.toString();
+ std::replace_if(
+ name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+ return name;
+ });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingTestEngineArchitecture);
+
+/**
+ * Test DynamicsProcessing Input Gain
+ */
+enum InputGainTestParamName {
+ INPUT_GAIN_INSTANCE_NAME,
+ INPUT_GAIN_PARAM,
+};
+class DynamicsProcessingTestInputGain
+ : public ::testing::TestWithParam<std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>,
+ std::vector<DynamicsProcessing::InputGain>>>,
+ public DynamicsProcessingTestHelper {
+ public:
+ DynamicsProcessingTestInputGain()
+ : DynamicsProcessingTestHelper(std::get<INPUT_GAIN_INSTANCE_NAME>(GetParam())),
+ mInputGain(std::get<INPUT_GAIN_PARAM>(GetParam())){};
+
+ void SetUp() override { SetUpDynamicsProcessingEffect(); }
+
+ void TearDown() override { TearDownDynamicsProcessingEffect(); }
+
+ const std::vector<DynamicsProcessing::InputGain> mInputGain;
+};
+
+TEST_P(DynamicsProcessingTestInputGain, SetAndGetInputGain) {
+ EXPECT_NO_FATAL_FAILURE(addInputGain(mInputGain));
+ SetAndGetDynamicsProcessingParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ DynamicsProcessingTest, DynamicsProcessingTestInputGain,
+ ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+ IFactory::descriptor, kDynamicsProcessingTypeUUID)),
+ testing::ValuesIn(DynamicsProcessingTestInputGain::kInputGainTestSet)),
+ [](const auto& info) {
+ auto descriptor = std::get<INPUT_GAIN_INSTANCE_NAME>(info.param).second;
+ std::string gains =
+ ::android::internal::ToString(std::get<INPUT_GAIN_PARAM>(info.param));
+ std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+ descriptor.common.name + "_UUID_" +
+ descriptor.common.id.uuid.toString() + "_inputGains_" + gains;
+ std::replace_if(
+ name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+ return name;
+ });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingTestInputGain);
+
+/**
+ * Test DynamicsProcessing Limiter Config
+ */
+enum LimiterConfigTestParamName {
+ LIMITER_INSTANCE_NAME,
+ LIMITER_CHANNEL,
+ LIMITER_ENABLE,
+ LIMITER_LINK_GROUP,
+ LIMITER_ENGINE_IN_USE,
+ LIMITER_ADDITIONAL,
+};
+enum LimiterConfigTestAdditionalParam {
+ LIMITER_ATTACK_TIME,
+ LIMITER_RELEASE_TIME,
+ LIMITER_RATIO,
+ LIMITER_THRESHOLD,
+ LIMITER_POST_GAIN,
+ LIMITER_MAX_NUM,
+};
+using LimiterConfigTestAdditional = std::array<float, LIMITER_MAX_NUM>;
+// attachTime, releaseTime, ratio, thresh, postGain
+static constexpr std::array<LimiterConfigTestAdditional, 4> kLimiterConfigTestAdditionalParam = {
+ {{-1, -60, -2.5, -2, -3.14},
+ {-1, 60, -2.5, 2, -3.14},
+ {1, -60, 2.5, -2, 3.14},
+ {1, 60, 2.5, 2, 3.14}}};
+
+using LimiterConfigTestParams =
+ std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int32_t, bool, int32_t, bool,
+ LimiterConfigTestAdditional>;
+
+void fillLimiterConfig(DynamicsProcessing::LimiterConfig& cfg,
+ const LimiterConfigTestParams& params) {
+ const std::array<float, LIMITER_MAX_NUM> additional = std::get<LIMITER_ADDITIONAL>(params);
+ cfg.channel = std::get<LIMITER_CHANNEL>(params);
+ cfg.enable = std::get<LIMITER_ENABLE>(params);
+ cfg.linkGroup = std::get<LIMITER_LINK_GROUP>(params);
+ cfg.attackTimeMs = additional[LIMITER_ATTACK_TIME];
+ cfg.releaseTimeMs = additional[LIMITER_RELEASE_TIME];
+ cfg.ratio = additional[LIMITER_RATIO];
+ cfg.thresholdDb = additional[LIMITER_THRESHOLD];
+ cfg.postGainDb = additional[LIMITER_POST_GAIN];
+}
+
+class DynamicsProcessingTestLimiterConfig
+ : public ::testing::TestWithParam<LimiterConfigTestParams>,
+ public DynamicsProcessingTestHelper {
+ public:
+ DynamicsProcessingTestLimiterConfig()
+ : DynamicsProcessingTestHelper(std::get<LIMITER_INSTANCE_NAME>(GetParam())),
+ mLimiterInUseEngine(std::get<LIMITER_ENGINE_IN_USE>(GetParam())) {
+ fillLimiterConfig(mCfg, GetParam());
+ }
+
+ void SetUp() override { SetUpDynamicsProcessingEffect(); }
+
+ void TearDown() override { TearDownDynamicsProcessingEffect(); }
+
+ DynamicsProcessing::LimiterConfig mCfg;
+ bool mLimiterInUseEngine;
+};
+
+TEST_P(DynamicsProcessingTestLimiterConfig, SetAndGetLimiterConfig) {
+ mEngineConfigPreset.limiterInUse = mLimiterInUseEngine;
+ EXPECT_NO_FATAL_FAILURE(addEngineConfig(mEngineConfigPreset));
+ EXPECT_NO_FATAL_FAILURE(addLimiterConfig({mCfg}));
+ SetAndGetDynamicsProcessingParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ DynamicsProcessingTest, DynamicsProcessingTestLimiterConfig,
+ ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+ IFactory::descriptor, kDynamicsProcessingTypeUUID)),
+ testing::Values(-1, 0, 1, 2), // channel count
+ testing::Bool(), // enable
+ testing::Values(3), // link group
+ testing::Bool(), // engine limiter enable
+ testing::ValuesIn(kLimiterConfigTestAdditionalParam)), // Additional
+ [](const auto& info) {
+ auto descriptor = std::get<LIMITER_INSTANCE_NAME>(info.param).second;
+ DynamicsProcessing::LimiterConfig cfg;
+ fillLimiterConfig(cfg, info.param);
+ std::string engineLimiterInUse =
+ std::to_string(std::get<LIMITER_ENGINE_IN_USE>(info.param));
+ std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+ descriptor.common.name + "_UUID_" +
+ descriptor.common.id.uuid.toString() + "_limiterConfig_" +
+ cfg.toString() + "_engineSetting_" + engineLimiterInUse;
+ std::replace_if(
+ name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+ return name;
+ });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingTestLimiterConfig);
+
+/**
+ * Test DynamicsProcessing ChannelConfig
+ */
+enum ChannelConfigTestParamName {
+ BAND_CHANNEL_TEST_INSTANCE_NAME,
+ BAND_CHANNEL_TEST_CHANNEL_CONFIG,
+ BAND_CHANNEL_TEST_ENGINE_IN_USE
+};
+using ChannelConfigTestParams = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>,
+ std::vector<DynamicsProcessing::ChannelConfig>, bool>;
+
+class DynamicsProcessingTestChannelConfig
+ : public ::testing::TestWithParam<ChannelConfigTestParams>,
+ public DynamicsProcessingTestHelper {
+ public:
+ DynamicsProcessingTestChannelConfig()
+ : DynamicsProcessingTestHelper(std::get<BAND_CHANNEL_TEST_INSTANCE_NAME>(GetParam())),
+ mCfg(std::get<BAND_CHANNEL_TEST_CHANNEL_CONFIG>(GetParam())),
+ mInUseEngine(std::get<BAND_CHANNEL_TEST_ENGINE_IN_USE>(GetParam())) {}
+
+ void SetUp() override { SetUpDynamicsProcessingEffect(); }
+
+ void TearDown() override { TearDownDynamicsProcessingEffect(); }
+
+ std::vector<DynamicsProcessing::ChannelConfig> mCfg;
+ const bool mInUseEngine;
+};
+
+TEST_P(DynamicsProcessingTestChannelConfig, SetAndGetPreEqChannelConfig) {
+ mEngineConfigPreset.preEqStage.inUse = mInUseEngine;
+ EXPECT_NO_FATAL_FAILURE(addEngineConfig(mEngineConfigPreset));
+ EXPECT_NO_FATAL_FAILURE(addPreEqChannelConfig(mCfg));
+ SetAndGetDynamicsProcessingParameters();
+}
+
+TEST_P(DynamicsProcessingTestChannelConfig, SetAndGetPostEqChannelConfig) {
+ mEngineConfigPreset.postEqStage.inUse = mInUseEngine;
+ EXPECT_NO_FATAL_FAILURE(addEngineConfig(mEngineConfigPreset));
+ EXPECT_NO_FATAL_FAILURE(addPostEqChannelConfig(mCfg));
+ SetAndGetDynamicsProcessingParameters();
+}
+
+TEST_P(DynamicsProcessingTestChannelConfig, SetAndGetMbcChannelConfig) {
+ mEngineConfigPreset.mbcStage.inUse = mInUseEngine;
+ EXPECT_NO_FATAL_FAILURE(addEngineConfig(mEngineConfigPreset));
+ EXPECT_NO_FATAL_FAILURE(addMbcChannelConfig(mCfg));
+ SetAndGetDynamicsProcessingParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ DynamicsProcessingTest, DynamicsProcessingTestChannelConfig,
+ ::testing::Combine(
+ testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+ IFactory::descriptor, kDynamicsProcessingTypeUUID)),
+ testing::ValuesIn(
+ DynamicsProcessingTestHelper::kChannelConfigTestSet), // channel config
+ testing::Bool()), // Engine inUse
+ [](const auto& info) {
+ auto descriptor = std::get<BAND_CHANNEL_TEST_INSTANCE_NAME>(info.param).second;
+ std::string engineInUse =
+ std::to_string(std::get<BAND_CHANNEL_TEST_ENGINE_IN_USE>(info.param));
+ std::string channelConfig = ::android::internal::ToString(
+ std::get<BAND_CHANNEL_TEST_CHANNEL_CONFIG>(info.param));
+
+ std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+ descriptor.common.name + "_UUID_" +
+ descriptor.common.id.uuid.toString() + "_" + channelConfig +
+ "_engineInUse_" + engineInUse;
+ std::replace_if(
+ name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+ return name;
+ });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingTestChannelConfig);
+
+/**
+ * Test DynamicsProcessing EqBandConfig
+ */
+enum EqBandConfigTestParamName {
+ EQ_BAND_INSTANCE_NAME,
+ EQ_BAND_CHANNEL,
+ EQ_BAND_CHANNEL_ENABLE,
+ EQ_BAND_ENABLE,
+ EQ_BAND_CUT_OFF_FREQ,
+ EQ_BAND_GAIN,
+ EQ_BAND_STAGE_IN_USE
+};
+using EqBandConfigTestParams = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int32_t,
+ std::vector<DynamicsProcessing::ChannelConfig>, bool,
+ std::vector<std::pair<int, float>>, float, bool>;
+
+void fillEqBandConfig(std::vector<DynamicsProcessing::EqBandConfig>& cfgs,
+ const EqBandConfigTestParams& params) {
+ const std::vector<std::pair<int, float>> cutOffFreqs = std::get<EQ_BAND_CUT_OFF_FREQ>(params);
+ int bandCount = cutOffFreqs.size();
+ cfgs.resize(bandCount);
+ for (int i = 0; i < bandCount; i++) {
+ cfgs[i].channel = std::get<EQ_BAND_CHANNEL>(params);
+ cfgs[i].band = cutOffFreqs[i].first;
+ cfgs[i].enable = std::get<EQ_BAND_ENABLE>(params);
+ cfgs[i].cutoffFrequencyHz = cutOffFreqs[i].second;
+ cfgs[i].gainDb = std::get<EQ_BAND_GAIN>(params);
+ }
+}
+
+class DynamicsProcessingTestEqBandConfig : public ::testing::TestWithParam<EqBandConfigTestParams>,
+ public DynamicsProcessingTestHelper {
+ public:
+ DynamicsProcessingTestEqBandConfig()
+ : DynamicsProcessingTestHelper(std::get<EQ_BAND_INSTANCE_NAME>(GetParam())),
+ mStageInUse(std::get<EQ_BAND_STAGE_IN_USE>(GetParam())),
+ mChannelConfig(std::get<EQ_BAND_CHANNEL_ENABLE>(GetParam())) {
+ fillEqBandConfig(mCfgs, GetParam());
+ }
+
+ void SetUp() override { SetUpDynamicsProcessingEffect(); }
+
+ void TearDown() override { TearDownDynamicsProcessingEffect(); }
+
+ std::vector<DynamicsProcessing::EqBandConfig> mCfgs;
+ const bool mStageInUse;
+ const std::vector<DynamicsProcessing::ChannelConfig> mChannelConfig;
+};
+
+TEST_P(DynamicsProcessingTestEqBandConfig, SetAndGetPreEqBandConfig) {
+ mEngineConfigPreset.preEqStage.inUse = mStageInUse;
+ mEngineConfigPreset.preEqStage.bandCount = mCfgs.size();
+ EXPECT_NO_FATAL_FAILURE(addEngineConfig(mEngineConfigPreset));
+ EXPECT_NO_FATAL_FAILURE(addPreEqChannelConfig(mChannelConfig));
+ EXPECT_NO_FATAL_FAILURE(addPreEqBandConfigs(mCfgs));
+ SetAndGetDynamicsProcessingParameters();
+}
+
+TEST_P(DynamicsProcessingTestEqBandConfig, SetAndGetPostEqBandConfig) {
+ mEngineConfigPreset.postEqStage.inUse = mStageInUse;
+ mEngineConfigPreset.postEqStage.bandCount = mCfgs.size();
+ EXPECT_NO_FATAL_FAILURE(addEngineConfig(mEngineConfigPreset));
+ EXPECT_NO_FATAL_FAILURE(addPostEqChannelConfig(mChannelConfig));
+ EXPECT_NO_FATAL_FAILURE(addPostEqBandConfigs(mCfgs));
+ SetAndGetDynamicsProcessingParameters();
+}
+
+std::vector<std::vector<std::pair<int, float>>> kBands{
+ {
+ {0, 600},
+ {1, 2000},
+ {2, 6000},
+ {3, 10000},
+ {4, 16000},
+ }, // 5 bands
+ {
+ {0, 800},
+ {3, 15000},
+ {2, 6000},
+ {1, 2000},
+ }, // 4 bands, unsorted
+ {
+ {0, 650},
+ {1, 2000},
+ {2, 6000},
+ {3, 10000},
+ {3, 16000},
+ }, // 5 bands, missing band
+ {
+ {0, 900},
+ {1, 8000},
+ {2, 4000},
+ {3, 12000},
+ }, // 4 bands, cutoff freq not increasing
+ {
+ {0, 450},
+ {1, 2000},
+ {7, 6000},
+ {3, 10000},
+ {4, 16000},
+ }, // bad band index
+ {
+ {0, 1},
+ {1, 8000},
+ }, // too low cutoff freq
+ {
+ {0, 1200},
+ {1, 80000},
+ }, // too high cutoff freq
+};
+
+INSTANTIATE_TEST_SUITE_P(
+ DynamicsProcessingTest, DynamicsProcessingTestEqBandConfig,
+ ::testing::Combine(
+ testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+ IFactory::descriptor, kDynamicsProcessingTypeUUID)),
+ testing::Values(-1, 0, 10), // channel ID
+ testing::ValuesIn(
+ DynamicsProcessingTestHelper::kChannelConfigTestSet), // channel enable
+ testing::Bool(), // band enable
+ testing::ValuesIn(kBands), // cut off frequencies
+ testing::Values(-3.14f, 3.14f), // gain
+ testing::Bool()), // stage in use
+ [](const auto& info) {
+ auto descriptor = std::get<EQ_BAND_INSTANCE_NAME>(info.param).second;
+ std::vector<DynamicsProcessing::EqBandConfig> cfgs;
+ fillEqBandConfig(cfgs, info.param);
+ std::string enable =
+ ::android::internal::ToString(std::get<EQ_BAND_CHANNEL_ENABLE>(info.param));
+ std::string bands = ::android::internal::ToString(cfgs);
+ std::string stageInUse = std::to_string(std::get<EQ_BAND_STAGE_IN_USE>(info.param));
+ std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+ descriptor.common.name + "_UUID_" +
+ descriptor.common.id.uuid.toString() + "_" + enable + "_bands_" +
+ bands + "_stageInUse_" + stageInUse;
+ std::replace_if(
+ name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+ return name;
+ });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingTestEqBandConfig);
+
+/**
+ * Test DynamicsProcessing MbcBandConfig
+ */
+
+enum MbcBandConfigParamName {
+ MBC_BAND_INSTANCE_NAME,
+ MBC_BAND_CHANNEL,
+ MBC_BAND_CHANNEL_CONFIG,
+ MBC_BAND_ENABLE,
+ MBC_BAND_CUTOFF_FREQ,
+ MBC_BAND_STAGE_IN_USE,
+ MBC_BAND_ADDITIONAL
+};
+enum MbcBandConfigAdditional {
+ MBC_ADD_ATTACK_TIME,
+ MBC_ADD_RELEASE_TIME,
+ MBC_ADD_RATIO,
+ MBC_ADD_THRESHOLD,
+ MBC_ADD_KNEE_WIDTH,
+ MBC_ADD_NOISE_GATE_THRESHOLD,
+ MBC_ADD_EXPENDER_RATIO,
+ MBC_ADD_PRE_GAIN,
+ MBC_ADD_POST_GAIN,
+ MBC_ADD_MAX_NUM
+};
+using TestParamsMbcBandConfigAdditional = std::array<float, MBC_ADD_MAX_NUM>;
+
+// attachTime, releaseTime, ratio, thresh, kneeWidth, noise, expander, preGain, postGain
+static constexpr std::array<TestParamsMbcBandConfigAdditional, 4> kMbcBandConfigAdditionalParam = {
+ {{-3, -10, -2, -2, -5, -90, -2.5, -2, -2},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {-3, 10, -2, 2, -5, 90, -2.5, 2, -2},
+ {3, 10, 2, 2, 5, 90, 2.5, 2, 2}}};
+
+using TestParamsMbcBandConfig =
+ std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int32_t,
+ std::vector<DynamicsProcessing::ChannelConfig>, bool,
+ std::vector<std::pair<int, float>>, bool, TestParamsMbcBandConfigAdditional>;
+
+void fillMbcBandConfig(std::vector<DynamicsProcessing::MbcBandConfig>& cfgs,
+ const TestParamsMbcBandConfig& params) {
+ const std::vector<std::pair<int, float>> cutOffFreqs = std::get<MBC_BAND_CUTOFF_FREQ>(params);
+ const std::array<float, MBC_ADD_MAX_NUM> additional = std::get<MBC_BAND_ADDITIONAL>(params);
+ int bandCount = cutOffFreqs.size();
+ cfgs.resize(bandCount);
+ for (int i = 0; i < bandCount; i++) {
+ cfgs[i] = DynamicsProcessing::MbcBandConfig{
+ .channel = std::get<MBC_BAND_CHANNEL>(params),
+ .band = cutOffFreqs[i].first,
+ .enable = std::get<MBC_BAND_ENABLE>(params),
+ .cutoffFrequencyHz = cutOffFreqs[i].second,
+ .attackTimeMs = additional[MBC_ADD_ATTACK_TIME],
+ .releaseTimeMs = additional[MBC_ADD_RELEASE_TIME],
+ .ratio = additional[MBC_ADD_RATIO],
+ .thresholdDb = additional[MBC_ADD_THRESHOLD],
+ .kneeWidthDb = additional[MBC_ADD_KNEE_WIDTH],
+ .noiseGateThresholdDb = additional[MBC_ADD_NOISE_GATE_THRESHOLD],
+ .expanderRatio = additional[MBC_ADD_EXPENDER_RATIO],
+ .preGainDb = additional[MBC_ADD_PRE_GAIN],
+ .postGainDb = additional[MBC_ADD_POST_GAIN]};
+ }
+}
+
+class DynamicsProcessingTestMbcBandConfig
+ : public ::testing::TestWithParam<TestParamsMbcBandConfig>,
+ public DynamicsProcessingTestHelper {
+ public:
+ DynamicsProcessingTestMbcBandConfig()
+ : DynamicsProcessingTestHelper(std::get<MBC_BAND_INSTANCE_NAME>(GetParam())),
+ mStageInUse(std::get<MBC_BAND_STAGE_IN_USE>(GetParam())),
+ mChannelConfig(std::get<MBC_BAND_CHANNEL_CONFIG>(GetParam())) {
+ fillMbcBandConfig(mCfgs, GetParam());
+ }
+
+ void SetUp() override { SetUpDynamicsProcessingEffect(); }
+
+ void TearDown() override { TearDownDynamicsProcessingEffect(); }
+
+ std::vector<DynamicsProcessing::MbcBandConfig> mCfgs;
+ const bool mStageInUse;
+ const std::vector<DynamicsProcessing::ChannelConfig> mChannelConfig;
+};
+
+TEST_P(DynamicsProcessingTestMbcBandConfig, SetAndGetMbcBandConfig) {
+ mEngineConfigPreset.mbcStage.inUse = mStageInUse;
+ mEngineConfigPreset.mbcStage.bandCount = mCfgs.size();
+ EXPECT_NO_FATAL_FAILURE(addEngineConfig(mEngineConfigPreset));
+ EXPECT_NO_FATAL_FAILURE(addMbcChannelConfig(mChannelConfig));
+ EXPECT_NO_FATAL_FAILURE(addMbcBandConfigs(mCfgs));
+ SetAndGetDynamicsProcessingParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ DynamicsProcessingTest, DynamicsProcessingTestMbcBandConfig,
+ ::testing::Combine(
+ testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+ IFactory::descriptor, kDynamicsProcessingTypeUUID)),
+ testing::Values(-1, 0, 10), // channel count
+ testing::ValuesIn(
+ DynamicsProcessingTestHelper::kChannelConfigTestSet), // channel config
+ testing::Bool(), // enable
+ testing::ValuesIn(kBands), // cut off frequencies
+ testing::Bool(), // stage in use
+ testing::ValuesIn(kMbcBandConfigAdditionalParam)), // Additional
+ [](const auto& info) {
+ auto descriptor = std::get<MBC_BAND_INSTANCE_NAME>(info.param).second;
+ std::vector<DynamicsProcessing::MbcBandConfig> cfgs;
+ fillMbcBandConfig(cfgs, info.param);
+ std::string enable =
+ ::android::internal::ToString(std::get<MBC_BAND_CHANNEL_CONFIG>(info.param));
+ std::string mbcBands = ::android::internal::ToString(cfgs);
+ std::string stageInUse = std::to_string(std::get<MBC_BAND_STAGE_IN_USE>(info.param));
+ std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+ descriptor.common.name + "_UUID_" +
+ descriptor.common.id.uuid.toString() + "_enable_" + enable +
+ "_bands_" + mbcBands + "_stageInUse_" + stageInUse;
+ std::replace_if(
+ name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+ return name;
+ });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingTestMbcBandConfig);
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ ABinderProcess_setThreadPoolMaxThreadCount(1);
+ ABinderProcess_startThreadPool();
+ return RUN_ALL_TESTS();
+}
diff --git a/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp b/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp
index d1f3b97..b8ea9c1 100644
--- a/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp
@@ -19,7 +19,9 @@
#include <Utils.h>
#include <aidl/Vintf.h>
#include <android/binder_enums.h>
-#include <unordered_set>
+#include <map>
+#include <utility>
+#include <vector>
#include "EffectHelper.h"
@@ -87,12 +89,11 @@
ASSERT_NE(nullptr, mFactory);
ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
- Parameter::Specific specific = getDefaultParamSpecific();
Parameter::Common common = EffectHelper::createParamCommon(
0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
IEffect::OpenEffectReturn ret;
- ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &ret, EX_NONE));
+ ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt, &ret, EX_NONE));
ASSERT_NE(nullptr, mEffect);
}
@@ -101,15 +102,6 @@
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
}
- Parameter::Specific getDefaultParamSpecific() {
- HapticGenerator::HapticScale hapticScale = {.id = 0,
- .scale = HapticGenerator::VibratorScale::MUTE};
- HapticGenerator hg = HapticGenerator::make<HapticGenerator::hapticScale>(hapticScale);
- Parameter::Specific specific =
- Parameter::Specific::make<Parameter::Specific::hapticGenerator>(hg);
- return specific;
- }
-
static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
std::shared_ptr<IFactory> mFactory;
std::shared_ptr<IEffect> mEffect;
@@ -122,13 +114,13 @@
void SetAndGetHapticGeneratorParameters() {
for (auto& it : mTags) {
- auto& tag = it.first;
- auto& hg = it.second;
+ auto& tag = std::get<ParamTestEnum::PARAM_TEST_TAG>(it);
+ auto& setHg = std::get<ParamTestEnum::PARAM_TEST_TARGET>(it);
// set parameter
Parameter expectParam;
Parameter::Specific specific;
- specific.set<Parameter::Specific::hapticGenerator>(hg);
+ specific.set<Parameter::Specific::hapticGenerator>(setHg);
expectParam.set<Parameter::specific>(specific);
EXPECT_STATUS(EX_NONE, mEffect->setParameter(expectParam)) << expectParam.toString();
@@ -139,15 +131,16 @@
hgId.set<HapticGenerator::Id::commonTag>(tag);
id.set<Parameter::Id::hapticGeneratorTag>(hgId);
EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &getParam));
- EXPECT_EQ(expectParam, getParam);
+ EXPECT_EQ(expectParam, getParam) << expectParam.toString() << "\n"
+ << getParam.toString();
}
}
void addHapticScaleParam(int id, HapticGenerator::VibratorScale scale) {
- HapticGenerator hg;
- HapticGenerator::HapticScale hapticScale = {.id = id, .scale = scale};
- hg.set<HapticGenerator::hapticScale>(hapticScale);
- mTags.push_back({HapticGenerator::hapticScale, hg});
+ HapticGenerator setHg;
+ std::vector<HapticGenerator::HapticScale> hapticScales = {{.id = id, .scale = scale}};
+ setHg.set<HapticGenerator::hapticScales>(hapticScales);
+ mTags.push_back({HapticGenerator::hapticScales, setHg});
}
void addVibratorInformationParam(float resonantFrequencyHz, float qFactor, float maxAmplitude) {
@@ -161,7 +154,8 @@
}
private:
- std::vector<std::pair<HapticGenerator::Tag, HapticGenerator>> mTags;
+ enum ParamTestEnum { PARAM_TEST_TAG, PARAM_TEST_TARGET };
+ std::vector<std::tuple<HapticGenerator::Tag, HapticGenerator>> mTags;
void CleanUp() { mTags.clear(); }
};
@@ -171,6 +165,12 @@
SetAndGetHapticGeneratorParameters();
}
+TEST_P(HapticGeneratorParamTest, SetAndGetMultipleHapticScales) {
+ EXPECT_NO_FATAL_FAILURE(addHapticScaleParam(mParamHapticScaleId, mParamVibratorScale));
+ EXPECT_NO_FATAL_FAILURE(addHapticScaleParam(mParamHapticScaleId, mParamVibratorScale));
+ SetAndGetHapticGeneratorParameters();
+}
+
TEST_P(HapticGeneratorParamTest, SetAndGetVibratorInformation) {
EXPECT_NO_FATAL_FAILURE(addVibratorInformationParam(mParamResonantFrequency, mParamQFactor,
mParamMaxAmplitude));
@@ -212,7 +212,7 @@
::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
IFactory::descriptor, kHapticGeneratorTypeUUID)),
testing::Values(MIN_ID - 1),
- testing::Values(HapticGenerator::VibratorScale::MUTE),
+ testing::Values(HapticGenerator::VibratorScale::NONE),
testing::Values(MIN_FLOAT), testing::Values(MIN_FLOAT),
testing::Values(MIN_FLOAT)),
[](const testing::TestParamInfo<HapticGeneratorParamTest::ParamType>& info) {
@@ -236,9 +236,202 @@
name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
return name;
});
-
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(HapticGeneratorParamTest);
+// Test HapticScale[] hapticScales parameter
+using HapticGeneratorScalesTestParam = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>>;
+class HapticGeneratorScalesTest : public ::testing::TestWithParam<HapticGeneratorScalesTestParam>,
+ public EffectHelper {
+ public:
+ HapticGeneratorScalesTest() {
+ std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
+ }
+
+ void SetUp() override {
+ ASSERT_NE(nullptr, mFactory);
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+
+ Parameter::Common common = EffectHelper::createParamCommon(
+ 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
+ kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
+ IEffect::OpenEffectReturn ret;
+ ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt, &ret, EX_NONE));
+ ASSERT_NE(nullptr, mEffect);
+ }
+
+ void TearDown() override {
+ ASSERT_NO_FATAL_FAILURE(close(mEffect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+ CleanUp();
+ }
+
+ static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+ std::shared_ptr<IFactory> mFactory;
+ std::shared_ptr<IEffect> mEffect;
+ Descriptor mDescriptor;
+
+ void addHapticScaleParam(std::vector<HapticGenerator::HapticScale> scales) {
+ mHapticScales.push_back(HapticGenerator::make<HapticGenerator::hapticScales>(scales));
+ for (const auto& scale : scales) {
+ expectMap.insert_or_assign(scale.id, scale.scale);
+ }
+ }
+
+ void SetHapticScaleParameters() {
+ // std::unordered_set<HapticGenerator::HapticScale> target;
+ for (auto& it : mHapticScales) {
+ Parameter::Specific specific =
+ Parameter::Specific::make<Parameter::Specific::hapticGenerator>(it);
+ Parameter param = Parameter::make<Parameter::specific>(specific);
+ EXPECT_STATUS(EX_NONE, mEffect->setParameter(param)) << param.toString();
+ }
+ }
+
+ void checkHapticScaleParameter() {
+ // get parameter
+ Parameter targetParam;
+ HapticGenerator::Id hgId = HapticGenerator::Id::make<HapticGenerator::Id::commonTag>(
+ HapticGenerator::hapticScales);
+ Parameter::Id id = Parameter::Id::make<Parameter::Id::hapticGeneratorTag>(hgId);
+ EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &targetParam));
+ ASSERT_EQ(Parameter::specific, targetParam.getTag());
+ Parameter::Specific specific = targetParam.get<Parameter::specific>();
+ ASSERT_EQ(Parameter::Specific::hapticGenerator, specific.getTag());
+ HapticGenerator hg = specific.get<Parameter::Specific::hapticGenerator>();
+ ASSERT_EQ(HapticGenerator::hapticScales, hg.getTag());
+ std::vector<HapticGenerator::HapticScale> scales = hg.get<HapticGenerator::hapticScales>();
+ ASSERT_EQ(scales.size(), expectMap.size());
+ for (const auto& scale : scales) {
+ auto itor = expectMap.find(scale.id);
+ ASSERT_NE(expectMap.end(), itor);
+ ASSERT_EQ(scale.scale, itor->second);
+ expectMap.erase(scale.id);
+ }
+ ASSERT_EQ(0ul, expectMap.size());
+ }
+
+ const static HapticGenerator::HapticScale kHapticScaleWithMinId;
+ const static HapticGenerator::HapticScale kHapticScaleWithMinIdNew;
+ const static HapticGenerator::HapticScale kHapticScale;
+ const static HapticGenerator::HapticScale kHapticScaleNew;
+ const static HapticGenerator::HapticScale kHapticScaleWithMaxId;
+ const static HapticGenerator::HapticScale kHapticScaleWithMaxIdNew;
+
+ std::vector<HapticGenerator> mHapticScales;
+
+ void CleanUp() {
+ mHapticScales.clear();
+ expectMap.clear();
+ }
+
+ private:
+ std::map<int /* trackID */, HapticGenerator::VibratorScale> expectMap;
+};
+
+const HapticGenerator::HapticScale HapticGeneratorScalesTest::kHapticScaleWithMinId = {
+ .id = MIN_ID, .scale = HapticGenerator::VibratorScale::MUTE};
+const HapticGenerator::HapticScale HapticGeneratorScalesTest::kHapticScaleWithMinIdNew = {
+ .id = MIN_ID, .scale = HapticGenerator::VibratorScale::VERY_LOW};
+const HapticGenerator::HapticScale HapticGeneratorScalesTest::kHapticScale = {
+ .id = 1, .scale = HapticGenerator::VibratorScale::LOW};
+const HapticGenerator::HapticScale HapticGeneratorScalesTest::kHapticScaleNew = {
+ .id = 1, .scale = HapticGenerator::VibratorScale::NONE};
+const HapticGenerator::HapticScale HapticGeneratorScalesTest::kHapticScaleWithMaxId = {
+ .id = MAX_ID, .scale = HapticGenerator::VibratorScale::VERY_HIGH};
+const HapticGenerator::HapticScale HapticGeneratorScalesTest::kHapticScaleWithMaxIdNew = {
+ .id = MAX_ID, .scale = HapticGenerator::VibratorScale::MUTE};
+
+TEST_P(HapticGeneratorScalesTest, SetAndUpdateOne) {
+ EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScale}));
+ EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+ EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScaleNew}));
+ EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+
+ EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScaleWithMinId}));
+ EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+ EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScaleWithMinIdNew}));
+ EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+
+ EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScaleWithMaxId}));
+ EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+ EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScaleWithMaxIdNew}));
+ EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+
+ EXPECT_NO_FATAL_FAILURE(checkHapticScaleParameter());
+}
+
+TEST_P(HapticGeneratorScalesTest, SetAndUpdateVector) {
+ EXPECT_NO_FATAL_FAILURE(
+ addHapticScaleParam({kHapticScale, kHapticScaleWithMaxId, kHapticScaleWithMinId}));
+ EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+ EXPECT_NO_FATAL_FAILURE(addHapticScaleParam(
+ {kHapticScaleNew, kHapticScaleWithMaxIdNew, kHapticScaleWithMinIdNew}));
+ EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+
+ EXPECT_NO_FATAL_FAILURE(checkHapticScaleParameter());
+}
+
+TEST_P(HapticGeneratorScalesTest, SetAndUpdateMultipleVector) {
+ EXPECT_NO_FATAL_FAILURE(
+ addHapticScaleParam({kHapticScale, kHapticScaleWithMaxId, kHapticScaleWithMinId}));
+ EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+ EXPECT_NO_FATAL_FAILURE(addHapticScaleParam(
+ {kHapticScaleNew, kHapticScaleWithMaxIdNew, kHapticScaleWithMinIdNew}));
+ EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+ EXPECT_NO_FATAL_FAILURE(
+ addHapticScaleParam({kHapticScale, kHapticScaleWithMaxId, kHapticScaleWithMinId}));
+ EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+
+ EXPECT_NO_FATAL_FAILURE(checkHapticScaleParameter());
+}
+
+TEST_P(HapticGeneratorScalesTest, SetOneAndAddMoreVector) {
+ EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScale}));
+ EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+ EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScaleWithMaxId, kHapticScaleWithMinId}));
+ EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+
+ EXPECT_NO_FATAL_FAILURE(checkHapticScaleParameter());
+}
+
+TEST_P(HapticGeneratorScalesTest, SetMultipleAndAddOneVector) {
+ EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScaleWithMaxId, kHapticScaleWithMinId}));
+ EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+ EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScale}));
+ EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+
+ EXPECT_NO_FATAL_FAILURE(checkHapticScaleParameter());
+}
+
+TEST_P(HapticGeneratorScalesTest, SetMultipleVectorRepeat) {
+ EXPECT_NO_FATAL_FAILURE(
+ addHapticScaleParam({kHapticScaleWithMaxId, kHapticScale, kHapticScaleWithMinId}));
+ EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+ EXPECT_NO_FATAL_FAILURE(
+ addHapticScaleParam({kHapticScaleWithMaxId, kHapticScale, kHapticScaleWithMinId}));
+ EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+ EXPECT_NO_FATAL_FAILURE(
+ addHapticScaleParam({kHapticScaleWithMaxId, kHapticScale, kHapticScaleWithMinId}));
+ EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+
+ EXPECT_NO_FATAL_FAILURE(checkHapticScaleParameter());
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ HapticGeneratorScalesTest, HapticGeneratorScalesTest,
+ ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+ IFactory::descriptor, kHapticGeneratorTypeUUID))),
+ [](const testing::TestParamInfo<HapticGeneratorScalesTest::ParamType>& info) {
+ auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
+ std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+ descriptor.common.name + "_UUID_" +
+ descriptor.common.id.uuid.toString();
+ std::replace_if(
+ name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+ return name;
+ });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(HapticGeneratorScalesTest);
+
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
ABinderProcess_setThreadPoolMaxThreadCount(1);
diff --git a/audio/common/7.0/enums/OWNERS b/audio/common/7.0/enums/OWNERS
deleted file mode 100644
index 24071af..0000000
--- a/audio/common/7.0/enums/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-elaurent@google.com
-mnaganov@google.com
diff --git a/audio/common/7.0/example/OWNERS b/audio/common/7.0/example/OWNERS
deleted file mode 100644
index 24071af..0000000
--- a/audio/common/7.0/example/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-elaurent@google.com
-mnaganov@google.com
diff --git a/audio/common/7.1/enums/OWNERS b/audio/common/7.1/enums/OWNERS
deleted file mode 100644
index 24071af..0000000
--- a/audio/common/7.1/enums/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-elaurent@google.com
-mnaganov@google.com
diff --git a/audio/common/all-versions/OWNERS b/audio/common/all-versions/OWNERS
deleted file mode 100644
index 24071af..0000000
--- a/audio/common/all-versions/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-elaurent@google.com
-mnaganov@google.com
diff --git a/audio/common/all-versions/default/OWNERS b/audio/common/all-versions/default/OWNERS
deleted file mode 100644
index 24071af..0000000
--- a/audio/common/all-versions/default/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-elaurent@google.com
-mnaganov@google.com
diff --git a/audio/core/all-versions/OWNERS b/audio/core/all-versions/OWNERS
deleted file mode 100644
index f9a2d6b..0000000
--- a/audio/core/all-versions/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 48436
-elaurent@google.com
-mnaganov@google.com
diff --git a/audio/core/all-versions/vts/functional/OWNERS b/audio/core/all-versions/vts/functional/OWNERS
deleted file mode 100644
index 448d9fe..0000000
--- a/audio/core/all-versions/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 48436
-mnaganov@google.com
diff --git a/audio/effect/all-versions/OWNERS b/audio/effect/all-versions/OWNERS
deleted file mode 100644
index f9a2d6b..0000000
--- a/audio/effect/all-versions/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 48436
-elaurent@google.com
-mnaganov@google.com
diff --git a/audio/effect/all-versions/vts/functional/OWNERS b/audio/effect/all-versions/vts/functional/OWNERS
deleted file mode 100644
index 448d9fe..0000000
--- a/audio/effect/all-versions/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 48436
-mnaganov@google.com
diff --git a/audio/policy/1.0/vts/OWNERS b/audio/policy/1.0/vts/OWNERS
deleted file mode 100644
index 24071af..0000000
--- a/audio/policy/1.0/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-elaurent@google.com
-mnaganov@google.com
diff --git a/audio/policy/1.0/vts/functional/OWNERS b/audio/policy/1.0/vts/functional/OWNERS
deleted file mode 100644
index 448d9fe..0000000
--- a/audio/policy/1.0/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 48436
-mnaganov@google.com
diff --git a/automotive/audiocontrol/aidl/default/audiocontrol-default.xml b/automotive/audiocontrol/aidl/default/audiocontrol-default.xml
index e82f6fa..3452ae9 100644
--- a/automotive/audiocontrol/aidl/default/audiocontrol-default.xml
+++ b/automotive/audiocontrol/aidl/default/audiocontrol-default.xml
@@ -1,5 +1,6 @@
<manifest version="2.0" type="device">
<hal format="aidl">
+ <version>2</version>
<name>android.hardware.automotive.audiocontrol</name>
<fqname>IAudioControl/default</fqname>
</hal>
diff --git a/automotive/can/aidl/default/tools/configurator/canprototools.cpp b/automotive/can/aidl/default/tools/configurator/canprototools.cpp
index 2aea315..84edd94 100644
--- a/automotive/can/aidl/default/tools/configurator/canprototools.cpp
+++ b/automotive/can/aidl/default/tools/configurator/canprototools.cpp
@@ -51,15 +51,20 @@
return std::string(buff, 0, std::min(n, got));
}
-std::optional<CanBusConfig> parseConfigFile(const std::string& filepath) {
- std::ifstream cfg_stream(filepath);
-
- // text headers that would be present in a plaintext proto config file.
+/*
+ parseConfigFile *used to* contain the body of parseConfigStream. However, it seems there's some
+ sort of odd behavior with IstreamInputStream and/or TextFormat::Parse, which causes HW Address
+ Sanitizer to flag a "tag-mismatch" in this function. Having the ifstream defined in a wrapper
+ function seems to solve this problem. The exact cause of this problem is yet unknown, but probably
+ lies somewhere in the protobuf implementation.
+*/
+static __attribute__((noinline)) std::optional<CanBusConfig> parseConfigStream(
+ std::ifstream& cfg_stream) {
static const std::array<std::string, 3> text_headers = {"buses", "#", "controller"};
auto cfg_file_snippet = readString(cfg_stream, 10);
if (!cfg_file_snippet.has_value()) {
- LOG(ERROR) << "Can't open " << filepath << " for reading";
+ LOG(ERROR) << "Can't read config from stream (maybe failed to open file?)";
return std::nullopt;
}
cfg_stream.seekg(0);
@@ -77,16 +82,25 @@
if (text_format) {
google::protobuf::io::IstreamInputStream pb_stream(&cfg_stream);
if (!google::protobuf::TextFormat::Parse(&pb_stream, &config)) {
- LOG(ERROR) << "Failed to parse (text format) " << filepath;
+ LOG(ERROR) << "Parsing text format config failed";
return std::nullopt;
}
} else if (!config.ParseFromIstream(&cfg_stream)) {
- LOG(ERROR) << "Failed to parse (binary format) " << filepath;
+ LOG(ERROR) << "Parsing binary format config failed";
return std::nullopt;
}
return config;
}
+std::optional<CanBusConfig> parseConfigFile(const std::string& filepath) {
+ std::ifstream cfg_stream(filepath);
+ auto cfg_maybe = parseConfigStream(cfg_stream);
+ if (!cfg_maybe.has_value()) {
+ LOG(ERROR) << "Failed to parse " << filepath;
+ }
+ return cfg_maybe;
+}
+
std::optional<BusConfig> fromPbBus(const Bus& pb_bus) {
BusConfig bus_cfg = {};
bus_cfg.name = pb_bus.name();
diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal
index 9e4f252..83b0d94 100644
--- a/automotive/vehicle/2.0/types.hal
+++ b/automotive/vehicle/2.0/types.hal
@@ -2117,6 +2117,12 @@
| VehicleArea:SEAT),
/**
+ * DO NOT USE
+ *
+ * This property is defined as type VehicleArea:GLOBAL, which means all seats use the same
+ * value. Use SEAT_HEADREST_HEIGHT_POS_V2 instead which fixes this issue by being defined as
+ * type VehicleArea:SEAT.
+ *
* Headrest height position
*
* Sets the headrest height.
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LocationResponseType.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/EvStoppingMode.aidl
similarity index 87%
copy from radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LocationResponseType.aidl
copy to automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/EvStoppingMode.aidl
index e89a40f..3be8d12 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LocationResponseType.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/EvStoppingMode.aidl
@@ -31,10 +31,11 @@
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
-package android.hardware.radio.network;
-@Backing(type="int") @JavaDerive(toString=true) @VintfStability
-enum LocationResponseType {
- REJECTED = 0,
- ACCEPTED_NO_LOCATION_PROVIDED = 1,
- ACCEPTED_LOCATION_PROVIDED = 2,
+package android.hardware.automotive.vehicle;
+@Backing(type="int") @VintfStability
+enum EvStoppingMode {
+ OTHER = 0,
+ CREEP = 1,
+ ROLL = 2,
+ HOLD = 3,
}
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleProperty.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleProperty.aidl
index c3b3e00..914787e 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleProperty.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleProperty.aidl
@@ -80,6 +80,7 @@
IGNITION_STATE = 289408009,
ABS_ACTIVE = 287310858,
TRACTION_CONTROL_ACTIVE = 287310859,
+ EV_STOPPING_MODE = 289408013,
HVAC_FAN_SPEED = 356517120,
HVAC_FAN_DIRECTION = 356517121,
HVAC_TEMPERATURE_CURRENT = 358614274,
@@ -155,11 +156,14 @@
SEAT_LUMBAR_SIDE_SUPPORT_POS = 356518803,
SEAT_LUMBAR_SIDE_SUPPORT_MOVE = 356518804,
SEAT_HEADREST_HEIGHT_POS = 289409941,
+ SEAT_HEADREST_HEIGHT_POS_V2 = 356518820,
SEAT_HEADREST_HEIGHT_MOVE = 356518806,
SEAT_HEADREST_ANGLE_POS = 356518807,
SEAT_HEADREST_ANGLE_MOVE = 356518808,
SEAT_HEADREST_FORE_AFT_POS = 356518809,
SEAT_HEADREST_FORE_AFT_MOVE = 356518810,
+ SEAT_FOOTWELL_LIGHTS_STATE = 356518811,
+ SEAT_FOOTWELL_LIGHTS_SWITCH = 356518812,
SEAT_EASY_ACCESS_ENABLED = 354421661,
SEAT_AIRBAG_ENABLED = 354421662,
SEAT_CUSHION_SIDE_SUPPORT_POS = 356518815,
@@ -195,6 +199,8 @@
CABIN_LIGHTS_SWITCH = 289410818,
READING_LIGHTS_STATE = 356519683,
READING_LIGHTS_SWITCH = 356519684,
+ STEERING_WHEEL_LIGHTS_STATE = 289410828,
+ STEERING_WHEEL_LIGHTS_SWITCH = 289410829,
SUPPORT_CUSTOMIZE_VENDOR_PERMISSION = 287313669,
DISABLED_OPTIONAL_FEATURES = 286265094,
INITIAL_USER_INFO = 299896583,
@@ -231,4 +237,14 @@
GENERAL_SAFETY_REGULATION_COMPLIANCE_REQUIREMENT = 289410887,
SUPPORTED_PROPERTY_IDS = 289476424,
SHUTDOWN_REQUEST = 289410889,
+ AUTOMATIC_EMERGENCY_BRAKING_ENABLED = 287313920,
+ FORWARD_COLLISION_WARNING_ENABLED = 287313922,
+ BLIND_SPOT_WARNING_ENABLED = 287313924,
+ LANE_DEPARTURE_WARNING_ENABLED = 287313926,
+ LANE_KEEP_ASSIST_ENABLED = 287313928,
+ LANE_CENTERING_ASSIST_ENABLED = 287313930,
+ EMERGENCY_LANE_KEEP_ASSIST_ENABLED = 287313933,
+ ADAPTIVE_CRUISE_CONTROL_ENABLED = 287313935,
+ HANDS_ON_DETECTION_ENABLED = 287313941,
+ DRIVER_ATTENTION_MONITORING_ENABLED = 287313944,
}
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/EvStoppingMode.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/EvStoppingMode.aidl
new file mode 100644
index 0000000..8c5ac46
--- /dev/null
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/EvStoppingMode.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.vehicle;
+
+/**
+ * Used by EV_STOPPING_MODE to enumerate the current state of the stopping mode.
+ *
+ * This enum may be extended to include more states in the future.
+ */
+@VintfStability
+@Backing(type="int")
+enum EvStoppingMode {
+ /**
+ * Other EV stopping mode. Ideally, this should never be used.
+ */
+ OTHER = 0,
+ /**
+ * Vehicle slowly moves forward when the brake pedal is released.
+ */
+ CREEP = 1,
+ /**
+ * Vehicle rolls freely when the brake pedal is released (similar to neutral gear).
+ */
+ ROLL = 2,
+ /**
+ * Vehicle stops and holds its position when the brake pedal is released.
+ */
+ HOLD = 3,
+}
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl
index 4d0b77b..e776154 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl
@@ -603,6 +603,20 @@
TRACTION_CONTROL_ACTIVE = 0x040B + 0x10000000 + 0x01000000
+ 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BOOLEAN
/**
+ * Represents property for the current stopping mode of the vehicle.
+ *
+ * For the global area ID (0), the VehicleAreaConfig#supportedEnumValues must be defined unless
+ * all enum values of EvStoppingMode are supported.
+ *
+ * The EvStoppingMode enum may be extended to include more states in the future.
+ *
+ * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+ * @access VehiclePropertyAccess.READ_WRITE
+ * @data_enum EvStoppingMode
+ */
+ EV_STOPPING_MODE =
+ 0x040D + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
+ /**
* HVAC Properties
*
* Additional rules for mapping a zoned HVAC property (except
@@ -1760,7 +1774,11 @@
SEAT_LUMBAR_SIDE_SUPPORT_MOVE = 0x0B94 + 0x10000000 + 0x05000000
+ 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
/**
- * Headrest height position
+ * (Deprecated) Headrest height position
+ *
+ * This property is deprecated because it is defined as type VehicleArea:GLOBAL, which means all
+ * seats use the same value. Use SEAT_HEADREST_HEIGHT_POS_V2 instead which fixes this issue by
+ * being defined as type VehicleArea:SEAT.
*
* Sets the headrest height.
* Max value indicates tallest setting.
@@ -1771,6 +1789,25 @@
*/
SEAT_HEADREST_HEIGHT_POS = 0x0B95 + 0x10000000 + 0x01000000
+ 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
+
+ /**
+ * Headrest height position
+ *
+ * Sets the headrest height for supported seats. VehiclePropConfig.areaConfigs specifies which
+ * seats are supported.
+ *
+ * The maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All values between
+ * minInt32Value and maxInt32Value must be supported. The maxInt32Value indicates the tallest
+ * setting and the minInt32Value indicates the shortest setting.
+ *
+ * This value is not in any particular unit but in a specified range of steps.
+ *
+ * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+ * @access VehiclePropertyAccess.READ_WRITE
+ */
+ SEAT_HEADREST_HEIGHT_POS_V2 =
+ 0x0BA4 + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.INT32,
+
/**
* Headrest height move
*
@@ -1824,6 +1861,48 @@
SEAT_HEADREST_FORE_AFT_MOVE = 0x0B9A + 0x10000000 + 0x05000000
+ 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
/**
+ * Represents property for the seat footwell lights state.
+ *
+ * SEAT_FOOTWELL_LIGHTS_STATE reflects the current state of the lights at any point in time.
+ * This is different from the function of SEAT_FOOTWELL_LIGHTS_SWITCH which represents the
+ * position of the switch controlling the lights. Therefore, SEAT_FOOTWELL_LIGHTS_STATE may not
+ * match the value of SEAT_FOOTWELL_LIGHTS_SWITCH (e.g. SEAT_FOOTWELL_LIGHTS_SWITCH=AUTOMATIC
+ * and SEAT_FOOTWELL_LIGHTS_STATE=ON).
+ *
+ * This property should only be implemented if SEAT_FOOTWELL_LIGHTS_STATE's value may be
+ * different from that of CABIN_LIGHTS_STATE.
+ *
+ * For each supported area ID, the VehicleAreaConfig#supportedEnumValues must be defined unless
+ * all enum values of VehicleLightState are supported.
+ *
+ * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+ * @access VehiclePropertyAccess.READ
+ * @data_enum VehicleLightState
+ */
+ SEAT_FOOTWELL_LIGHTS_STATE =
+ 0x0B9B + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.INT32,
+ /**
+ * Represents property for the seat footwell lights switch.
+ *
+ * SEAT_FOOTWELL_LIGHTS_SWITCH represents the position of the switch controlling the lights.
+ * This is different from the function of SEAT_FOOTWELL_LIGHTS_STATE which reflects the current
+ * state of the lights at any point in time. Therefore, SEAT_FOOTWELL_LIGHTS_SWITCH may not
+ * match the value of SEAT_FOOTWELL_LIGHTS_STATE (e.g. SEAT_FOOTWELL_LIGHTS_SWITCH=AUTOMATIC and
+ * SEAT_FOOTWELL_LIGHTS_STATE=ON).
+ *
+ * This property should only be implemented if SEAT_FOOTWELL_LIGHTS_SWITCH's value may be
+ * different from that of CABIN_LIGHTS_SWITCH.
+ *
+ * For each supported area ID, the VehicleAreaConfig#supportedEnumValues must be defined unless
+ * all enum values of VehicleLightSwitch are supported.
+ *
+ * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+ * @access VehiclePropertyAccess.READ_WRITE
+ * @data_enum VehicleLightSwitch
+ */
+ SEAT_FOOTWELL_LIGHTS_SWITCH =
+ 0x0B9C + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.INT32,
+ /**
* Represents property for Seat easy access feature.
*
* If true, the seat will automatically adjust to make it easier for the occupant to enter and
@@ -2414,6 +2493,48 @@
READING_LIGHTS_SWITCH = 0x0F04 + 0x10000000 + 0x05000000
+ 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
/**
+ * Steering wheel lights state
+ *
+ * Represents the current state of the steering wheel lights. This is different from
+ * STEERING_WHEEL_LIGHTS_SWITCH which represents the position of the switch controlling
+ * the lights. Therefore, STEERING_WHEEL_LIGHTS_STATE may not match the value of
+ * STEERING_WHEEL_LIGHTS_SWITCH (e.g. STEERING_WHEEL_LIGHTS_SWITCH=AUTOMATIC and
+ * STEERING_WHEEL_LIGHTS_STATE=ON).
+ *
+ * This property should only be implemented if STEERING_WHEEL_LIGHTS_STATE's value may be
+ * different from that of CABIN_LIGHTS_STATE.
+ *
+ * For the global area ID (0), the VehicleAreaConfig#supportedEnumValues must be defined unless
+ * all enum values of VehicleLightState are supported.
+ *
+ * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+ * @access VehiclePropertyAccess.READ
+ * @data_enum VehicleLightState
+ */
+ STEERING_WHEEL_LIGHTS_STATE =
+ 0x0F0C + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
+ /**
+ * Steering wheel lights switch
+ *
+ * Represents the position of the switch controlling the steering wheel lights. This is
+ * different from STEERING_WHEEL_LIGHTS_STATE which represents the current state of the steering
+ * wheel lights. Therefore, STEERING_WHEEL_LIGHTS_SWITCH may not match the value of
+ * STEERING_WHEEL_LIGHTS_STATE (e.g. STEERING_WHEEL_LIGHTS_SWITCH=AUTOMATIC and
+ * STEERING_WHEEL_LIGHTS_STATE=ON).
+ *
+ * This property should only be implemented if STEERING_WHEEL_LIGHTS_SWITCH's value may be
+ * different from that of CABIN_LIGHTS_SWITCH.
+ *
+ * For the global area ID (0), the VehicleAreaConfig#supportedEnumValues must be defined unless
+ * all enum values of VehicleLightSwitch are supported.
+ *
+ * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+ * @access VehiclePropertyAccess.READ_WRITE
+ * @data_enum VehicleLightSwitch
+ */
+ STEERING_WHEEL_LIGHTS_SWITCH =
+ 0x0F0D + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
+ /**
* Support customize permissions for vendor properties
*
* Implement this property if vehicle hal support customize vendor permissions feature.
@@ -3296,4 +3417,183 @@
*/
SHUTDOWN_REQUEST =
0x0F49 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
+
+ /***************************************************************************
+ * Start of ADAS Properties
+ * Allocate IDs in range of 0x1000 (inclusive) to 0x1100 (exclusive) for ADAS properties
+ **************************************************************************/
+
+ /**
+ * Enable or disable automatic emergency braking (AEB).
+ *
+ * Set true to enable AEB and false to disable AEB. When AEB is enabled, the ADAS system in the
+ * vehicle should be turned on and monitoring to avoid potential collisions.
+ *
+ * This property is defined as read_write, but OEMs have the option to implement it as read
+ * only.
+ *
+ * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+ * @access VehiclePropertyAccess.READ_WRITE
+ */
+ AUTOMATIC_EMERGENCY_BRAKING_ENABLED =
+ 0x1000 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+
+ /**
+ * Enable or disable forward collision warning (FCW).
+ *
+ * Set true to enable FCW and false to disable FCW. When FCW is enabled, the ADAS system in the
+ * vehicle should be turned on and monitoring for potential collisions.
+ *
+ * This property is defined as read_write, but OEMs have the option to implement it as read
+ * only.
+ *
+ * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+ * @access VehiclePropertyAccess.READ_WRITE
+ */
+ FORWARD_COLLISION_WARNING_ENABLED =
+ 0x1002 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+
+ /**
+ * Enable and disable blind spot warning (BSW).
+ *
+ * Set true to enable BSW and false to disable BSW. When BSW is enabled, the ADAS system in the
+ * vehicle should be turned on and monitoring for objects in the vehicle’s blind spots.
+ *
+ * This property is defined as read_write, but OEMs have the option to implement it as read
+ * only.
+ *
+ * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+ * @access VehiclePropertyAccess.READ_WRITE
+ */
+ BLIND_SPOT_WARNING_ENABLED =
+ 0x1004 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+
+ /**
+ * Enable or disable lane departure warning (LDW).
+ *
+ * Set true to enable LDW and false to disable LDW. When LDW is enabled, the ADAS system in the
+ * vehicle should be turned on and monitoring if the vehicle is approaching or crossing lane
+ * lines, in which case a warning will be given.
+ *
+ * This property is defined as read_write, but OEMs have the option to implement it as read
+ * only.
+ *
+ * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+ * @access VehiclePropertyAccess.READ_WRITE
+ */
+ LANE_DEPARTURE_WARNING_ENABLED =
+ 0x1006 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+
+ /**
+ * Enable or disable Lane Keep Assist (LKA).
+ *
+ * Set true to enable LKA and false to disable LKA. When LKA is enabled, the ADAS system in the
+ * vehicle should be turned on and monitoring if the driver unintentionally drifts toward or
+ * over the lane marking. If an unintentional lane departure is detected, the system applies
+ * steering control to return the vehicle into the current lane.
+ *
+ * This is different from Lane Centering Assist (LCA) which, when activated, applies continuous
+ * steering control to keep the vehicle centered in the current lane.
+ *
+ * This property is defined as read_write, but OEMs have the option to implement it as read
+ * only.
+ *
+ * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+ * @access VehiclePropertyAccess.READ_WRITE
+ */
+ LANE_KEEP_ASSIST_ENABLED =
+ 0x1008 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+
+ /**
+ * Enable or disable lane centering assist (LCA).
+ *
+ * Set true to enable LCA and false to disable LCA. When LCA is enabled, the ADAS system in the
+ * vehicle should be turned on and waiting for an activation signal from the driver. Once the
+ * feature is activated, the ADAS system should be steering the vehicle to keep it centered in
+ * its current lane.
+ *
+ * This is different from Lane Keep Assist (LKA) which monitors if the driver unintentionally
+ * drifts toward or over the lane marking. If an unintentional lane departure is detected, the
+ * system applies steering control to return the vehicle into the current lane.
+ *
+ * This property is defined as read_write, but OEMs have the option to implement it as read
+ * only.
+ *
+ * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+ * @access VehiclePropertyAccess.READ_WRITE
+ */
+ LANE_CENTERING_ASSIST_ENABLED =
+ 0x100A + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+
+ /*
+ * Enable or disable emergency lane keep assist (ELKA).
+ *
+ * Set true to enable ELKA and false to disable ELKA. When ELKA is enabled, the ADAS system in
+ * the vehicle should be on and monitoring for unsafe lane changes by the driver. When an unsafe
+ * maneuver is detected, ELKA alerts the driver and applies steering corrections to keep the
+ * vehicle in its original lane.
+ *
+ * This property is defined as read_write, but OEMs have the option to implement it as read
+ * only.
+ *
+ * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+ * @access VehiclePropertyAccess.READ_WRITE
+ */
+ EMERGENCY_LANE_KEEP_ASSIST_ENABLED =
+ 0x100D + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+
+ /**
+ * Enable or disable adaptive cruise control (ACC).
+ *
+ * Set true to enable ACC and false to disable ACC. When ACC is enabled, the ADAS system in the
+ * vehicle should be turned on and waiting for an activation signal from the driver. Once the
+ * feature is activated, the ADAS system in the car should be accelerating and braking in a way
+ * that allows the vehicle to maintain a set speed and to maintain a set distance gap from a
+ * leading vehicle.
+ *
+ * This property is defined as read_write, but OEMs have the option to implement it as read
+ * only.
+ *
+ * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+ * @access VehiclePropertyAccess.READ_WRITE
+ */
+ ADAPTIVE_CRUISE_CONTROL_ENABLED =
+ 0x100F + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+
+ /**
+ * Enable or disable hands on detection (HOD).
+ *
+ * Set true to enable HOD and false to disable HOD. When HOD is enabled, a system inside the
+ * vehicle should be monitoring the presence of the driver's hands on the steering wheel and
+ * send a warning if it detects that the driver's hands are no longer on the steering wheel.
+ *
+ * This property is defined as read_write, but OEMs have the option to implement it as read
+ * only.
+ *
+ * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+ * @access VehiclePropertyAccess.READ_WRITE
+ */
+ HANDS_ON_DETECTION_ENABLED =
+ 0x1015 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+
+ /**
+ * Enable or disable driver attention monitoring.
+ *
+ * Set true to enable driver attention monitoring and false to disable driver attention
+ * monitoring. When driver attention monitoring is enabled, a system inside the vehicle should
+ * be monitoring the attention level of the driver and should send a warning if it detects that
+ * the driver is distracted.
+ *
+ * This property is defined as read_write, but OEMs have the option to implement it as read
+ * only.
+ *
+ * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+ * @access VehiclePropertyAccess.READ_WRITE
+ */
+ DRIVER_ATTENTION_MONITORING_ENABLED =
+ 0x1018 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+
+ /***************************************************************************
+ * End of ADAS Properties
+ **************************************************************************/
}
diff --git a/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h b/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h
index 75b371f..8b77040 100644
--- a/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h
+++ b/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h
@@ -80,6 +80,7 @@
{VehicleProperty::IGNITION_STATE, VehiclePropertyAccess::READ},
{VehicleProperty::ABS_ACTIVE, VehiclePropertyAccess::READ},
{VehicleProperty::TRACTION_CONTROL_ACTIVE, VehiclePropertyAccess::READ},
+ {VehicleProperty::EV_STOPPING_MODE, VehiclePropertyAccess::READ_WRITE},
{VehicleProperty::HVAC_FAN_SPEED, VehiclePropertyAccess::READ_WRITE},
{VehicleProperty::HVAC_FAN_DIRECTION, VehiclePropertyAccess::READ_WRITE},
{VehicleProperty::HVAC_TEMPERATURE_CURRENT, VehiclePropertyAccess::READ},
@@ -155,11 +156,14 @@
{VehicleProperty::SEAT_LUMBAR_SIDE_SUPPORT_POS, VehiclePropertyAccess::READ_WRITE},
{VehicleProperty::SEAT_LUMBAR_SIDE_SUPPORT_MOVE, VehiclePropertyAccess::READ_WRITE},
{VehicleProperty::SEAT_HEADREST_HEIGHT_POS, VehiclePropertyAccess::READ_WRITE},
+ {VehicleProperty::SEAT_HEADREST_HEIGHT_POS_V2, VehiclePropertyAccess::READ_WRITE},
{VehicleProperty::SEAT_HEADREST_HEIGHT_MOVE, VehiclePropertyAccess::READ_WRITE},
{VehicleProperty::SEAT_HEADREST_ANGLE_POS, VehiclePropertyAccess::READ_WRITE},
{VehicleProperty::SEAT_HEADREST_ANGLE_MOVE, VehiclePropertyAccess::READ_WRITE},
{VehicleProperty::SEAT_HEADREST_FORE_AFT_POS, VehiclePropertyAccess::READ_WRITE},
{VehicleProperty::SEAT_HEADREST_FORE_AFT_MOVE, VehiclePropertyAccess::READ_WRITE},
+ {VehicleProperty::SEAT_FOOTWELL_LIGHTS_STATE, VehiclePropertyAccess::READ},
+ {VehicleProperty::SEAT_FOOTWELL_LIGHTS_SWITCH, VehiclePropertyAccess::READ_WRITE},
{VehicleProperty::SEAT_EASY_ACCESS_ENABLED, VehiclePropertyAccess::READ_WRITE},
{VehicleProperty::SEAT_AIRBAG_ENABLED, VehiclePropertyAccess::READ_WRITE},
{VehicleProperty::SEAT_CUSHION_SIDE_SUPPORT_POS, VehiclePropertyAccess::READ_WRITE},
@@ -195,6 +199,8 @@
{VehicleProperty::CABIN_LIGHTS_SWITCH, VehiclePropertyAccess::READ_WRITE},
{VehicleProperty::READING_LIGHTS_STATE, VehiclePropertyAccess::READ},
{VehicleProperty::READING_LIGHTS_SWITCH, VehiclePropertyAccess::READ_WRITE},
+ {VehicleProperty::STEERING_WHEEL_LIGHTS_STATE, VehiclePropertyAccess::READ},
+ {VehicleProperty::STEERING_WHEEL_LIGHTS_SWITCH, VehiclePropertyAccess::READ_WRITE},
{VehicleProperty::SUPPORT_CUSTOMIZE_VENDOR_PERMISSION, VehiclePropertyAccess::READ},
{VehicleProperty::DISABLED_OPTIONAL_FEATURES, VehiclePropertyAccess::READ},
{VehicleProperty::INITIAL_USER_INFO, VehiclePropertyAccess::READ_WRITE},
@@ -231,6 +237,16 @@
{VehicleProperty::GENERAL_SAFETY_REGULATION_COMPLIANCE_REQUIREMENT, VehiclePropertyAccess::READ},
{VehicleProperty::SUPPORTED_PROPERTY_IDS, VehiclePropertyAccess::READ},
{VehicleProperty::SHUTDOWN_REQUEST, VehiclePropertyAccess::WRITE},
+ {VehicleProperty::AUTOMATIC_EMERGENCY_BRAKING_ENABLED, VehiclePropertyAccess::READ_WRITE},
+ {VehicleProperty::FORWARD_COLLISION_WARNING_ENABLED, VehiclePropertyAccess::READ_WRITE},
+ {VehicleProperty::BLIND_SPOT_WARNING_ENABLED, VehiclePropertyAccess::READ_WRITE},
+ {VehicleProperty::LANE_DEPARTURE_WARNING_ENABLED, VehiclePropertyAccess::READ_WRITE},
+ {VehicleProperty::LANE_KEEP_ASSIST_ENABLED, VehiclePropertyAccess::READ_WRITE},
+ {VehicleProperty::LANE_CENTERING_ASSIST_ENABLED, VehiclePropertyAccess::READ_WRITE},
+ {VehicleProperty::EMERGENCY_LANE_KEEP_ASSIST_ENABLED, VehiclePropertyAccess::READ_WRITE},
+ {VehicleProperty::ADAPTIVE_CRUISE_CONTROL_ENABLED, VehiclePropertyAccess::READ_WRITE},
+ {VehicleProperty::HANDS_ON_DETECTION_ENABLED, VehiclePropertyAccess::READ_WRITE},
+ {VehicleProperty::DRIVER_ATTENTION_MONITORING_ENABLED, VehiclePropertyAccess::READ_WRITE},
};
} // namespace vehicle
diff --git a/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h b/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h
index 6e797b9..d7e87e2 100644
--- a/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h
+++ b/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h
@@ -80,6 +80,7 @@
{VehicleProperty::IGNITION_STATE, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::ABS_ACTIVE, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::TRACTION_CONTROL_ACTIVE, VehiclePropertyChangeMode::ON_CHANGE},
+ {VehicleProperty::EV_STOPPING_MODE, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::HVAC_FAN_SPEED, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::HVAC_FAN_DIRECTION, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::HVAC_TEMPERATURE_CURRENT, VehiclePropertyChangeMode::ON_CHANGE},
@@ -155,11 +156,14 @@
{VehicleProperty::SEAT_LUMBAR_SIDE_SUPPORT_POS, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::SEAT_LUMBAR_SIDE_SUPPORT_MOVE, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::SEAT_HEADREST_HEIGHT_POS, VehiclePropertyChangeMode::ON_CHANGE},
+ {VehicleProperty::SEAT_HEADREST_HEIGHT_POS_V2, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::SEAT_HEADREST_HEIGHT_MOVE, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::SEAT_HEADREST_ANGLE_POS, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::SEAT_HEADREST_ANGLE_MOVE, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::SEAT_HEADREST_FORE_AFT_POS, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::SEAT_HEADREST_FORE_AFT_MOVE, VehiclePropertyChangeMode::ON_CHANGE},
+ {VehicleProperty::SEAT_FOOTWELL_LIGHTS_STATE, VehiclePropertyChangeMode::ON_CHANGE},
+ {VehicleProperty::SEAT_FOOTWELL_LIGHTS_SWITCH, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::SEAT_EASY_ACCESS_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::SEAT_AIRBAG_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::SEAT_CUSHION_SIDE_SUPPORT_POS, VehiclePropertyChangeMode::ON_CHANGE},
@@ -195,6 +199,8 @@
{VehicleProperty::CABIN_LIGHTS_SWITCH, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::READING_LIGHTS_STATE, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::READING_LIGHTS_SWITCH, VehiclePropertyChangeMode::ON_CHANGE},
+ {VehicleProperty::STEERING_WHEEL_LIGHTS_STATE, VehiclePropertyChangeMode::ON_CHANGE},
+ {VehicleProperty::STEERING_WHEEL_LIGHTS_SWITCH, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::SUPPORT_CUSTOMIZE_VENDOR_PERMISSION, VehiclePropertyChangeMode::STATIC},
{VehicleProperty::DISABLED_OPTIONAL_FEATURES, VehiclePropertyChangeMode::STATIC},
{VehicleProperty::INITIAL_USER_INFO, VehiclePropertyChangeMode::ON_CHANGE},
@@ -231,6 +237,16 @@
{VehicleProperty::GENERAL_SAFETY_REGULATION_COMPLIANCE_REQUIREMENT, VehiclePropertyChangeMode::STATIC},
{VehicleProperty::SUPPORTED_PROPERTY_IDS, VehiclePropertyChangeMode::STATIC},
{VehicleProperty::SHUTDOWN_REQUEST, VehiclePropertyChangeMode::ON_CHANGE},
+ {VehicleProperty::AUTOMATIC_EMERGENCY_BRAKING_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
+ {VehicleProperty::FORWARD_COLLISION_WARNING_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
+ {VehicleProperty::BLIND_SPOT_WARNING_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
+ {VehicleProperty::LANE_DEPARTURE_WARNING_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
+ {VehicleProperty::LANE_KEEP_ASSIST_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
+ {VehicleProperty::LANE_CENTERING_ASSIST_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
+ {VehicleProperty::EMERGENCY_LANE_KEEP_ASSIST_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
+ {VehicleProperty::ADAPTIVE_CRUISE_CONTROL_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
+ {VehicleProperty::HANDS_ON_DETECTION_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
+ {VehicleProperty::DRIVER_ATTENTION_MONITORING_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
};
} // namespace vehicle
diff --git a/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java b/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java
index 455d3d4..14600f0 100644
--- a/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java
+++ b/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java
@@ -72,6 +72,7 @@
Map.entry(VehicleProperty.IGNITION_STATE, VehiclePropertyAccess.READ),
Map.entry(VehicleProperty.ABS_ACTIVE, VehiclePropertyAccess.READ),
Map.entry(VehicleProperty.TRACTION_CONTROL_ACTIVE, VehiclePropertyAccess.READ),
+ Map.entry(VehicleProperty.EV_STOPPING_MODE, VehiclePropertyAccess.READ_WRITE),
Map.entry(VehicleProperty.HVAC_FAN_SPEED, VehiclePropertyAccess.READ_WRITE),
Map.entry(VehicleProperty.HVAC_FAN_DIRECTION, VehiclePropertyAccess.READ_WRITE),
Map.entry(VehicleProperty.HVAC_TEMPERATURE_CURRENT, VehiclePropertyAccess.READ),
@@ -147,11 +148,14 @@
Map.entry(VehicleProperty.SEAT_LUMBAR_SIDE_SUPPORT_POS, VehiclePropertyAccess.READ_WRITE),
Map.entry(VehicleProperty.SEAT_LUMBAR_SIDE_SUPPORT_MOVE, VehiclePropertyAccess.READ_WRITE),
Map.entry(VehicleProperty.SEAT_HEADREST_HEIGHT_POS, VehiclePropertyAccess.READ_WRITE),
+ Map.entry(VehicleProperty.SEAT_HEADREST_HEIGHT_POS_V2, VehiclePropertyAccess.READ_WRITE),
Map.entry(VehicleProperty.SEAT_HEADREST_HEIGHT_MOVE, VehiclePropertyAccess.READ_WRITE),
Map.entry(VehicleProperty.SEAT_HEADREST_ANGLE_POS, VehiclePropertyAccess.READ_WRITE),
Map.entry(VehicleProperty.SEAT_HEADREST_ANGLE_MOVE, VehiclePropertyAccess.READ_WRITE),
Map.entry(VehicleProperty.SEAT_HEADREST_FORE_AFT_POS, VehiclePropertyAccess.READ_WRITE),
Map.entry(VehicleProperty.SEAT_HEADREST_FORE_AFT_MOVE, VehiclePropertyAccess.READ_WRITE),
+ Map.entry(VehicleProperty.SEAT_FOOTWELL_LIGHTS_STATE, VehiclePropertyAccess.READ),
+ Map.entry(VehicleProperty.SEAT_FOOTWELL_LIGHTS_SWITCH, VehiclePropertyAccess.READ_WRITE),
Map.entry(VehicleProperty.SEAT_EASY_ACCESS_ENABLED, VehiclePropertyAccess.READ_WRITE),
Map.entry(VehicleProperty.SEAT_AIRBAG_ENABLED, VehiclePropertyAccess.READ_WRITE),
Map.entry(VehicleProperty.SEAT_CUSHION_SIDE_SUPPORT_POS, VehiclePropertyAccess.READ_WRITE),
@@ -187,6 +191,8 @@
Map.entry(VehicleProperty.CABIN_LIGHTS_SWITCH, VehiclePropertyAccess.READ_WRITE),
Map.entry(VehicleProperty.READING_LIGHTS_STATE, VehiclePropertyAccess.READ),
Map.entry(VehicleProperty.READING_LIGHTS_SWITCH, VehiclePropertyAccess.READ_WRITE),
+ Map.entry(VehicleProperty.STEERING_WHEEL_LIGHTS_STATE, VehiclePropertyAccess.READ),
+ Map.entry(VehicleProperty.STEERING_WHEEL_LIGHTS_SWITCH, VehiclePropertyAccess.READ_WRITE),
Map.entry(VehicleProperty.SUPPORT_CUSTOMIZE_VENDOR_PERMISSION, VehiclePropertyAccess.READ),
Map.entry(VehicleProperty.DISABLED_OPTIONAL_FEATURES, VehiclePropertyAccess.READ),
Map.entry(VehicleProperty.INITIAL_USER_INFO, VehiclePropertyAccess.READ_WRITE),
@@ -222,7 +228,17 @@
Map.entry(VehicleProperty.VEHICLE_CURB_WEIGHT, VehiclePropertyAccess.READ),
Map.entry(VehicleProperty.GENERAL_SAFETY_REGULATION_COMPLIANCE_REQUIREMENT, VehiclePropertyAccess.READ),
Map.entry(VehicleProperty.SUPPORTED_PROPERTY_IDS, VehiclePropertyAccess.READ),
- Map.entry(VehicleProperty.SHUTDOWN_REQUEST, VehiclePropertyAccess.WRITE)
+ Map.entry(VehicleProperty.SHUTDOWN_REQUEST, VehiclePropertyAccess.WRITE),
+ Map.entry(VehicleProperty.AUTOMATIC_EMERGENCY_BRAKING_ENABLED, VehiclePropertyAccess.READ_WRITE),
+ Map.entry(VehicleProperty.FORWARD_COLLISION_WARNING_ENABLED, VehiclePropertyAccess.READ_WRITE),
+ Map.entry(VehicleProperty.BLIND_SPOT_WARNING_ENABLED, VehiclePropertyAccess.READ_WRITE),
+ Map.entry(VehicleProperty.LANE_DEPARTURE_WARNING_ENABLED, VehiclePropertyAccess.READ_WRITE),
+ Map.entry(VehicleProperty.LANE_KEEP_ASSIST_ENABLED, VehiclePropertyAccess.READ_WRITE),
+ Map.entry(VehicleProperty.LANE_CENTERING_ASSIST_ENABLED, VehiclePropertyAccess.READ_WRITE),
+ Map.entry(VehicleProperty.EMERGENCY_LANE_KEEP_ASSIST_ENABLED, VehiclePropertyAccess.READ_WRITE),
+ Map.entry(VehicleProperty.ADAPTIVE_CRUISE_CONTROL_ENABLED, VehiclePropertyAccess.READ_WRITE),
+ Map.entry(VehicleProperty.HANDS_ON_DETECTION_ENABLED, VehiclePropertyAccess.READ_WRITE),
+ Map.entry(VehicleProperty.DRIVER_ATTENTION_MONITORING_ENABLED, VehiclePropertyAccess.READ_WRITE)
);
}
diff --git a/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java b/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java
index aaa344f..864f392 100644
--- a/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java
+++ b/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java
@@ -72,6 +72,7 @@
Map.entry(VehicleProperty.IGNITION_STATE, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.ABS_ACTIVE, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.TRACTION_CONTROL_ACTIVE, VehiclePropertyChangeMode.ON_CHANGE),
+ Map.entry(VehicleProperty.EV_STOPPING_MODE, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.HVAC_FAN_SPEED, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.HVAC_FAN_DIRECTION, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.HVAC_TEMPERATURE_CURRENT, VehiclePropertyChangeMode.ON_CHANGE),
@@ -147,11 +148,14 @@
Map.entry(VehicleProperty.SEAT_LUMBAR_SIDE_SUPPORT_POS, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.SEAT_LUMBAR_SIDE_SUPPORT_MOVE, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.SEAT_HEADREST_HEIGHT_POS, VehiclePropertyChangeMode.ON_CHANGE),
+ Map.entry(VehicleProperty.SEAT_HEADREST_HEIGHT_POS_V2, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.SEAT_HEADREST_HEIGHT_MOVE, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.SEAT_HEADREST_ANGLE_POS, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.SEAT_HEADREST_ANGLE_MOVE, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.SEAT_HEADREST_FORE_AFT_POS, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.SEAT_HEADREST_FORE_AFT_MOVE, VehiclePropertyChangeMode.ON_CHANGE),
+ Map.entry(VehicleProperty.SEAT_FOOTWELL_LIGHTS_STATE, VehiclePropertyChangeMode.ON_CHANGE),
+ Map.entry(VehicleProperty.SEAT_FOOTWELL_LIGHTS_SWITCH, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.SEAT_EASY_ACCESS_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.SEAT_AIRBAG_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.SEAT_CUSHION_SIDE_SUPPORT_POS, VehiclePropertyChangeMode.ON_CHANGE),
@@ -187,6 +191,8 @@
Map.entry(VehicleProperty.CABIN_LIGHTS_SWITCH, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.READING_LIGHTS_STATE, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.READING_LIGHTS_SWITCH, VehiclePropertyChangeMode.ON_CHANGE),
+ Map.entry(VehicleProperty.STEERING_WHEEL_LIGHTS_STATE, VehiclePropertyChangeMode.ON_CHANGE),
+ Map.entry(VehicleProperty.STEERING_WHEEL_LIGHTS_SWITCH, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.SUPPORT_CUSTOMIZE_VENDOR_PERMISSION, VehiclePropertyChangeMode.STATIC),
Map.entry(VehicleProperty.DISABLED_OPTIONAL_FEATURES, VehiclePropertyChangeMode.STATIC),
Map.entry(VehicleProperty.INITIAL_USER_INFO, VehiclePropertyChangeMode.ON_CHANGE),
@@ -222,7 +228,17 @@
Map.entry(VehicleProperty.VEHICLE_CURB_WEIGHT, VehiclePropertyChangeMode.STATIC),
Map.entry(VehicleProperty.GENERAL_SAFETY_REGULATION_COMPLIANCE_REQUIREMENT, VehiclePropertyChangeMode.STATIC),
Map.entry(VehicleProperty.SUPPORTED_PROPERTY_IDS, VehiclePropertyChangeMode.STATIC),
- Map.entry(VehicleProperty.SHUTDOWN_REQUEST, VehiclePropertyChangeMode.ON_CHANGE)
+ Map.entry(VehicleProperty.SHUTDOWN_REQUEST, VehiclePropertyChangeMode.ON_CHANGE),
+ Map.entry(VehicleProperty.AUTOMATIC_EMERGENCY_BRAKING_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
+ Map.entry(VehicleProperty.FORWARD_COLLISION_WARNING_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
+ Map.entry(VehicleProperty.BLIND_SPOT_WARNING_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
+ Map.entry(VehicleProperty.LANE_DEPARTURE_WARNING_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
+ Map.entry(VehicleProperty.LANE_KEEP_ASSIST_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
+ Map.entry(VehicleProperty.LANE_CENTERING_ASSIST_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
+ Map.entry(VehicleProperty.EMERGENCY_LANE_KEEP_ASSIST_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
+ Map.entry(VehicleProperty.ADAPTIVE_CRUISE_CONTROL_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
+ Map.entry(VehicleProperty.HANDS_ON_DETECTION_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
+ Map.entry(VehicleProperty.DRIVER_ATTENTION_MONITORING_ENABLED, VehiclePropertyChangeMode.ON_CHANGE)
);
}
diff --git a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp
index 20048a2..5521ed1 100644
--- a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp
+++ b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp
@@ -89,6 +89,7 @@
{"SEAT_2_LEFT", SEAT_2_LEFT},
{"SEAT_2_RIGHT", SEAT_2_RIGHT},
{"SEAT_2_CENTER", SEAT_2_CENTER},
+ {"SEAT_2_LEFT_2_RIGHT_2_CENTER", SEAT_2_LEFT | SEAT_2_RIGHT | SEAT_2_CENTER},
{"WHEEL_REAR_RIGHT", WHEEL_REAR_RIGHT},
{"WHEEL_REAR_LEFT", WHEEL_REAR_LEFT},
{"WHEEL_FRONT_RIGHT", WHEEL_FRONT_RIGHT},
@@ -107,7 +108,11 @@
{"LIGHT_STATE_ON", LIGHT_STATE_ON},
{"LIGHT_STATE_OFF", LIGHT_STATE_OFF},
{"LIGHT_SWITCH_OFF", LIGHT_SWITCH_OFF},
+ {"LIGHT_SWITCH_ON", LIGHT_SWITCH_ON},
{"LIGHT_SWITCH_AUTO", LIGHT_SWITCH_AUTO},
+ {"EV_STOPPING_MODE_CREEP", EV_STOPPING_MODE_CREEP},
+ {"EV_STOPPING_MODE_ROLL", EV_STOPPING_MODE_ROLL},
+ {"EV_STOPPING_MODE_HOLD", EV_STOPPING_MODE_HOLD},
{"MIRROR_DRIVER_LEFT_RIGHT",
toInt(VehicleAreaMirror::DRIVER_LEFT) | toInt(VehicleAreaMirror::DRIVER_RIGHT)},
#ifdef ENABLE_VEHICLE_HAL_TEST_PROPERTIES
diff --git a/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json b/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
index c17a2e2..8181769 100644
--- a/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
+++ b/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
@@ -861,6 +861,41 @@
]
},
{
+ "property": "VehicleProperty::SEAT_HEADREST_HEIGHT_POS_V2",
+ "defaultValue": {
+ "int32Values": [
+ 0
+ ]
+ },
+ "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_HEADREST_HEIGHT_MOVE",
"defaultValue": {
"int32Values": [
@@ -1036,6 +1071,71 @@
]
},
{
+ "property": "VehicleProperty::SEAT_FOOTWELL_LIGHTS_STATE",
+ "defaultValue": {
+ "int32Values": [
+ "Constants::LIGHT_STATE_OFF"
+ ]
+ },
+ "areas": [
+ {
+ "areaId": "Constants::SEAT_1_LEFT",
+ "supportedEnumValues": [
+ "Constants::LIGHT_STATE_OFF",
+ "Constants::LIGHT_STATE_ON"
+ ]
+ },
+ {
+ "areaId": "Constants::SEAT_1_RIGHT",
+ "supportedEnumValues": [
+ "Constants::LIGHT_STATE_OFF",
+ "Constants::LIGHT_STATE_ON"
+ ]
+ },
+ {
+ "areaId": "Constants::SEAT_2_LEFT_2_RIGHT_2_CENTER",
+ "supportedEnumValues": [
+ "Constants::LIGHT_STATE_OFF",
+ "Constants::LIGHT_STATE_ON"
+ ]
+ }
+ ]
+ },
+ {
+ "property": "VehicleProperty::SEAT_FOOTWELL_LIGHTS_SWITCH",
+ "defaultValue": {
+ "int32Values": [
+ "Constants::LIGHT_SWITCH_OFF"
+ ]
+ },
+ "areas": [
+ {
+ "areaId": "Constants::SEAT_1_LEFT",
+ "supportedEnumValues": [
+ "Constants::LIGHT_SWITCH_OFF",
+ "Constants::LIGHT_SWITCH_ON",
+ "Constants::LIGHT_SWITCH_AUTO"
+ ]
+ },
+ {
+ "areaId": "Constants::SEAT_1_RIGHT",
+ "supportedEnumValues": [
+ "Constants::LIGHT_SWITCH_OFF",
+ "Constants::LIGHT_SWITCH_ON",
+ "Constants::LIGHT_SWITCH_AUTO"
+ ]
+ },
+ {
+ "areaId": "Constants::SEAT_2_LEFT_2_RIGHT_2_CENTER",
+ "supportedEnumValues": [
+ "Constants::LIGHT_SWITCH_OFF",
+ "Constants::LIGHT_SWITCH_ON",
+ "Constants::LIGHT_SWITCH_AUTO"
+ ]
+ }
+ ]
+ },
+ {
"property": "VehicleProperty::SEAT_EASY_ACCESS_ENABLED",
"defaultValue": {
"int32Values": [
@@ -1588,6 +1688,24 @@
]
},
{
+ "property": "VehicleProperty::EV_STOPPING_MODE",
+ "defaultValue": {
+ "int32Values": [
+ "Constants::EV_STOPPING_MODE_CREEP"
+ ]
+ },
+ "areas": [
+ {
+ "areaId": 0,
+ "supportedEnumValues": [
+ "Constants::EV_STOPPING_MODE_CREEP",
+ "Constants::EV_STOPPING_MODE_ROLL",
+ "Constants::EV_STOPPING_MODE_HOLD"
+ ]
+ }
+ ]
+ },
+ {
"property": "VehicleProperty::FUEL_LEVEL_LOW",
"defaultValue": {
"int32Values": [
@@ -1626,6 +1744,77 @@
}
},
{
+ "property": "VehicleProperty::HW_KEY_INPUT_V2",
+ "defaultValue": {
+ "int32Values": [
+ 0,
+ 0,
+ 0,
+ 0
+ ],
+ "int64Values": [
+ 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::HW_MOTION_INPUT",
+ "defaultValue": {
+ "int32Values": [
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0
+ ],
+ "floatValues": [
+ 0,
+ 0,
+ 0,
+ 0
+ ],
+ "int64Values": [
+ 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::HW_ROTARY_INPUT",
"defaultValue": {
"int32Values": [
@@ -1982,8 +2171,8 @@
160,
280,
5,
- 605,
- 825,
+ 600,
+ 840,
10
]
},
@@ -2707,6 +2896,23 @@
]
},
{
+ "property": "VehicleProperty::STEERING_WHEEL_LIGHTS_STATE",
+ "defaultValue": {
+ "int32Values": [
+ "Constants::LIGHT_STATE_ON"
+ ]
+ },
+ "areas": [
+ {
+ "areaId": 0,
+ "supportedEnumValues": [
+ "Constants::LIGHT_STATE_OFF",
+ "Constants::LIGHT_STATE_ON"
+ ]
+ }
+ ]
+ },
+ {
"property": "VehicleProperty::HEADLIGHTS_SWITCH",
"defaultValue": {
"int32Values": [
@@ -2780,6 +2986,24 @@
]
},
{
+ "property": "VehicleProperty::STEERING_WHEEL_LIGHTS_SWITCH",
+ "defaultValue": {
+ "int32Values": [
+ "Constants::LIGHT_SWITCH_AUTO"
+ ]
+ },
+ "areas": [
+ {
+ "areaId": 0,
+ "supportedEnumValues": [
+ "Constants::LIGHT_SWITCH_OFF",
+ "Constants::LIGHT_SWITCH_ON",
+ "Constants::LIGHT_SWITCH_AUTO"
+ ]
+ }
+ ]
+ },
+ {
"property": "VehicleProperty::EVS_SERVICE_REQUEST",
"defaultValue": {
"int32Values": [
@@ -2808,6 +3032,38 @@
}
},
{
+ "property": "VehicleProperty::EMERGENCY_LANE_KEEP_ASSIST_ENABLED",
+ "defaultValue": {
+ "int32Values": [
+ 1
+ ]
+ }
+ },
+ {
+ "property": "VehicleProperty::ADAPTIVE_CRUISE_CONTROL_ENABLED",
+ "defaultValue": {
+ "int32Values": [
+ 1
+ ]
+ }
+ },
+ {
+ "property": "VehicleProperty::HANDS_ON_DETECTION_ENABLED",
+ "defaultValue": {
+ "int32Values": [
+ 1
+ ]
+ }
+ },
+ {
+ "property": "VehicleProperty::DRIVER_ATTENTION_MONITORING_ENABLED",
+ "defaultValue": {
+ "int32Values": [
+ 1
+ ]
+ }
+ },
+ {
"property": "VehicleProperty::INITIAL_USER_INFO"
},
{
@@ -2897,6 +3153,54 @@
"GsrComplianceRequirementType::GSR_COMPLIANCE_REQUIRED_V1"
]
}
+ },
+ {
+ "property": "VehicleProperty::AUTOMATIC_EMERGENCY_BRAKING_ENABLED",
+ "defaultValue": {
+ "int32Values": [
+ 0
+ ]
+ }
+ },
+ {
+ "property": "VehicleProperty::FORWARD_COLLISION_WARNING_ENABLED",
+ "defaultValue": {
+ "int32Values": [
+ 0
+ ]
+ }
+ },
+ {
+ "property": "VehicleProperty::BLIND_SPOT_WARNING_ENABLED",
+ "defaultValue": {
+ "int32Values": [
+ 0
+ ]
+ }
+ },
+ {
+ "property": "VehicleProperty::LANE_DEPARTURE_WARNING_ENABLED",
+ "defaultValue": {
+ "int32Values": [
+ 0
+ ]
+ }
+ },
+ {
+ "property": "VehicleProperty::LANE_KEEP_ASSIST_ENABLED",
+ "defaultValue": {
+ "int32Values": [
+ 0
+ ]
+ }
+ },
+ {
+ "property": "VehicleProperty::LANE_CENTERING_ASSIST_ENABLED",
+ "defaultValue": {
+ "int32Values": [
+ 0
+ ]
+ }
}
]
}
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 e515bad..5e35b0f 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
@@ -240,6 +240,14 @@
static aidl::android::hardware::automotive::vehicle::VehiclePropValue createHwInputKeyProp(
aidl::android::hardware::automotive::vehicle::VehicleHwKeyInputAction action,
int32_t keyCode, int32_t targetDisplay);
+ static aidl::android::hardware::automotive::vehicle::VehiclePropValue createHwKeyInputV2Prop(
+ int32_t area, int32_t targetDisplay, int32_t keyCode, int32_t action,
+ int32_t repeatCount);
+ static aidl::android::hardware::automotive::vehicle::VehiclePropValue createHwMotionInputProp(
+ int32_t area, int32_t display, int32_t inputType, int32_t action, int32_t buttonState,
+ int32_t pointerCount, int32_t pointerId[], int32_t toolType[], float xData[],
+ float yData[], float pressure[], float size[]);
+
static std::string genFakeDataHelp();
static std::string parseErrMsg(std::string fieldName, std::string value, std::string type);
};
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 dd76524..6e085db 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
@@ -672,6 +672,14 @@
--genfakedata --keypress [keyCode(int32)] [display[int32]]: Generate key press.
+--genfakedata --keyinputv2 [area(int32)] [display(int32)] [keyCode[int32]] [action[int32]]
+ [repeatCount(int32)]
+
+--genfakedata --motioninput [area(int32)] [display(int32)] [inputType[int32]] [action[int32]]
+ [buttonState(int32)] --pointer [pointerId(int32)] [toolType(int32)] [xData(float)] [yData(float)]
+ [pressure(float)] [size(float)]
+ Generate a motion input event. --pointer option can be specified multiple times.
+
)";
}
@@ -802,6 +810,135 @@
onValueChangeCallback(
createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_UP, keyCode, display));
return "keypress event generated successfully";
+ } else if (command == "--keyinputv2") {
+ int32_t area;
+ int32_t display;
+ int32_t keyCode;
+ int32_t action;
+ int32_t repeatCount;
+ // --genfakedata --keyinputv2 [area(int32)] [display(int32)] [keyCode[int32]]
+ // [action[int32]] [repeatCount(int32)]
+ if (options.size() != 7) {
+ return "incorrect argument count, need 7 arguments for --genfakedata --keyinputv2\n";
+ }
+ if (!android::base::ParseInt(options[2], &area)) {
+ return parseErrMsg("area", options[2], "int");
+ }
+ if (!android::base::ParseInt(options[3], &display)) {
+ return parseErrMsg("display", options[3], "int");
+ }
+ if (!android::base::ParseInt(options[4], &keyCode)) {
+ return parseErrMsg("keyCode", options[4], "int");
+ }
+ if (!android::base::ParseInt(options[5], &action)) {
+ return parseErrMsg("action", options[5], "int");
+ }
+ if (!android::base::ParseInt(options[6], &repeatCount)) {
+ return parseErrMsg("repeatCount", options[6], "int");
+ }
+ // Send back to HAL
+ onValueChangeCallback(createHwKeyInputV2Prop(area, display, keyCode, action, repeatCount));
+ return StringPrintf(
+ "keyinputv2 event generated successfully with area:%d, display:%d,"
+ " keyCode:%d, action:%d, repeatCount:%d",
+ area, display, keyCode, action, repeatCount);
+
+ } else if (command == "--motioninput") {
+ int32_t area;
+ int32_t display;
+ int32_t inputType;
+ int32_t action;
+ int32_t buttonState;
+ int32_t pointerCount;
+
+ // --genfakedata --motioninput [area(int32)] [display(int32)] [inputType[int32]]
+ // [action[int32]] [buttonState(int32)] [pointerCount(int32)]
+ // --pointer [pointerId(int32)] [toolType(int32)] [xData(float)] [yData(float)]
+ // [pressure(float)] [size(float)]
+ int optionsSize = (int)options.size();
+ if (optionsSize / 7 < 2) {
+ return "incorrect argument count, need at least 14 arguments for --genfakedata "
+ "--motioninput including at least 1 --pointer\n";
+ }
+
+ if (optionsSize % 7 != 0) {
+ return "incorrect argument count, need 6 arguments for every --pointer\n";
+ }
+ pointerCount = (int)optionsSize / 7 - 1;
+
+ if (!android::base::ParseInt(options[2], &area)) {
+ return parseErrMsg("area", options[2], "int");
+ }
+ if (!android::base::ParseInt(options[3], &display)) {
+ return parseErrMsg("display", options[3], "int");
+ }
+ if (!android::base::ParseInt(options[4], &inputType)) {
+ return parseErrMsg("inputType", options[4], "int");
+ }
+ if (!android::base::ParseInt(options[5], &action)) {
+ return parseErrMsg("action", options[5], "int");
+ }
+ if (!android::base::ParseInt(options[6], &buttonState)) {
+ return parseErrMsg("buttonState", options[6], "int");
+ }
+
+ int32_t pointerId[pointerCount];
+ int32_t toolType[pointerCount];
+ float xData[pointerCount];
+ float yData[pointerCount];
+ float pressure[pointerCount];
+ float size[pointerCount];
+
+ for (int i = 7, pc = 0; i < optionsSize; i += 7, pc += 1) {
+ int offset = i;
+ if (options[offset] != "--pointer") {
+ return "--pointer is needed for the motion input\n";
+ }
+ offset += 1;
+ if (!android::base::ParseInt(options[offset], &pointerId[pc])) {
+ return parseErrMsg("pointerId", options[offset], "int");
+ }
+ offset += 1;
+ if (!android::base::ParseInt(options[offset], &toolType[pc])) {
+ return parseErrMsg("toolType", options[offset], "int");
+ }
+ offset += 1;
+ if (!android::base::ParseFloat(options[offset], &xData[pc])) {
+ return parseErrMsg("xData", options[offset], "float");
+ }
+ offset += 1;
+ if (!android::base::ParseFloat(options[offset], &yData[pc])) {
+ return parseErrMsg("yData", options[offset], "float");
+ }
+ offset += 1;
+ if (!android::base::ParseFloat(options[offset], &pressure[pc])) {
+ return parseErrMsg("pressure", options[offset], "float");
+ }
+ offset += 1;
+ if (!android::base::ParseFloat(options[offset], &size[pc])) {
+ return parseErrMsg("size", options[offset], "float");
+ }
+ }
+
+ // Send back to HAL
+ onValueChangeCallback(createHwMotionInputProp(area, display, inputType, action, buttonState,
+ pointerCount, pointerId, toolType, xData,
+ yData, pressure, size));
+
+ std::string successMessage = StringPrintf(
+ "motion event generated successfully with area:%d, display:%d,"
+ " inputType:%d, action:%d, buttonState:%d, pointerCount:%d\n",
+ area, display, inputType, action, buttonState, pointerCount);
+ for (int i = 0; i < pointerCount; i++) {
+ successMessage += StringPrintf(
+ "Pointer #%d {\n"
+ " id:%d , tooltype:%d \n"
+ " x:%f , y:%f\n"
+ " pressure: %f, data: %f\n"
+ "}\n",
+ i, pointerId[i], toolType[i], xData[i], yData[i], pressure[i], size[i]);
+ }
+ return successMessage;
}
return StringPrintf("Unknown command: \"%s\"\n%s", command.c_str(), genFakeDataHelp().c_str());
@@ -819,6 +956,59 @@
return value;
}
+VehiclePropValue FakeVehicleHardware::createHwKeyInputV2Prop(int32_t area, int32_t targetDisplay,
+ int32_t keyCode, int32_t action,
+ int32_t repeatCount) {
+ VehiclePropValue value = {.prop = toInt(VehicleProperty::HW_KEY_INPUT_V2),
+ .areaId = area,
+ .timestamp = elapsedRealtimeNano(),
+ .status = VehiclePropertyStatus::AVAILABLE,
+ .value.int32Values = {targetDisplay, keyCode, action, repeatCount},
+ .value.int64Values = {elapsedRealtimeNano()}};
+ return value;
+}
+
+VehiclePropValue FakeVehicleHardware::createHwMotionInputProp(
+ int32_t area, int32_t display, int32_t inputType, int32_t action, int32_t buttonState,
+ int32_t pointerCount, int32_t pointerId[], int32_t toolType[], float xData[], float yData[],
+ float pressure[], float size[]) {
+ std::vector<int> intValues;
+ intValues.push_back(display);
+ intValues.push_back(inputType);
+ intValues.push_back(action);
+ intValues.push_back(buttonState);
+ intValues.push_back(pointerCount);
+ for (int i = 0; i < pointerCount; i++) {
+ intValues.push_back(pointerId[i]);
+ }
+ for (int i = 0; i < pointerCount; i++) {
+ intValues.push_back(toolType[i]);
+ }
+
+ std::vector<float> floatValues;
+ for (int i = 0; i < pointerCount; i++) {
+ floatValues.push_back(xData[i]);
+ }
+ for (int i = 0; i < pointerCount; i++) {
+ floatValues.push_back(yData[i]);
+ }
+ for (int i = 0; i < pointerCount; i++) {
+ floatValues.push_back(pressure[i]);
+ }
+ for (int i = 0; i < pointerCount; i++) {
+ floatValues.push_back(size[i]);
+ }
+
+ VehiclePropValue value = {.prop = toInt(VehicleProperty::HW_MOTION_INPUT),
+ .areaId = area,
+ .timestamp = elapsedRealtimeNano(),
+ .status = VehiclePropertyStatus::AVAILABLE,
+ .value.int32Values = intValues,
+ .value.floatValues = floatValues,
+ .value.int64Values = {elapsedRealtimeNano()}};
+ return value;
+}
+
void FakeVehicleHardware::eventFromVehicleBus(const VehiclePropValue& value) {
mServerSidePropStore->writeValue(mValuePool->obtain(value));
}
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 0184462..79990ad 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
@@ -1776,7 +1776,61 @@
"failed to parse keyCode as int: \"0.1\""},
{"genfakedata_keypress_invalid_display",
{"--genfakedata", "--keypress", "1", "0.1"},
- "failed to parse display as int: \"0.1\""}};
+ "failed to parse display as int: \"0.1\""},
+ {"genfakedata_keyinputv2_incorrect_arguments",
+ {"--genfakedata", "--keyinputv2", "1", "1"},
+ "incorrect argument count, need 7 arguments for --genfakedata --keyinputv2\n"},
+ {"genfakedata_keyinputv2_invalid_area",
+ {"--genfakedata", "--keyinputv2", "0.1", "1", "1", "1", "1"},
+ "failed to parse area as int: \"0.1\""},
+ {"genfakedata_keyinputv2_invalid_display",
+ {"--genfakedata", "--keyinputv2", "1", "0.1", "1", "1", "1"},
+ "failed to parse display as int: \"0.1\""},
+ {"genfakedata_keyinputv2_invalid_keycode",
+ {"--genfakedata", "--keyinputv2", "1", "1", "0.1", "1", "1"},
+ "failed to parse keyCode as int: \"0.1\""},
+ {"genfakedata_keyinputv2_invalid_action",
+ {"--genfakedata", "--keyinputv2", "1", "1", "1", "0.1", "1"},
+ "failed to parse action as int: \"0.1\""},
+ {"genfakedata_keyinputv2_invalid_repeatcount",
+ {"--genfakedata", "--keyinputv2", "1", "1", "1", "1", "0.1"},
+ "failed to parse repeatCount as int: \"0.1\""},
+ {"genfakedata_motioninput_invalid_argument_count",
+ {"--genfakedata", "--motioninput", "1", "1", "1", "1", "1"},
+ "incorrect argument count, need at least 14 arguments for --genfakedata "
+ "--motioninput including at least 1 --pointer\n"},
+ {"genfakedata_motioninput_pointer_invalid_argument_count",
+ {"--genfakedata", "--motioninput", "1", "1", "1", "1", "1", "--pointer", "1", "1", "1",
+ "1", "1", "1", "--pointer"},
+ "incorrect argument count, need 6 arguments for every --pointer\n"},
+ {"genfakedata_motioninput_invalid_area",
+ {"--genfakedata", "--motioninput", "0.1", "1", "1", "1", "1", "--pointer", "1", "1",
+ "1", "1", "1", "1"},
+ "failed to parse area as int: \"0.1\""},
+ {"genfakedata_motioninput_invalid_display",
+ {"--genfakedata", "--motioninput", "1", "0.1", "1", "1", "1", "--pointer", "1", "1",
+ "1", "1", "1", "1"},
+ "failed to parse display as int: \"0.1\""},
+ {"genfakedata_motioninput_invalid_inputtype",
+ {"--genfakedata", "--motioninput", "1", "1", "0.1", "1", "1", "--pointer", "1", "1",
+ "1", "1", "1", "1"},
+ "failed to parse inputType as int: \"0.1\""},
+ {"genfakedata_motioninput_invalid_action",
+ {"--genfakedata", "--motioninput", "1", "1", "1", "0.1", "1", "--pointer", "1", "1",
+ "1", "1", "1", "1"},
+ "failed to parse action as int: \"0.1\""},
+ {"genfakedata_motioninput_invalid_buttonstate",
+ {"--genfakedata", "--motioninput", "1", "1", "1", "1", "0.1", "--pointer", "1", "1",
+ "1.2", "1.2", "1.2", "1.2"},
+ "failed to parse buttonState as int: \"0.1\""},
+ {"genfakedata_motioninput_invalid_pointerid",
+ {"--genfakedata", "--motioninput", "1", "1", "1", "1", "1", "--pointer", "0.1", "1",
+ "1.2", "1", "1", "1"},
+ "failed to parse pointerId as int: \"0.1\""},
+ {"genfakedata_motioninput_invalid_tooltype",
+ {"--genfakedata", "--motioninput", "1", "1", "1", "1", "1", "--pointer", "1", "0.1",
+ "1.2", "1", "1", "1"},
+ "failed to parse toolType as int: \"0.1\""}};
}
TEST_P(FakeVehicleHardwareOptionsTest, testInvalidOptions) {
@@ -1965,6 +2019,78 @@
EXPECT_EQ(2, events[1].value.int32Values[2]);
}
+TEST_F(FakeVehicleHardwareTest, testDebugGenFakeDataKeyInputV2) {
+ std::vector<std::string> options = {"--genfakedata", "--keyinputv2", "1", "2", "3", "4", "5"};
+
+ DumpResult result = getHardware()->dump(options);
+
+ ASSERT_FALSE(result.callerShouldDumpState);
+ ASSERT_THAT(result.buffer, HasSubstr("successfully"));
+
+ auto events = getChangedProperties();
+ ASSERT_EQ(1u, events.size());
+ EXPECT_EQ(toInt(VehicleProperty::HW_KEY_INPUT_V2), events[0].prop);
+ ASSERT_EQ(4u, events[0].value.int32Values.size());
+ EXPECT_EQ(2, events[0].value.int32Values[0]);
+ EXPECT_EQ(3, events[0].value.int32Values[1]);
+ EXPECT_EQ(4, events[0].value.int32Values[2]);
+ EXPECT_EQ(5, events[0].value.int32Values[3]);
+ ASSERT_EQ(1u, events[0].value.int64Values.size());
+}
+
+TEST_F(FakeVehicleHardwareTest, testDebugGenFakeDataMotionInput) {
+ std::vector<std::string> options = {"--genfakedata",
+ "--motioninput",
+ "1",
+ "2",
+ "3",
+ "4",
+ "5",
+ "--pointer",
+ "11",
+ "22",
+ "33.3",
+ "44.4",
+ "55.5",
+ "66.6",
+ "--pointer",
+ "21",
+ "32",
+ "43.3",
+ "54.4",
+ "65.5",
+ "76.6"};
+
+ DumpResult result = getHardware()->dump(options);
+
+ ASSERT_FALSE(result.callerShouldDumpState);
+ ASSERT_THAT(result.buffer, HasSubstr("successfully"));
+
+ auto events = getChangedProperties();
+ ASSERT_EQ(1u, events.size());
+ EXPECT_EQ(toInt(VehicleProperty::HW_MOTION_INPUT), events[0].prop);
+ ASSERT_EQ(9u, events[0].value.int32Values.size());
+ EXPECT_EQ(2, events[0].value.int32Values[0]);
+ EXPECT_EQ(3, events[0].value.int32Values[1]);
+ EXPECT_EQ(4, events[0].value.int32Values[2]);
+ EXPECT_EQ(5, events[0].value.int32Values[3]);
+ EXPECT_EQ(2, events[0].value.int32Values[4]);
+ EXPECT_EQ(11, events[0].value.int32Values[5]);
+ EXPECT_EQ(21, events[0].value.int32Values[6]);
+ EXPECT_EQ(22, events[0].value.int32Values[7]);
+ EXPECT_EQ(32, events[0].value.int32Values[8]);
+ ASSERT_EQ(8u, events[0].value.floatValues.size());
+ EXPECT_FLOAT_EQ(33.3, events[0].value.floatValues[0]);
+ EXPECT_FLOAT_EQ(43.3, events[0].value.floatValues[1]);
+ EXPECT_FLOAT_EQ(44.4, events[0].value.floatValues[2]);
+ EXPECT_FLOAT_EQ(54.4, events[0].value.floatValues[3]);
+ EXPECT_FLOAT_EQ(55.5, events[0].value.floatValues[4]);
+ EXPECT_FLOAT_EQ(65.5, events[0].value.floatValues[5]);
+ EXPECT_FLOAT_EQ(66.6, events[0].value.floatValues[6]);
+ EXPECT_FLOAT_EQ(76.6, events[0].value.floatValues[7]);
+ ASSERT_EQ(1u, events[0].value.int64Values.size());
+}
+
TEST_F(FakeVehicleHardwareTest, testGetEchoReverseBytes) {
ASSERT_EQ(setValue(VehiclePropValue{
.prop = ECHO_REVERSE_BYTES,
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/PropertyUtils.h b/automotive/vehicle/aidl/impl/utils/common/include/PropertyUtils.h
index bf27c95..7275ba3 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/PropertyUtils.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/PropertyUtils.h
@@ -28,6 +28,7 @@
namespace propertyutils_impl {
// These names are not part of the API since we only expose ints.
+using ::aidl::android::hardware::automotive::vehicle::EvStoppingMode;
using ::aidl::android::hardware::automotive::vehicle::PortLocationType;
using ::aidl::android::hardware::automotive::vehicle::VehicleArea;
using ::aidl::android::hardware::automotive::vehicle::VehicleAreaDoor;
@@ -98,7 +99,11 @@
constexpr int LIGHT_STATE_ON = toInt(propertyutils_impl::VehicleLightState::ON);
constexpr int LIGHT_STATE_OFF = toInt(propertyutils_impl::VehicleLightState::OFF);
constexpr int LIGHT_SWITCH_OFF = toInt(propertyutils_impl::VehicleLightSwitch::OFF);
+constexpr int LIGHT_SWITCH_ON = toInt(propertyutils_impl::VehicleLightSwitch::ON);
constexpr int LIGHT_SWITCH_AUTO = toInt(propertyutils_impl::VehicleLightSwitch::AUTOMATIC);
+constexpr int EV_STOPPING_MODE_CREEP = toInt(propertyutils_impl::EvStoppingMode::CREEP);
+constexpr int EV_STOPPING_MODE_ROLL = toInt(propertyutils_impl::EvStoppingMode::ROLL);
+constexpr int EV_STOPPING_MODE_HOLD = toInt(propertyutils_impl::EvStoppingMode::HOLD);
constexpr int WHEEL_FRONT_LEFT = toInt(propertyutils_impl::VehicleAreaWheel::LEFT_FRONT);
constexpr int WHEEL_FRONT_RIGHT = toInt(propertyutils_impl::VehicleAreaWheel::RIGHT_FRONT);
constexpr int WHEEL_REAR_LEFT = toInt(propertyutils_impl::VehicleAreaWheel::LEFT_REAR);
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h b/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h
index 08e1990..0915701 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h
@@ -20,6 +20,7 @@
#include <aidl/android/hardware/automotive/vehicle/DiagnosticFloatSensorIndex.h>
#include <aidl/android/hardware/automotive/vehicle/DiagnosticIntegerSensorIndex.h>
#include <aidl/android/hardware/automotive/vehicle/EvConnectorType.h>
+#include <aidl/android/hardware/automotive/vehicle/EvStoppingMode.h>
#include <aidl/android/hardware/automotive/vehicle/EvsServiceState.h>
#include <aidl/android/hardware/automotive/vehicle/EvsServiceType.h>
#include <aidl/android/hardware/automotive/vehicle/FuelType.h>
diff --git a/automotive/vehicle/aidl/impl/vhal/src/VehicleService.cpp b/automotive/vehicle/aidl/impl/vhal/src/VehicleService.cpp
index c8b5c65..f8a4e7d 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/VehicleService.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/VehicleService.cpp
@@ -27,6 +27,13 @@
using ::android::hardware::automotive::vehicle::fake::FakeVehicleHardware;
int main(int /* argc */, char* /* argv */[]) {
+ ALOGI("Starting thread pool...");
+ if (!ABinderProcess_setThreadPoolMaxThreadCount(4)) {
+ ALOGE("%s", "failed to set thread pool max thread count");
+ return 1;
+ }
+ ABinderProcess_startThreadPool();
+
std::unique_ptr<FakeVehicleHardware> hardware = std::make_unique<FakeVehicleHardware>();
std::shared_ptr<DefaultVehicleHal> vhal =
::ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
@@ -39,12 +46,6 @@
return 1;
}
- if (!ABinderProcess_setThreadPoolMaxThreadCount(4)) {
- ALOGE("%s", "failed to set thread pool max thread count");
- return 1;
- }
- ABinderProcess_startThreadPool();
-
ALOGI("Vehicle Service Ready");
ABinderProcess_joinThreadPool();
diff --git a/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp b/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
index 5595afe..1680442 100644
--- a/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
+++ b/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
@@ -481,12 +481,42 @@
actualPropertyType);
}
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyEmergencyLaneKeepAssistEnabledConfig) {
+ verifyProperty(VehicleProperty::EMERGENCY_LANE_KEEP_ASSIST_ENABLED,
+ VehiclePropertyAccess::READ_WRITE, VehiclePropertyChangeMode::ON_CHANGE,
+ VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyAdaptiveCruiseControlEnabledConfig) {
+ verifyProperty(VehicleProperty::ADAPTIVE_CRUISE_CONTROL_ENABLED,
+ VehiclePropertyAccess::READ_WRITE, VehiclePropertyChangeMode::ON_CHANGE,
+ VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyHandsOnDetectionEnabledConfig) {
+ verifyProperty(VehicleProperty::HANDS_ON_DETECTION_ENABLED, VehiclePropertyAccess::READ_WRITE,
+ VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+ VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyDriverAttentionMonitoringEnabledConfig) {
+ verifyProperty(VehicleProperty::DRIVER_ATTENTION_MONITORING_ENABLED,
+ VehiclePropertyAccess::READ_WRITE, VehiclePropertyChangeMode::ON_CHANGE,
+ VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
+}
+
TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyEvBrakeRegenerationLevelConfig) {
verifyProperty(VehicleProperty::EV_BRAKE_REGENERATION_LEVEL,
VehiclePropertyAccess::READ_WRITE, VehiclePropertyChangeMode::ON_CHANGE,
VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::INT32);
}
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyEvStoppingModeConfig) {
+ verifyProperty(VehicleProperty::EV_STOPPING_MODE, VehiclePropertyAccess::READ_WRITE,
+ VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+ VehicleArea::GLOBAL, VehiclePropertyType::INT32);
+}
+
TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyEvCurrentBatteryCapacityConfig) {
verifyProperty(VehicleProperty::EV_CURRENT_BATTERY_CAPACITY, VehiclePropertyAccess::READ,
VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
@@ -547,6 +577,18 @@
VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
}
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifySteeringWheelLightsStateConfig) {
+ verifyProperty(VehicleProperty::STEERING_WHEEL_LIGHTS_STATE, VehiclePropertyAccess::READ,
+ VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+ VehicleArea::GLOBAL, VehiclePropertyType::INT32);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifySteeringWheelLightsSwitchConfig) {
+ verifyProperty(VehicleProperty::STEERING_WHEEL_LIGHTS_SWITCH, VehiclePropertyAccess::READ_WRITE,
+ VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+ VehicleArea::GLOBAL, VehiclePropertyType::INT32);
+}
+
TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyMirrorAutoFoldEnabledConfig) {
verifyProperty(VehicleProperty::MIRROR_AUTO_FOLD_ENABLED, VehiclePropertyAccess::READ_WRITE,
VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
@@ -559,12 +601,30 @@
VehicleArea::MIRROR, VehiclePropertyType::BOOLEAN);
}
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifySeatHeadrestHeightPosV2Config) {
+ verifyProperty(VehicleProperty::SEAT_HEADREST_HEIGHT_POS_V2, VehiclePropertyAccess::READ_WRITE,
+ VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+ VehicleArea::SEAT, VehiclePropertyType::INT32);
+}
+
TEST_P(VtsHalAutomotiveVehicleTargetTest, verifySeatWalkInPosConfig) {
verifyProperty(VehicleProperty::SEAT_WALK_IN_POS, VehiclePropertyAccess::READ_WRITE,
VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
VehicleArea::SEAT, VehiclePropertyType::INT32);
}
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifySeatFootwellLightsStateConfig) {
+ verifyProperty(VehicleProperty::SEAT_FOOTWELL_LIGHTS_STATE, VehiclePropertyAccess::READ,
+ VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+ VehicleArea::SEAT, VehiclePropertyType::INT32);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifySeatFootwellLightsSwitchConfig) {
+ verifyProperty(VehicleProperty::SEAT_FOOTWELL_LIGHTS_SWITCH, VehiclePropertyAccess::READ_WRITE,
+ VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+ VehicleArea::SEAT, VehiclePropertyType::INT32);
+}
+
TEST_P(VtsHalAutomotiveVehicleTargetTest, verifySeatEasyAccessEnabledConfig) {
verifyProperty(VehicleProperty::SEAT_EASY_ACCESS_ENABLED, VehiclePropertyAccess::READ_WRITE,
VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
@@ -601,6 +661,42 @@
VehicleArea::SEAT, VehiclePropertyType::INT32);
}
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyAutomaticEmergencyBrakingEnabledConfig) {
+ verifyProperty(VehicleProperty::AUTOMATIC_EMERGENCY_BRAKING_ENABLED,
+ VehiclePropertyAccess::READ_WRITE, VehiclePropertyChangeMode::ON_CHANGE,
+ VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyForwardCollisionWarningEnabledConfig) {
+ verifyProperty(VehicleProperty::FORWARD_COLLISION_WARNING_ENABLED,
+ VehiclePropertyAccess::READ_WRITE, VehiclePropertyChangeMode::ON_CHANGE,
+ VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyBlindSpotWarningEnabledConfig) {
+ verifyProperty(VehicleProperty::BLIND_SPOT_WARNING_ENABLED, VehiclePropertyAccess::READ_WRITE,
+ VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+ VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyLaneDepartureWarningEnabledConfig) {
+ verifyProperty(VehicleProperty::LANE_DEPARTURE_WARNING_ENABLED,
+ VehiclePropertyAccess::READ_WRITE, VehiclePropertyChangeMode::ON_CHANGE,
+ VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyLaneKeepAssistEnabledConfig) {
+ verifyProperty(VehicleProperty::LANE_KEEP_ASSIST_ENABLED, VehiclePropertyAccess::READ_WRITE,
+ VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+ VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyLaneCenteringAssistEnabledConfig) {
+ verifyProperty(VehicleProperty::LANE_CENTERING_ASSIST_ENABLED,
+ VehiclePropertyAccess::READ_WRITE, VehiclePropertyChangeMode::ON_CHANGE,
+ VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
+}
+
std::vector<ServiceDescriptor> getDescriptors() {
std::vector<ServiceDescriptor> descriptors;
for (std::string name : getAidlHalInstanceNames(IVehicle::descriptor)) {
diff --git a/camera/device/3.2/default/convert.cpp b/camera/device/3.2/default/convert.cpp
index 06ad7e9..2075607 100644
--- a/camera/device/3.2/default/convert.cpp
+++ b/camera/device/3.2/default/convert.cpp
@@ -16,6 +16,7 @@
#define LOG_TAG "android.hardware.camera.device@3.2-convert-impl"
#include <log/log.h>
+#include <system/camera_metadata.h>
#include "include/convert.h"
@@ -43,6 +44,13 @@
ALOGE("%s: input CameraMetadata is corrupt!", __FUNCTION__);
return false;
}
+
+ if (validate_camera_metadata_structure((camera_metadata_t*)data, /*expected_size=*/NULL) !=
+ OK) {
+ ALOGE("%s: Failed to validate the metadata structure", __FUNCTION__);
+ return false;
+ }
+
*dst = (camera_metadata_t*) data;
return true;
}
diff --git a/camera/provider/aidl/vts/camera_aidl_test.h b/camera/provider/aidl/vts/camera_aidl_test.h
index 8b8a4bc..f13d6b2 100644
--- a/camera/provider/aidl/vts/camera_aidl_test.h
+++ b/camera/provider/aidl/vts/camera_aidl_test.h
@@ -17,7 +17,10 @@
#ifndef HARDWARE_INTERFACES_CAMERA_PROVIDER_AIDL_VTS_CAMERA_AIDL_TEST_H_
#define HARDWARE_INTERFACES_CAMERA_PROVIDER_AIDL_VTS_CAMERA_AIDL_TEST_H_
+// TODO: LOG_TAG should not be in header
+#ifndef LOG_TAG
#define LOG_TAG "camera_aidl_hal_test"
+#endif
#include <string>
#include <unordered_map>
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index e7bb282..9b2175a 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -78,6 +78,7 @@
</hal>
<hal format="aidl" optional="true">
<name>android.hardware.automotive.audiocontrol</name>
+ <version>2</version>
<interface>
<name>IAudioControl</name>
<instance>default</instance>
@@ -306,6 +307,7 @@
<instance>default</instance>
</interface>
</hal>
+ <!-- Either the native or the HIDL mapper HAL must exist on the device -->
<hal format="hidl" optional="true">
<name>android.hardware.graphics.mapper</name>
<!-- New, non-Go devices should use 4.0, tested in vts_treble_vintf_vendor_test -->
@@ -616,6 +618,14 @@
<instance>default</instance>
</interface>
</hal>
+ <hal format="hidl" optional="true">
+ <name>android.hardware.soundtrigger</name>
+ <version>2.3</version>
+ <interface>
+ <name>ISoundTriggerHw</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
<hal format="aidl" optional="true">
<name>android.hardware.soundtrigger3</name>
<version>1</version>
@@ -656,6 +666,13 @@
</interface>
</hal>
<hal format="aidl" optional="true">
+ <name>android.hardware.tv.earc</name>
+ <interface>
+ <name>IEArc</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+ <hal format="aidl" optional="true">
<name>android.hardware.tv.hdmi</name>
<interface>
<name>IHdmi</name>
@@ -765,4 +782,13 @@
<instance>default</instance>
</interface>
</hal>
+ <!-- Either the native or the HIDL mapper HAL must exist on the device -->
+ <hal format="native" optional="true">
+ <name>mapper</name>
+ <version>5.0</version>
+ <interface>
+ <name>I</name>
+ <regex-instance>.*</regex-instance>
+ </interface>
+ </hal>
</compatibility-matrix>
diff --git a/contexthub/1.0/default/OWNERS b/contexthub/1.0/default/OWNERS
deleted file mode 100644
index 90c2330..0000000
--- a/contexthub/1.0/default/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-arthuri@google.com
-bduddie@google.com
-stange@google.com
diff --git a/contexthub/1.1/default/OWNERS b/contexthub/1.1/default/OWNERS
deleted file mode 100644
index 90c2330..0000000
--- a/contexthub/1.1/default/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-arthuri@google.com
-bduddie@google.com
-stange@google.com
diff --git a/contexthub/1.1/vts/functional/OWNERS b/contexthub/1.1/vts/functional/OWNERS
deleted file mode 100644
index 2cf5bca..0000000
--- a/contexthub/1.1/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 156070
-include ../../../1.0/vts/functional/OWNERS
diff --git a/contexthub/1.2/default/OWNERS b/contexthub/1.2/default/OWNERS
deleted file mode 100644
index 90c2330..0000000
--- a/contexthub/1.2/default/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-arthuri@google.com
-bduddie@google.com
-stange@google.com
diff --git a/contexthub/1.2/vts/functional/OWNERS b/contexthub/1.2/vts/functional/OWNERS
deleted file mode 100644
index 2cf5bca..0000000
--- a/contexthub/1.2/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 156070
-include ../../../1.0/vts/functional/OWNERS
diff --git a/contexthub/1.0/vts/functional/OWNERS b/contexthub/OWNERS
similarity index 81%
rename from contexthub/1.0/vts/functional/OWNERS
rename to contexthub/OWNERS
index f254cd5..d5cfc2e 100644
--- a/contexthub/1.0/vts/functional/OWNERS
+++ b/contexthub/OWNERS
@@ -1,5 +1,4 @@
# Bug component: 156070
-#Context Hub team
arthuri@google.com
bduddie@google.com
stange@google.com
diff --git a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl
index 272d768..c1f4df8 100644
--- a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl
+++ b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl
@@ -46,5 +46,6 @@
void onHostEndpointConnected(in android.hardware.contexthub.HostEndpointInfo hostEndpointInfo);
void onHostEndpointDisconnected(char hostEndpointId);
long[] getPreloadedNanoappIds();
+ void onNanSessionStateChanged(in boolean state);
const int EX_CONTEXT_HUB_UNSPECIFIED = -1;
}
diff --git a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHubCallback.aidl b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHubCallback.aidl
index f81f7cf..e72ae73 100644
--- a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHubCallback.aidl
+++ b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHubCallback.aidl
@@ -38,4 +38,6 @@
void handleContextHubMessage(in android.hardware.contexthub.ContextHubMessage msg, in String[] msgContentPerms);
void handleContextHubAsyncEvent(in android.hardware.contexthub.AsyncEventType evt);
void handleTransactionResult(in int transactionId, in boolean success);
+ void handleNanSessionRequest(in boolean enable);
+ const int CONTEXTHUB_NAN_TRANSACTION_TIMEOUT_MS = 10000;
}
diff --git a/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl b/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl
index 9fa67a5..7f50730 100644
--- a/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl
+++ b/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl
@@ -204,6 +204,19 @@
long[] getPreloadedNanoappIds();
/**
+ * Invoked when the state of the NAN session requested through handleNanSessionRequest()
+ * changes. This function may be invoked without a corresponding handleNanSessionRequest to
+ * indicate if a NAN session was terminated without a request due to resource limitations.
+ *
+ * If the state becomes disabled without an explicit request from the HAL, the HAL MUST
+ * explicitly invoke handleNanSessionRequest() at a later point in time to attempt to
+ * re-enable NAN.
+ *
+ * @param state True if the NAN session is currently enabled.
+ */
+ void onNanSessionStateChanged(in boolean state);
+
+ /**
* Error codes that are used as service specific errors with the AIDL return
* value EX_SERVICE_SPECIFIC.
*/
diff --git a/contexthub/aidl/android/hardware/contexthub/IContextHubCallback.aidl b/contexthub/aidl/android/hardware/contexthub/IContextHubCallback.aidl
index e385d48..cff1893 100644
--- a/contexthub/aidl/android/hardware/contexthub/IContextHubCallback.aidl
+++ b/contexthub/aidl/android/hardware/contexthub/IContextHubCallback.aidl
@@ -74,4 +74,25 @@
*
*/
void handleTransactionResult(in int transactionId, in boolean success);
+
+ /**
+ * This callback is passed by the Contexthub service to the HAL implementation to allow the HAL
+ * to request a WiFi NAN session is created to allow the Contexthub to be able to utilize NAN
+ * functionality.
+ *
+ * onNanSessionStateChanged() will be invoked asynchronously after the NAN session request has
+ * been completed. This must be done within CONTEXTHUB_NAN_TRANSACTION_TIMEOUT_MS. If the
+ * request times out, onNanSessionStateChanged() will be invoked with the state that the session
+ * was previously in.
+ *
+ * @param enable Whether the NAN session should be enabled or disabled depending on whether the
+ * Contexthub needs access to NAN.
+ */
+ void handleNanSessionRequest(in boolean enable);
+
+ /**
+ * Amount of time, in milliseconds, that a handleNanSessionRequest can be pending before the
+ * Contexthub service must respond.
+ */
+ const int CONTEXTHUB_NAN_TRANSACTION_TIMEOUT_MS = 10000;
}
diff --git a/contexthub/aidl/default/ContextHub.cpp b/contexthub/aidl/default/ContextHub.cpp
index ac1dc46..615ac5c 100644
--- a/contexthub/aidl/default/ContextHub.cpp
+++ b/contexthub/aidl/default/ContextHub.cpp
@@ -87,6 +87,10 @@
return ndk::ScopedAStatus::ok();
}
+ScopedAStatus ContextHub::onNanSessionStateChanged(bool /*sin_state*/) {
+ return ndk::ScopedAStatus::ok();
+}
+
ScopedAStatus ContextHub::registerCallback(int32_t in_contextHubId,
const std::shared_ptr<IContextHubCallback>& in_cb) {
if (in_contextHubId == kMockHubId) {
diff --git a/contexthub/aidl/default/include/contexthub-impl/ContextHub.h b/contexthub/aidl/default/include/contexthub-impl/ContextHub.h
index 4aeb948..b3998b9 100644
--- a/contexthub/aidl/default/include/contexthub-impl/ContextHub.h
+++ b/contexthub/aidl/default/include/contexthub-impl/ContextHub.h
@@ -47,6 +47,7 @@
::ndk::ScopedAStatus onHostEndpointConnected(const HostEndpointInfo& in_info) override;
::ndk::ScopedAStatus onHostEndpointDisconnected(char16_t in_hostEndpointId) override;
+ ::ndk::ScopedAStatus onNanSessionStateChanged(bool in_state) override;
private:
static constexpr uint32_t kMockHubId = 0;
diff --git a/contexthub/aidl/vts/OWNERS b/contexthub/aidl/vts/OWNERS
deleted file mode 100644
index 150818d..0000000
--- a/contexthub/aidl/vts/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-file:/contexthub/common/vts/OWNERS
diff --git a/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp b/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp
index 8104f27..4731648 100644
--- a/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp
+++ b/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp
@@ -100,6 +100,8 @@
Status handleTransactionResult(int32_t /* transactionId */, bool /* success */) override {
return Status::ok();
}
+
+ Status handleNanSessionRequest(bool /* enable */) override { return Status::ok(); }
};
TEST_P(ContextHubAidl, TestRegisterCallback) {
@@ -131,6 +133,8 @@
return Status::ok();
}
+ Status handleNanSessionRequest(bool /* enable */) override { return Status::ok(); }
+
std::promise<std::vector<NanoappInfo>> promise;
};
@@ -194,6 +198,8 @@
return Status::ok();
}
+ Status handleNanSessionRequest(bool /* enable */) override { return Status::ok(); }
+
uint32_t expectedTransactionId = 0;
std::promise<bool> promise;
};
@@ -354,6 +360,11 @@
ASSERT_TRUE(contextHub->onHostEndpointDisconnected(kHostEndpointId).isOk());
}
+TEST_P(ContextHubAidl, TestNanSessionStateChange) {
+ ASSERT_TRUE(contextHub->onNanSessionStateChanged(true /*state*/).isOk());
+ ASSERT_TRUE(contextHub->onNanSessionStateChanged(false /*state*/).isOk());
+}
+
std::string PrintGeneratedTest(const testing::TestParamInfo<ContextHubAidl::ParamType>& info) {
return std::string("CONTEXT_HUB_ID_") + std::to_string(std::get<1>(info.param));
}
diff --git a/contexthub/common/default/1.X/OWNERS b/contexthub/common/default/1.X/OWNERS
deleted file mode 100644
index 90c2330..0000000
--- a/contexthub/common/default/1.X/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-arthuri@google.com
-bduddie@google.com
-stange@google.com
diff --git a/contexthub/common/vts/OWNERS b/contexthub/common/vts/OWNERS
deleted file mode 100644
index 161b2f0..0000000
--- a/contexthub/common/vts/OWNERS
+++ /dev/null
@@ -1,8 +0,0 @@
-#Context Hub team
-arthuri@google.com
-bduddie@google.com
-stange@google.com
-
-#VTS team
-dshi@google.com
-trong@google.com
diff --git a/current.txt b/current.txt
index 0fb8b49..fbdd3fe 100644
--- a/current.txt
+++ b/current.txt
@@ -932,5 +932,6 @@
# ABI preserving changes to HALs during Android U
2aa559cda86c358c6429114ef6bc72c1b43281e98f9eb6b4df5e7073c8d05767 android.hardware.automotive.vehicle@2.0::types
42abd285a4293dadb8c89bc63b90cae2872fbffe90c4517aa3ea4965e8aecff7 android.hardware.graphics.common@1.2::types
+4f1a02d21a22104c734f71cdbba19b6f7e93d4ee107ff79f0dbdd171a8430e0e android.hardware.automotive.vehicle@2.0::types
# There will be no more HIDL HALs. Use AIDL instead.
diff --git a/gnss/aidl/android/hardware/gnss/GnssData.aidl b/gnss/aidl/android/hardware/gnss/GnssData.aidl
index 492ba31..1bd8d48 100644
--- a/gnss/aidl/android/hardware/gnss/GnssData.aidl
+++ b/gnss/aidl/android/hardware/gnss/GnssData.aidl
@@ -104,7 +104,7 @@
* True indicates that the GNSS chipset switches off duty cycling. In such mode, no clock
* discontinuities are expected and, when supported, carrier phase should be continuous in good
* signal conditions. All non-blocklisted, healthy constellations, satellites and frequency
- * bands must be tracked and reported in this mode.
+ * bands that are meaningful to positioning accuracy must be tracked and reported in this mode.
*
* False indicates that the GNSS chipset optimizes power via duty cycling, constellations and
* frequency limits, etc.
diff --git a/gnss/aidl/android/hardware/gnss/IGnssMeasurementInterface.aidl b/gnss/aidl/android/hardware/gnss/IGnssMeasurementInterface.aidl
index 4316407..33e9008 100644
--- a/gnss/aidl/android/hardware/gnss/IGnssMeasurementInterface.aidl
+++ b/gnss/aidl/android/hardware/gnss/IGnssMeasurementInterface.aidl
@@ -36,9 +36,9 @@
* If true, GNSS chipset must switch off duty cycling. In such mode no clock discontinuities
* are expected and, when supported, carrier phase should be continuous in good signal
* conditions. All non-blocklisted, healthy constellations, satellites and frequency bands
- * that the chipset supports must be reported in this mode. The GNSS chipset is allowed to
- * consume more power in this mode. If false, API must optimize power via duty cycling,
- * constellations and frequency limits, etc.
+ * that are meaningful to positioning accuracy must be tracked and reported in this mode.
+ * The GNSS chipset is allowed to consume more power in this mode. If false, API must
+ * optimize power via duty cycling, constellations and frequency limits, etc.
*/
boolean enableFullTracking;
diff --git a/graphics/Android.bp b/graphics/Android.bp
index 4898dbe..2fbcb41 100644
--- a/graphics/Android.bp
+++ b/graphics/Android.bp
@@ -21,6 +21,9 @@
static_libs: [
"android.hardware.graphics.allocator-V2-ndk",
],
+ defaults: [
+ "android.hardware.graphics.common-ndk_static",
+ ],
}
cc_defaults {
@@ -28,6 +31,9 @@
shared_libs: [
"android.hardware.graphics.allocator-V2-ndk",
],
+ defaults: [
+ "android.hardware.graphics.common-ndk_shared",
+ ],
}
cc_defaults {
diff --git a/graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl b/graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl
index 980e246..49c2497 100644
--- a/graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl
+++ b/graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl
@@ -41,4 +41,5 @@
android.hardware.graphics.common.PixelFormat format = android.hardware.graphics.common.PixelFormat.UNSPECIFIED;
android.hardware.graphics.common.BufferUsage usage = android.hardware.graphics.common.BufferUsage.CPU_READ_NEVER;
long reservedSize;
+ android.hardware.graphics.common.ExtendableType[] additionalOptions;
}
diff --git a/graphics/allocator/aidl/android/hardware/graphics/allocator/AllocationResult.aidl b/graphics/allocator/aidl/android/hardware/graphics/allocator/AllocationResult.aidl
index 0774e25..76f1c95 100644
--- a/graphics/allocator/aidl/android/hardware/graphics/allocator/AllocationResult.aidl
+++ b/graphics/allocator/aidl/android/hardware/graphics/allocator/AllocationResult.aidl
@@ -18,13 +18,17 @@
import android.hardware.common.NativeHandle;
- /**
+/**
* Result of an IAllocator::allocate call.
*
* @sa +ndk libnativewindow#AHardwareBuffer_Desc
*/
@VintfStability
parcelable AllocationResult {
+ /**
+ * The number of pixels between two consecutive rows of an allocated buffer, when the concept
+ * of consecutive rows is defined. Otherwise, it has no meaning.
+ */
int stride;
NativeHandle[] buffers;
-}
\ No newline at end of file
+}
diff --git a/graphics/allocator/aidl/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl b/graphics/allocator/aidl/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl
index ffc50b8..50aa2b7 100644
--- a/graphics/allocator/aidl/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl
+++ b/graphics/allocator/aidl/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl
@@ -17,6 +17,7 @@
package android.hardware.graphics.allocator;
import android.hardware.graphics.common.BufferUsage;
+import android.hardware.graphics.common.ExtendableType;
import android.hardware.graphics.common.PixelFormat;
@VintfStability
@@ -54,6 +55,9 @@
/**
* Buffer usage mask; valid flags can be found in the definition of
* BufferUsage.aidl in graphics/common
+ *
+ * The allocator must report isSupported() == false and reject any allocations
+ * with unrecognized buffer usages.
*/
BufferUsage usage = BufferUsage.CPU_READ_NEVER;
@@ -62,4 +66,16 @@
* See getReservedRegion for more information.
*/
long reservedSize;
+
+ /**
+ * Extensible additional options that can be set.
+ *
+ * This is intended for options that do not change the overall usage, but which do impact
+ * how a buffer is allocated. An example of this is compression level, such as for
+ * the EGL_EXT_surface_compression extension.
+ *
+ * The allocator must report isSupported() == false and reject any allocations
+ * with unrecognized options.
+ */
+ ExtendableType[] additionalOptions;
}
diff --git a/graphics/allocator/aidl/vts/VtsHalGraphicsAllocatorAidl_TargetTest.cpp b/graphics/allocator/aidl/vts/VtsHalGraphicsAllocatorAidl_TargetTest.cpp
index 09f1c15..4778020 100644
--- a/graphics/allocator/aidl/vts/VtsHalGraphicsAllocatorAidl_TargetTest.cpp
+++ b/graphics/allocator/aidl/vts/VtsHalGraphicsAllocatorAidl_TargetTest.cpp
@@ -217,6 +217,8 @@
}
return ret;
}
+
+ int32_t allocatorVersion() const { return mIAllocatorVersion; }
};
BufferHandle::~BufferHandle() {
@@ -309,6 +311,62 @@
EXPECT_GE(buffer->stride(), 64);
}
+TEST_P(GraphicsAllocatorAidlTests, RejectsUnknownUsages) {
+ if (allocatorVersion() < 2) {
+ GTEST_SKIP() << "Must be version 2+";
+ return;
+ }
+
+ constexpr auto FirstInvalidV2Usage = static_cast<BufferUsage>(1LL << 33);
+
+ BufferUsage invalidUsage;
+ if (allocatorVersion() == 2) {
+ invalidUsage = FirstInvalidV2Usage;
+ } else {
+ GTEST_FAIL() << "Unknown version " << allocatorVersion();
+ }
+
+ BufferDescriptorInfo info{
+ .name = {"CPU_8888"},
+ .width = 64,
+ .height = 64,
+ .layerCount = 1,
+ .format = PixelFormat::RGBA_8888,
+ .usage = BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN,
+ .reservedSize = 0,
+ };
+
+ // First make sure we can allocate a known usage buffer as expected
+ EXPECT_TRUE(isSupported(info));
+ EXPECT_TRUE(allocate(info));
+
+ // Now add the unknown bit and verify it's rejected
+ info.usage |= invalidUsage;
+ EXPECT_FALSE(isSupported(info)) << "isSupported() returned true for unknown-to-HAL usage";
+ EXPECT_FALSE(allocate(info)) << "allocate succeeded for unknown-to-HAL usage";
+}
+
+TEST_P(GraphicsAllocatorAidlTests, RejectsUnknownOptions) {
+ if (allocatorVersion() < 2) {
+ GTEST_SKIP() << "Must be version 2+";
+ return;
+ }
+
+ BufferDescriptorInfo info{
+ .name = {"CPU_8888"},
+ .width = 64,
+ .height = 64,
+ .layerCount = 1,
+ .format = PixelFormat::RGBA_8888,
+ .usage = BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN,
+ .reservedSize = 0,
+ };
+ info.additionalOptions.push_back({"android.hardware.graphics.common.NotARealOption", 1});
+
+ EXPECT_FALSE(isSupported(info)) << "isSupported() returned true for unknown-to-HAL option";
+ EXPECT_FALSE(allocate(info)) << "allocate succeeded for unknown-to-HAL option";
+}
+
TEST_P(GraphicsFrontBufferTests, FrontBufferGpuToCpu) {
BufferDescriptorInfo info{
.name = {"CPU_8888"},
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/StandardMetadataType.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/StandardMetadataType.aidl
index 06b31a2..6e2e106 100644
--- a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/StandardMetadataType.aidl
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/StandardMetadataType.aidl
@@ -58,4 +58,5 @@
CTA861_3 = 20,
SMPTE2094_40 = 21,
SMPTE2094_10 = 22,
+ STRIDE = 23,
}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl b/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl
index 4bca795..8cfdae6 100644
--- a/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl
+++ b/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl
@@ -368,4 +368,17 @@
* If this is unset when encoded into a byte stream, the byte stream is empty.
*/
SMPTE2094_10 = 22,
+
+ /**
+ * Can be used to get the stride in pixels of the buffer allocation. This is the number of
+ * pixels between two consecutive rows of an allocated buffer, when the concept of consecutive
+ * rows is defined. Otherwise, it has no meaning.
+ *
+ * Must match the value returned in android.hardware.graphics.allocator.AllocationResult#stride
+ *
+ * This is required metadata in mapper5 and should be read-only.
+ *
+ * The metadata type is a uint32_t.
+ */
+ STRIDE = 23,
}
diff --git a/graphics/composer/aidl/vts/VtsComposerClient.cpp b/graphics/composer/aidl/vts/VtsComposerClient.cpp
index 00b578b..43f4b84 100644
--- a/graphics/composer/aidl/vts/VtsComposerClient.cpp
+++ b/graphics/composer/aidl/vts/VtsComposerClient.cpp
@@ -404,14 +404,31 @@
return {std::move(configs.first), vtsDisplays};
}
for (int config : configs.second) {
- auto status = updateDisplayProperties(&vtsDisplay, config);
+ auto status = addDisplayConfig(&vtsDisplay, config);
if (!status.isOk()) {
- ALOGE("Unable to get the displays for test, failed to update the properties "
+ ALOGE("Unable to get the displays for test, failed to add config "
"for display %" PRId64,
display);
return {std::move(status), vtsDisplays};
}
}
+
+ auto config = getActiveConfig(display);
+ if (!config.first.isOk()) {
+ ALOGE("Unable to get the displays for test, failed to get active config "
+ "for display %" PRId64, display);
+ return {std::move(config.first), vtsDisplays};
+ }
+
+ auto status = updateDisplayProperties(&vtsDisplay, config.second);
+ if (!status.isOk()) {
+ ALOGE("Unable to get the displays for test, "
+ "failed to update the properties "
+ "for display %" PRId64,
+ display);
+ return {std::move(status), vtsDisplays};
+ }
+
vtsDisplays.emplace_back(vtsDisplay);
addDisplayToDisplayResources(display, /*isVirtual*/ false);
}
@@ -420,7 +437,7 @@
}
}
-ScopedAStatus VtsComposerClient::updateDisplayProperties(VtsDisplay* vtsDisplay, int32_t config) {
+ScopedAStatus VtsComposerClient::addDisplayConfig(VtsDisplay* vtsDisplay, int32_t config) {
const auto width =
getDisplayAttribute(vtsDisplay->getDisplayId(), config, DisplayAttribute::WIDTH);
const auto height =
@@ -431,7 +448,6 @@
getDisplayAttribute(vtsDisplay->getDisplayId(), config, DisplayAttribute::CONFIG_GROUP);
if (width.first.isOk() && height.first.isOk() && vsyncPeriod.first.isOk() &&
configGroup.first.isOk()) {
- vtsDisplay->setDimensions(width.second, height.second);
vtsDisplay->addDisplayConfig(config, {vsyncPeriod.second, configGroup.second});
return ScopedAStatus::ok();
}
@@ -442,6 +458,21 @@
return ScopedAStatus::fromServiceSpecificError(IComposerClient::EX_BAD_CONFIG);
}
+ScopedAStatus VtsComposerClient::updateDisplayProperties(VtsDisplay* vtsDisplay, int32_t config) {
+ const auto width =
+ getDisplayAttribute(vtsDisplay->getDisplayId(), config, DisplayAttribute::WIDTH);
+ const auto height =
+ getDisplayAttribute(vtsDisplay->getDisplayId(), config, DisplayAttribute::HEIGHT);
+ if (width.first.isOk() && height.first.isOk()) {
+ vtsDisplay->setDimensions(width.second, height.second);
+ return ScopedAStatus::ok();
+ }
+
+ LOG(ERROR) << "Failed to update display property for width: " << width.first.isOk()
+ << ", height: " << height.first.isOk();
+ return ScopedAStatus::fromServiceSpecificError(IComposerClient::EX_BAD_CONFIG);
+}
+
ScopedAStatus VtsComposerClient::addDisplayToDisplayResources(int64_t display, bool isVirtual) {
if (mDisplayResources.insert({display, DisplayResource(isVirtual)}).second) {
return ScopedAStatus::ok();
diff --git a/graphics/composer/aidl/vts/VtsComposerClient.h b/graphics/composer/aidl/vts/VtsComposerClient.h
index e61fde9..c4bc464 100644
--- a/graphics/composer/aidl/vts/VtsComposerClient.h
+++ b/graphics/composer/aidl/vts/VtsComposerClient.h
@@ -178,6 +178,7 @@
std::pair<ScopedAStatus, OverlayProperties> getOverlaySupport();
private:
+ ScopedAStatus addDisplayConfig(VtsDisplay* vtsDisplay, int32_t config);
ScopedAStatus updateDisplayProperties(VtsDisplay* vtsDisplay, int32_t config);
ScopedAStatus addDisplayToDisplayResources(int64_t display, bool isVirtual);
diff --git a/graphics/mapper/stable-c/Android.bp b/graphics/mapper/stable-c/Android.bp
index fa3087a..1d01a02 100644
--- a/graphics/mapper/stable-c/Android.bp
+++ b/graphics/mapper/stable-c/Android.bp
@@ -33,6 +33,13 @@
export_header_lib_headers: [
"libarect_headers",
],
+ // TODO(b/214400477) Remove apex_available
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media.swcodec",
+ "test_com.android.media.swcodec",
+ ],
+ min_sdk_version: "29",
}
cc_library_shared {
@@ -66,6 +73,13 @@
"libbase_headers",
"libimapper_stablec",
],
+ // TODO(b/214400477) Remove apex_available
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media.swcodec",
+ "test_com.android.media.swcodec",
+ ],
+ min_sdk_version: "29",
}
cc_test {
diff --git a/graphics/mapper/stable-c/README.md b/graphics/mapper/stable-c/README.md
new file mode 100644
index 0000000..30f3ccc
--- /dev/null
+++ b/graphics/mapper/stable-c/README.md
@@ -0,0 +1,110 @@
+# IMapper "stable-c" HAL
+
+Starting with gralloc version 5, IMapper is now exposed as a C API instead of through HIDL or AIDL.
+This is due to HIDL being deprecated, and AIDL not wanting to support a pass-through mode & pointers
+for just a couple of clients such as IMapper. So instead a stable C API is used to fill this gap.
+
+## Implementing
+
+To provide an implementation a library implementing the AIMapper API interface should be provided
+in `/vendor/lib[64]/hw/mapper.<imapper_suffix>.so`. The `<imapper_suffix>` should be specified
+as the `<instance>` in the VINTF manifest `<interface>` section. For example:
+```xml
+<manifest version="1.0" type="device">
+ <hal format="native">
+ <name>mapper</name>
+ <version>5.0</version>
+ <interface>
+ <name>I</name>
+ <instance>minigbm</instance>
+ </interface>
+ </hal>
+</manifest>
+```
+defines that the IMapper 5.0 library is provided by `/vendor/lib[64]/hw/mapper.minigbm.so`.
+
+This library must export the following `extern "C"` symbols:
+
+### `ANDROID_HAL_STABLEC_VERSION`
+
+This is a uint32_t that should simply be set to the exported AIMapper version. For example:
+```c++
+extern "C" uint32_t ANDROID_HAL_STABLEC_VERSION = AIMAPPER_VERSION_5;
+```
+
+### `AIMapper_loadIMapper`
+
+This is what should actually load the HAL interface. The full type signature is
+```c++
+extern "C" AIMapper_Error AIMapper_loadIMapper(AIMapper* _Nullable* _Nonnull outImplementation)
+```
+
+See `include/android/hardware/graphics/mapper/IMapper.h` for complete documentation on what
+this function must return.
+
+To make it easier to implement this C API, a header-only helper library is provided called
+`libimapper_providerutils`. This library handles mapping from the C API struct to a C++ class
+as well as provides helpers for encoding & decoding metadata, largely replacing the role that
+`libgralloctypes` filled with IMapper 4.
+
+To use this library, create a class that extends from `IMapperV5Impl` and use `IMapperProvider` to
+implement `AIMapper_loadIMapper`:
+
+```c++
+// The IMapper interface itself
+#include <android/hardware/graphics/mapper/IMapper.h>
+// Helpers for reading & writing metadata
+#include <android/hardware/graphics/mapper/utils/IMapperMetadataTypes.h>
+// Helper for providing the implementation interface
+#include <android/hardware/graphics/mapper/utils/IMapperProvider.h>
+
+// Define an IMapperV5 implementation
+class CrosGrallocMapperV5 final : public vendor::mapper::IMapperV5Impl {
+ // Override all the methods of IMapperV5Impl
+ AIMapper_Error importBuffer(const native_handle_t* _Nonnull handle,
+ buffer_handle_t _Nullable* _Nonnull outBufferHandle) override;
+ [etc...]
+};
+
+// Expose the required C symbols
+
+extern "C" uint32_t ANDROID_HAL_STABLEC_VERSION = AIMAPPER_VERSION_5;
+
+extern "C" AIMapper_Error AIMapper_loadIMapper(AIMapper* _Nullable* _Nonnull outImplementation) {
+ // Define an IMapperProvider for our V5 implementation
+ static vendor::mapper::IMapperProvider<CrosGrallocMapperV5> provider;
+ return provider.load(outImplementation);
+}
+```
+
+A complete example, including using IMapperMetadataTypes, can be found in the cuttlefish
+implementation in `//external/minigbm/cros_gralloc/mapper_stablec`
+
+### Testing
+
+As with HIDL & AIDL HALs, a VTS test is provided to validate the implementation. It is found in the
+`vts` folder and may be run using `$ atest VtsHalGraphicsMapperStableC_TargetTest`
+
+## Using
+
+It is strongly recommended that clients use either the `AHardwareBuffer` (preferred) or
+`GraphicBufferMapper` (from libui) APIs to use the mapper HAL rather than attempting to use
+`AIMapper` directly.
+
+## Version changes
+
+### Version 5
+
+* Initial introduction of this HAL interface
+* Largely feature-equivalent to IMapper4
+* Requires allocator-V2
+* Removes `BufferDescriptorInfo`;
+* IsSupported has moved to IAllocator
+* Removes `validateBufferSize`, validation is instead handled by clients using metadata queries
+* Getting the following StandardMetadataType is now mandatory:
+ * STRIDE
+* Setting the following StandardMetadataTypes is now mandatory:
+ * DATASPACE
+ * SMPTE2086
+ * CTA861_3
+ * BLEND_MODE
diff --git a/graphics/mapper/stable-c/implutils/include/android/hardware/graphics/mapper/utils/IMapperMetadataTypes.h b/graphics/mapper/stable-c/implutils/include/android/hardware/graphics/mapper/utils/IMapperMetadataTypes.h
index 25af6d1..0e6d3dc 100644
--- a/graphics/mapper/stable-c/implutils/include/android/hardware/graphics/mapper/utils/IMapperMetadataTypes.h
+++ b/graphics/mapper/stable-c/implutils/include/android/hardware/graphics/mapper/utils/IMapperMetadataTypes.h
@@ -563,9 +563,12 @@
DEFINE_TYPE(CTA861_3, std::optional<Cta861_3>);
DEFINE_TYPE(SMPTE2094_10, std::optional<std::vector<uint8_t>>);
DEFINE_TYPE(SMPTE2094_40, std::optional<std::vector<uint8_t>>);
+DEFINE_TYPE(STRIDE, uint32_t);
#undef DEFINE_TYPE
+#if defined(__cplusplus) && __cplusplus >= 202002L
+
template <typename F, std::size_t... I>
void invokeWithStandardMetadata(F&& f, StandardMetadataType type, std::index_sequence<I...>) {
// Setup the jump table, mapping from each type to a springboard that invokes the template
@@ -620,4 +623,6 @@
return retVal;
}
+#endif
+
} // namespace android::hardware::graphics::mapper
\ No newline at end of file
diff --git a/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp b/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp
index 85246ee..2c06353 100644
--- a/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp
+++ b/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp
@@ -154,6 +154,7 @@
std::shared_ptr<IAllocator> mAllocator;
AIMapper* mIMapper = nullptr;
AIMapper_loadIMapperFn mIMapperLoader;
+ int32_t* mIMapperHALVersion = nullptr;
protected:
void Initialize(std::shared_ptr<IAllocator> allocator) {
@@ -171,10 +172,12 @@
ASSERT_NE(nullptr, mIMapperLoader) << "AIMapper_locaIMapper missing from " << lib_name;
ASSERT_EQ(AIMAPPER_ERROR_NONE, mIMapperLoader(&mIMapper));
ASSERT_NE(mIMapper, nullptr);
+ mIMapperHALVersion = (int32_t*)dlsym(so, "ANDROID_HAL_MAPPER_VERSION");
}
public:
AIMapper_loadIMapperFn getIMapperLoader() const { return mIMapperLoader; }
+ int32_t* getHalVersion() const { return mIMapperHALVersion; }
std::unique_ptr<BufferAllocation> allocate(const BufferDescriptorInfo& descriptorInfo) {
AllocationResult result;
@@ -557,6 +560,15 @@
void TearDown() override {}
};
+TEST_P(GraphicsMapperStableCTests, VersionChecks) {
+ ASSERT_NE(nullptr, getHalVersion()) << "Resolving ANDROID_HAL_MAPPER_VERSION symbol failed";
+ int32_t halVersion = *getHalVersion();
+ EXPECT_EQ(halVersion, AIMAPPER_VERSION_5) << "Unrecognized ANDROID_HAL_MAPPER_VERSION";
+ EXPECT_EQ(mapper()->version, AIMAPPER_VERSION_5) << "Unrecognized AIMapper::version";
+ EXPECT_EQ(halVersion, mapper()->version)
+ << "AIMapper version & ANDROID_HAL_MAPPER_VERSION don't agree";
+}
+
TEST_P(GraphicsMapperStableCTests, AllV5CallbacksDefined) {
ASSERT_GE(mapper()->version, AIMAPPER_VERSION_5);
@@ -1557,6 +1569,16 @@
}
}
+TEST_P(GraphicsMapperStableCTests, GetStride) {
+ auto buffer = allocateGeneric();
+ ASSERT_TRUE(buffer);
+ auto bufferHandle = buffer->import();
+ ASSERT_TRUE(bufferHandle);
+ auto value = getStandardMetadata<StandardMetadataType::STRIDE>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(buffer->stride(), *value);
+}
+
TEST_P(GraphicsMapperStableCTests, SupportsRequiredGettersSetters) {
auto buffer = allocateGeneric();
ASSERT_TRUE(buffer);
@@ -1587,6 +1609,7 @@
StandardMetadataType::BLEND_MODE,
StandardMetadataType::SMPTE2086,
StandardMetadataType::CTA861_3,
+ StandardMetadataType::STRIDE,
};
std::vector<StandardMetadataType> requiredSetters = {
diff --git a/radio/aidl/Android.bp b/radio/aidl/Android.bp
index 9caa97a..e8cebd7 100644
--- a/radio/aidl/Android.bp
+++ b/radio/aidl/Android.bp
@@ -163,7 +163,12 @@
enabled: true,
},
java: {
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.btservices",
+ ],
sdk_version: "module_current",
+ min_sdk_version: "Tiramisu",
},
},
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetwork.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetwork.aidl
index be06c47..382ddd8 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetwork.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetwork.aidl
@@ -81,6 +81,4 @@
oneway void isNullCipherAndIntegrityEnabled(in int serial);
oneway void isN1ModeEnabled(in int serial);
oneway void setN1ModeEnabled(in int serial, boolean enable);
- oneway void setLocationPrivacySetting(in int serial, in boolean shareLocation);
- oneway void getLocationPrivacySetting(in int serial);
}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkIndication.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkIndication.aidl
index 229f3e2..0f017ea 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkIndication.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkIndication.aidl
@@ -49,5 +49,4 @@
oneway void suppSvcNotify(in android.hardware.radio.RadioIndicationType type, in android.hardware.radio.network.SuppSvcNotification suppSvc);
oneway void voiceRadioTechChanged(in android.hardware.radio.RadioIndicationType type, in android.hardware.radio.RadioTechnology rat);
oneway void emergencyNetworkScanResult(in android.hardware.radio.RadioIndicationType type, in android.hardware.radio.network.EmergencyRegResult result);
- oneway void onNetworkInitiatedLocationResult(in android.hardware.radio.RadioIndicationType type, in android.hardware.radio.network.LocationResponseType locationResponseType);
}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkResponse.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkResponse.aidl
index 009fdd3..bfe8fa3 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkResponse.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkResponse.aidl
@@ -80,6 +80,4 @@
oneway void isNullCipherAndIntegrityEnabledResponse(in android.hardware.radio.RadioResponseInfo info, in boolean isEnabled);
oneway void isN1ModeEnabledResponse(in android.hardware.radio.RadioResponseInfo info, boolean isEnabled);
oneway void setN1ModeEnabledResponse(in android.hardware.radio.RadioResponseInfo info);
- oneway void setLocationPrivacySettingResponse(in android.hardware.radio.RadioResponseInfo info);
- oneway void getLocationPrivacySettingResponse(in android.hardware.radio.RadioResponseInfo info, boolean shareLocation);
}
diff --git a/radio/aidl/android/hardware/radio/network/IRadioNetwork.aidl b/radio/aidl/android/hardware/radio/network/IRadioNetwork.aidl
index 86b6eca..f22cdb0 100644
--- a/radio/aidl/android/hardware/radio/network/IRadioNetwork.aidl
+++ b/radio/aidl/android/hardware/radio/network/IRadioNetwork.aidl
@@ -555,30 +555,4 @@
* Response function is IRadioNetworkResponse.setN1ModeEnabledResponse()
*/
void setN1ModeEnabled(in int serial, boolean enable);
-
- /**
- * This API updates the current user setting of sharing the location data. This value must be
- * used by radio before honoring a network initiated location request for non emergency use
- * cases. The radio shall ignore this setting during emergency call, emergency SMS or emergency
- * call back modes and continue to provide the location information to the network initiated
- * location requests.
- *
- * @param serial Serial number of request.
- * @param shareLocation Whether to share location data to the network or not. true means the
- * radio is allowed to provide location data for any network initiated locations
- * request. false means the radio must not share location data for any network initiated
- * location requests for non-emergency use cases.
- *
- * Response function is IRadioNetworkResponse.setLocationPrivacySettingResponse()
- */
- void setLocationPrivacySetting(in int serial, in boolean shareLocation);
-
- /**
- * Request the current setting of sharing the location data.
- *
- * @param serial Serial number of request.
- *
- * Response function is IRadioNetworkResponse.getLocationPrivacySettingResponse()
- */
- void getLocationPrivacySetting(in int serial);
}
diff --git a/radio/aidl/android/hardware/radio/network/IRadioNetworkIndication.aidl b/radio/aidl/android/hardware/radio/network/IRadioNetworkIndication.aidl
index 2891496..47d932d 100644
--- a/radio/aidl/android/hardware/radio/network/IRadioNetworkIndication.aidl
+++ b/radio/aidl/android/hardware/radio/network/IRadioNetworkIndication.aidl
@@ -21,14 +21,13 @@
import android.hardware.radio.network.BarringInfo;
import android.hardware.radio.network.CellIdentity;
import android.hardware.radio.network.CellInfo;
-import android.hardware.radio.network.EmergencyRegResult;
import android.hardware.radio.network.LinkCapacityEstimate;
-import android.hardware.radio.network.LocationResponseType;
import android.hardware.radio.network.NetworkScanResult;
import android.hardware.radio.network.PhoneRestrictedState;
import android.hardware.radio.network.PhysicalChannelConfig;
import android.hardware.radio.network.SignalStrength;
import android.hardware.radio.network.SuppSvcNotification;
+import android.hardware.radio.network.EmergencyRegResult;
/**
* Interface declaring unsolicited radio indications for network APIs.
@@ -200,13 +199,4 @@
* @param result the result of the Emergency Network Scan
*/
void emergencyNetworkScanResult(in RadioIndicationType type, in EmergencyRegResult result);
-
- /**
- * Reports the result of the network initiated location request.
- *
- * @param type Type of radio indication
- * @param locationResponseType result of the network initiated location request.
- */
- void onNetworkInitiatedLocationResult(
- in RadioIndicationType type, in LocationResponseType locationResponseType);
}
diff --git a/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl b/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl
index f186df7..457b5b9 100644
--- a/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl
+++ b/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl
@@ -622,6 +622,7 @@
* RadioError:NONE
* RadioError:RADIO_NOT_AVAILABLE
* RadioError:MODEM_ERR
+ * RadioError:REQUEST_NOT_SUPPORTED
*/
void setNullCipherAndIntegrityEnabledResponse(in RadioResponseInfo info);
@@ -666,26 +667,4 @@
* RadioError:INVALID_STATE
*/
void setN1ModeEnabledResponse(in RadioResponseInfo info);
-
- /**
- * @param info Response info struct containing response type, serial no. and error
- *
- * Valid errors returned:
- * RadioError:NONE
- * RadioError:RADIO_NOT_AVAILABLE
- * RadioError:INTERNAL_ERR
- */
- void setLocationPrivacySettingResponse(in RadioResponseInfo info);
-
- /**
- * @param info Response info struct containing response type, serial no. and error
- * @param shareLocation Indicates whether the location sharing is allowed or not, True if
- * allowed else false.
- *
- * Valid errors returned:
- * RadioError:NONE
- * RadioError:RADIO_NOT_AVAILABLE
- * RadioError:INTERNAL_ERR
- */
- void getLocationPrivacySettingResponse(in RadioResponseInfo info, boolean shareLocation);
}
diff --git a/radio/aidl/android/hardware/radio/network/LocationResponseType.aidl b/radio/aidl/android/hardware/radio/network/LocationResponseType.aidl
deleted file mode 100644
index 0c502d0..0000000
--- a/radio/aidl/android/hardware/radio/network/LocationResponseType.aidl
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.radio.network;
-
-@VintfStability
-@Backing(type="int")
-@JavaDerive(toString=true)
-enum LocationResponseType {
- /**
- * Network initiated Location request rejected by modem because the user has not given
- * permission for this use case
- */
- REJECTED = 0,
- /**
- * Network initiated Location request is accepted by modem however no location information has
- * been shared to network due to a failure
- */
- ACCEPTED_NO_LOCATION_PROVIDED = 1,
- /**
- * Network initiated Location request is accepted and location information is provided to the
- * network by modem
- */
- ACCEPTED_LOCATION_PROVIDED = 2,
-}
diff --git a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioNetwork.h b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioNetwork.h
index 7dbb27b..d57c83d 100644
--- a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioNetwork.h
+++ b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioNetwork.h
@@ -108,9 +108,6 @@
::ndk::ScopedAStatus setNullCipherAndIntegrityEnabled(int32_t serial, bool enabled) override;
::ndk::ScopedAStatus isNullCipherAndIntegrityEnabled(int32_t serial) override;
- ::ndk::ScopedAStatus setLocationPrivacySetting(int32_t serial, bool shareLocation) override;
- ::ndk::ScopedAStatus getLocationPrivacySetting(int32_t serial) override;
-
protected:
std::shared_ptr<::aidl::android::hardware::radio::network::IRadioNetworkResponse> respond();
diff --git a/radio/aidl/compat/libradiocompat/network/RadioNetwork.cpp b/radio/aidl/compat/libradiocompat/network/RadioNetwork.cpp
index e6a44d1..a379eec 100644
--- a/radio/aidl/compat/libradiocompat/network/RadioNetwork.cpp
+++ b/radio/aidl/compat/libradiocompat/network/RadioNetwork.cpp
@@ -372,18 +372,4 @@
respond()->setN1ModeEnabledResponse(notSupported(serial));
return ok();
}
-
-ScopedAStatus RadioNetwork::setLocationPrivacySetting(int32_t serial, bool /*shareLocation*/) {
- LOG_CALL << serial;
- LOG(ERROR) << " setLocationPrivacySetting is unsupported by HIDL HALs";
- respond()->setLocationPrivacySettingResponse(notSupported(serial));
- return ok();
-}
-
-ScopedAStatus RadioNetwork::getLocationPrivacySetting(int32_t serial) {
- LOG_CALL << serial;
- LOG(ERROR) << " getLocationPrivacySetting is unsupported by HIDL HALs";
- respond()->getLocationPrivacySettingResponse(notSupported(serial), false);
- return ok();
-}
} // namespace android::hardware::radio::compat
diff --git a/radio/aidl/vts/VtsHalRadioTargetTest.cpp b/radio/aidl/vts/VtsHalRadioTargetTest.cpp
index c25f930..33a0d7d 100644
--- a/radio/aidl/vts/VtsHalRadioTargetTest.cpp
+++ b/radio/aidl/vts/VtsHalRadioTargetTest.cpp
@@ -56,7 +56,7 @@
testing::ValuesIn(android::getAidlHalInstanceNames(IRadioNetwork::descriptor)),
android::PrintInstanceNameToString);
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(RadioSapTest);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SapTest);
INSTANTIATE_TEST_SUITE_P(PerInstance, SapTest,
testing::ValuesIn(android::getAidlHalInstanceNames(ISap::descriptor)),
android::PrintInstanceNameToString);
diff --git a/radio/aidl/vts/radio_network_indication.cpp b/radio/aidl/vts/radio_network_indication.cpp
index 7178982..ae3bd4b 100644
--- a/radio/aidl/vts/radio_network_indication.cpp
+++ b/radio/aidl/vts/radio_network_indication.cpp
@@ -97,8 +97,3 @@
RadioIndicationType /*type*/, const EmergencyRegResult& /*result*/) {
return ndk::ScopedAStatus::ok();
}
-
-ndk::ScopedAStatus RadioNetworkIndication::onNetworkInitiatedLocationResult(
- RadioIndicationType /*type*/, LocationResponseType /*locationResponseType*/) {
- return ndk::ScopedAStatus::ok();
-}
diff --git a/radio/aidl/vts/radio_network_response.cpp b/radio/aidl/vts/radio_network_response.cpp
index 35e4202..25d45a5 100644
--- a/radio/aidl/vts/radio_network_response.cpp
+++ b/radio/aidl/vts/radio_network_response.cpp
@@ -320,17 +320,3 @@
parent_network.notify(info.serial);
return ndk::ScopedAStatus::ok();
}
-
-ndk::ScopedAStatus RadioNetworkResponse::setLocationPrivacySettingResponse(
- const RadioResponseInfo& info) {
- rspInfo = info;
- parent_network.notify(info.serial);
- return ndk::ScopedAStatus::ok();
-}
-
-ndk::ScopedAStatus RadioNetworkResponse::getLocationPrivacySettingResponse(
- const RadioResponseInfo& info, bool /*shareLocation*/) {
- rspInfo = info;
- parent_network.notify(info.serial);
- return ndk::ScopedAStatus::ok();
-}
diff --git a/radio/aidl/vts/radio_network_test.cpp b/radio/aidl/vts/radio_network_test.cpp
index 658fcf7..3d6dbe7 100644
--- a/radio/aidl/vts/radio_network_test.cpp
+++ b/radio/aidl/vts/radio_network_test.cpp
@@ -2021,8 +2021,8 @@
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
- ASSERT_TRUE(CheckAnyOfErrors(
- radioRsp_network->rspInfo.error,
- {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::MODEM_ERR}));
+ ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
+ {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
+ RadioError::MODEM_ERR, RadioError::REQUEST_NOT_SUPPORTED}));
LOG(DEBUG) << "isNullCipherAndIntegrityEnabled finished";
}
diff --git a/radio/aidl/vts/radio_network_utils.h b/radio/aidl/vts/radio_network_utils.h
index 496ec03..601f044 100644
--- a/radio/aidl/vts/radio_network_utils.h
+++ b/radio/aidl/vts/radio_network_utils.h
@@ -169,12 +169,6 @@
const RadioResponseInfo& info, bool isEnabled) override;
virtual ndk::ScopedAStatus setN1ModeEnabledResponse(const RadioResponseInfo& info) override;
-
- virtual ndk::ScopedAStatus setLocationPrivacySettingResponse(
- const RadioResponseInfo& info) override;
-
- virtual ndk::ScopedAStatus getLocationPrivacySettingResponse(const RadioResponseInfo& info,
- bool shareLocation) override;
};
/* Callback class for radio network indication */
@@ -232,9 +226,6 @@
virtual ndk::ScopedAStatus emergencyNetworkScanResult(
RadioIndicationType type, const EmergencyRegResult& result) override;
-
- virtual ndk::ScopedAStatus onNetworkInitiatedLocationResult(
- RadioIndicationType type, LocationResponseType locationResponseType) override;
};
// The main test class for Radio AIDL Network.
diff --git a/secure_element/aidl/default/main.cpp b/secure_element/aidl/default/main.cpp
index 16b8236..9b5a8fc 100644
--- a/secure_element/aidl/default/main.cpp
+++ b/secure_element/aidl/default/main.cpp
@@ -15,141 +15,673 @@
*/
#include <aidl/android/hardware/secure_element/BnSecureElement.h>
-
#include <android-base/hex.h>
#include <android-base/logging.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
+#include <algorithm>
+
using aidl::android::hardware::secure_element::BnSecureElement;
using aidl::android::hardware::secure_element::ISecureElementCallback;
using aidl::android::hardware::secure_element::LogicalChannelResponse;
using android::base::HexString;
using ndk::ScopedAStatus;
-static const std::vector<uint8_t> kAndroidTestAid = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41,
- 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64,
- 0x43, 0x54, 0x53, 0x31};
-static const std::vector<uint8_t> kLongAndroidTestAid = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41,
- 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64,
- 0x43, 0x54, 0x53, 0x32};
+static const std::vector<uint8_t> kIssuerSecurityDomainSelectResponse = {0x00, 0x00, 0x90, 0x00};
-class MySecureElement : public BnSecureElement {
+namespace se {
+// Application identifier.
+using Aid = std::vector<uint8_t>;
+
+// ISO7816 APDU status codes.
+enum Status : uint16_t {
+ SW_WRONG_DATA = 0x6A80,
+ SW_LOGICAL_CHANNEL_NOT_SUPPORTED = 0x6881,
+ SW_CONDITIONS_NOT_SATISFIED = 0x6985,
+ SW_INCORRECT_P1P2 = 0x6A86,
+ SW_BYTES_REMAINING_00 = 0x6100,
+ SW_WRONG_LENGTH = 0x6700,
+ SW_CORRECT_LENGTH_00 = 0x6C00,
+ SW_INS_NOT_SUPPORTED = 0x6D00,
+ SW_NO_ERROR = 0x9000,
+};
+
+// Type for raw APDUs.
+using RawApdu = std::vector<uint8_t>;
+
+// Wrap a command APDU (Application Processing Data Unit) to provide
+// accessors for header fields.
+struct Apdu {
public:
- ScopedAStatus closeChannel(int8_t channelNumber) override {
- LOG(INFO) << __func__ << " channel number: " << channelNumber;
- return ScopedAStatus::ok();
+ // Construct a command Apdu.
+ Apdu(std::vector<uint8_t> packet) : bytes_(std::move(packet)) {
+ CHECK(bytes_.size() >= kHeaderSize) << "command APDU created with invalid length";
+ size_t payload_len = bytes_.size() - kHeaderSize;
+
+ // TODO(b/123254068) - add support for extended command APDUs.
+ // Pre compute Lc and Le.
+
+ // Case 1: CLA | INS | P1 | P2
+ if (payload_len == 0) {
+ lc_ = 0;
+ le_ = 0;
+ return;
+ }
+
+ // Case 2: CLA | INS | P1 | P2 | Le
+ // Le has a value of 1 to 255.
+ if (payload_len == 1) {
+ le_ = bytes_[kHeaderSize];
+ le_ = le_ == 0 ? 256 : le_;
+ lc_ = 0;
+ return;
+ }
+
+ // Case 3: CLA | INS | P1 | P2 | Lc | Data
+ // Lc is less than 256 bytes
+ // of data, and Le is zero.
+ lc_ = bytes_[kHeaderSize];
+ if (payload_len <= (1 + lc_)) {
+ le_ = 0;
+ }
+
+ // Case 4: CLA | INS | P1 | P2 | Lc | Data | Le
+ // The legacy Case 4. Lc and Le
+ // are less than 256 bytes of data.
+ else {
+ le_ = bytes_[bytes_.size() - 1];
+ le_ = le_ == 0 ? 256 : le_;
+ }
}
- ScopedAStatus getAtr(std::vector<uint8_t>* _aidl_return) override {
- LOG(INFO) << __func__;
- _aidl_return->clear();
- return ScopedAStatus::ok();
+
+ // Construct a response Apdu with data.
+ static RawApdu CreateResponse(std::vector<uint8_t> data, Status status) {
+ // Append status word.
+ data.push_back(status >> 8);
+ data.push_back(status);
+ return data;
}
+
+ // Construct a response Apdu with no data.
+ static RawApdu CreateResponse(Status status) {
+ // Append status word.
+ return std::vector<uint8_t>{static_cast<uint8_t>(status >> 8),
+ static_cast<uint8_t>(status)};
+ }
+
+ // Return if command APDU is extended.
+ // The ISO/IEC 7816-4:2013 specification defines an extended APDU as any APDU
+ // whose payload data, response data or expected data length exceeds the 256
+ // byte limit.
+ bool IsExtended() const { return (bytes_.size() - kHeaderSize) > 256; }
+
+ // Return if command APDU has payload bytes.
+ bool HasPayload() const { return bytes_.size() > kHeaderSize; }
+
+ uint8_t get_cla() const { return bytes_[0]; }
+ uint8_t get_ins() const { return bytes_[1]; }
+ uint8_t get_p1() const { return bytes_[2]; }
+ uint8_t get_p2() const { return bytes_[3]; }
+
+ // Return the channel number encoded in the CLA field.
+ uint8_t get_channel_number() const {
+ // Type 4 commands — Encode legacy ISO/IEC 7816-4 logical channel
+ // information. Type 16 commands — Defined by the ISO/IEC 7816-4:2013
+ // specification to
+ // encode information for additional 16 logical channels in the card.
+ uint8_t cla = get_cla();
+ return (cla & 0x40) == 0 ? cla & 0x3 : 4 + (cla & 0xf);
+ }
+
+ // Return the length of the command data field.
+ uint16_t get_lc() const { return lc_; }
+
+ // Return the expected length of the response data field.
+ // Le should be have the same format as Lc.
+ uint16_t get_le() const { return le_; }
+
+ // Get the pointer to the APDU raw data.
+ std::vector<uint8_t> const& get_data() const { return bytes_; }
+
+ private:
+ // Size of command header, including CLA, INS, P1, P2 fields.
+ const size_t kHeaderSize = 4;
+
+ // Command or response buffer.
+ std::vector<uint8_t> bytes_{};
+
+ // Lengths of command data field and expected response data field.
+ uint16_t lc_{0};
+ uint16_t le_{0};
+};
+
+// Type of SE applets.
+class Applet {
+ public:
+ virtual ~Applet() {}
+
+ // Called to inform this applet that it has been selected.
+ virtual RawApdu Select(Aid const& aid, uint8_t p2) = 0;
+
+ // Called by the Java Card runtime environment to process an
+ // incoming APDU command. SELECT commands are processed by \ref select
+ // instead.
+ virtual RawApdu Process(Apdu const& apdu) = 0;
+};
+}; // namespace se
+
+// Implement the Google-eSE-test.cap test applet for passing OMAPI CTS tests
+// on Cuttlefish. The reference can be found here:
+// cts/tests/tests/secure_element/sample_applet/src/com/android/cts/omapi/test/CtsAndroidOmapiTestApplet.java
+class CtsAndroidOmapiTestApplet : public se::Applet {
+ public:
+ CtsAndroidOmapiTestApplet() {}
+ virtual ~CtsAndroidOmapiTestApplet() {}
+
+ se::RawApdu Select(se::Aid const& aid, uint8_t /*p2*/) override {
+ if (aid[aid.size() - 1] == 0x31) {
+ // AID: A000000476416E64726F696443545331
+ return se::Apdu::CreateResponse(se::Status::SW_NO_ERROR);
+ } else {
+ // AID: A000000476416E64726F696443545332
+ return se::Apdu::CreateResponse(GenerateBerTLVBytes(SELECT_RESPONSE_DATA_LENGTH),
+ se::Status::SW_NO_ERROR);
+ }
+ }
+
+ se::RawApdu ReadNextResponseChunk(uint16_t max_output_len) {
+ uint16_t output_len = static_cast<uint16_t>(response_.size() - response_offset_);
+ output_len = std::min<uint16_t>(max_output_len, output_len);
+ std::vector<uint8_t> output{
+ &response_[response_offset_],
+ &response_[response_offset_ + output_len],
+ };
+ response_offset_ += output_len;
+ uint16_t remaining_len = response_.size() - response_offset_;
+ se::Status status = se::Status::SW_NO_ERROR;
+ if (remaining_len > 0) {
+ if (remaining_len > 256) {
+ remaining_len = 0x00;
+ }
+ status = se::Status(se::Status::SW_BYTES_REMAINING_00 | remaining_len);
+ } else {
+ response_.clear();
+ response_offset_ = 0;
+ }
+ return se::Apdu::CreateResponse(output, status);
+ }
+
+ se::RawApdu Process(se::Apdu const& apdu) override {
+ uint16_t lc;
+ uint16_t le = apdu.get_le();
+ uint8_t p1 = apdu.get_p1();
+ uint8_t p2 = apdu.get_p2();
+
+ switch (apdu.get_ins()) {
+ case NO_DATA_INS_1:
+ case NO_DATA_INS_2:
+ LOG(INFO) << __func__ << ": NO_DATA_INS_1|2";
+ return se::Apdu::CreateResponse(se::Status::SW_NO_ERROR);
+
+ case DATA_INS_1:
+ case DATA_INS_2:
+ // Return 256 bytes of data.
+ LOG(INFO) << __func__ << ": DATA_INS_1|2";
+ return se::Apdu::CreateResponse(GeneratesBytes(256), se::Status::SW_NO_ERROR);
+
+ case GET_RESPONSE_INS:
+ // ISO GET_RESPONSE command.
+ LOG(INFO) << __func__ << ": GET_RESPONSE_INS";
+ if (response_.empty()) {
+ return se::Apdu::CreateResponse(se::Status::SW_CONDITIONS_NOT_SATISFIED);
+ }
+ return ReadNextResponseChunk(apdu.get_le());
+
+ case SW_62xx_APDU_INS:
+ LOG(INFO) << __func__ << ": SW_62xx_APDU_INS";
+ if (p1 < 1 || p1 > 16) {
+ return se::Apdu::CreateResponse(se::Status::SW_INCORRECT_P1P2);
+ }
+ if (p2 == SW_62xx_DATA_APDU_P2) {
+ return se::Apdu::CreateResponse(GeneratesBytes(3),
+ se::Status(SW_62xx_resp[p1 - 1]));
+ }
+ if (p2 == SW_62xx_VALIDATE_DATA_P2) {
+ std::vector<uint8_t> output{SW_62xx_VALIDATE_DATA_RESP.begin(),
+ SW_62xx_VALIDATE_DATA_RESP.end()};
+ output[2] = p1;
+ return se::Apdu::CreateResponse(std::move(output),
+ se::Status(SW_62xx_resp[p1 - 1]));
+ }
+ return se::Apdu::CreateResponse(se::Status(SW_62xx_resp[p1 - 1]));
+
+ case SEGMENTED_RESP_INS_1:
+ case SEGMENTED_RESP_INS_2:
+ LOG(INFO) << __func__ << ": SEGMENTED_RESP_INS_1|2";
+ response_ = GeneratesBytes((static_cast<uint16_t>(p1) << 8) | p2);
+ response_offset_ = 0;
+ return ReadNextResponseChunk(std::min<uint16_t>(apdu.get_le(), 256));
+
+ case SEGMENTED_RESP_INS_3:
+ case SEGMENTED_RESP_INS_4:
+ LOG(INFO) << __func__ << ": SEGMENTED_RESP_INS_3|4";
+ response_ = GeneratesBytes((static_cast<uint16_t>(p1) << 8) | p2);
+ response_offset_ = 0;
+ return ReadNextResponseChunk(apdu.get_le());
+
+ case SEGMENTED_RESP_INS_5:
+ LOG(INFO) << __func__ << ": SEGMENTED_RESP_INS_5";
+ if (le == 0xff) {
+ return se::Apdu::CreateResponse(
+ se::Status(se::Status::SW_CORRECT_LENGTH_00 | 0xff));
+ }
+ response_ = GeneratesBytes((static_cast<uint16_t>(p1) << 8) | p2);
+ response_offset_ = 0;
+ return ReadNextResponseChunk(apdu.get_le());
+
+ case CHECK_SELECT_P2_APDU:
+ LOG(INFO) << __func__ << ": CHECK_SELECT_P2_APDU";
+ return se::Apdu::CreateResponse(std::vector<uint8_t>{apdu.get_p2()},
+ se::Status::SW_NO_ERROR);
+
+ default:
+ // Case is not known.
+ LOG(INFO) << __func__ << ": UNKNOWN_INS";
+ return se::Apdu::CreateResponse(se::Status::SW_INS_NOT_SUPPORTED);
+ }
+ }
+
+ private:
+ std::vector<uint8_t> response_{};
+ uint16_t response_offset_{0};
+
+ static const uint8_t NO_DATA_INS_1 = 0x06;
+ static const uint8_t NO_DATA_INS_2 = 0x0A;
+ static const uint8_t DATA_INS_1 = 0x08;
+ static const uint8_t DATA_INS_2 = 0x0C;
+ static const uint8_t SW_62xx_APDU_INS = 0xF3;
+ static const uint8_t SW_62xx_DATA_APDU_P2 = 0x08;
+ static const uint8_t SW_62xx_VALIDATE_DATA_P2 = 0x0C;
+
+ static constexpr std::array<uint8_t, 7> SW_62xx_VALIDATE_DATA_RESP = {0x01, 0xF3, 0x00, 0x0C,
+ 0x01, 0xAA, 0x00};
+ static constexpr uint16_t SW_62xx_resp[] = {
+ 0x6200, 0x6281, 0x6282, 0x6283, 0x6285, 0x62F1, 0x62F2, 0x63F1,
+ 0x63F2, 0x63C2, 0x6202, 0x6280, 0x6284, 0x6286, 0x6300, 0x6381,
+ };
+
+ static const uint8_t SEGMENTED_RESP_INS_1 = 0xC2;
+ static const uint8_t SEGMENTED_RESP_INS_2 = 0xC4;
+ static const uint8_t SEGMENTED_RESP_INS_3 = 0xC6;
+ static const uint8_t SEGMENTED_RESP_INS_4 = 0xC8;
+ static const uint8_t SEGMENTED_RESP_INS_5 = 0xCF;
+ static const uint8_t CHECK_SELECT_P2_APDU = 0xF4;
+ static const uint8_t GET_RESPONSE_INS = 0xC0;
+ static const uint8_t BER_TLV_TYPE = 0x1F;
+ static const uint16_t SELECT_RESPONSE_DATA_LENGTH = 252;
+
+ static const uint16_t LENGTH_256 = 0x0100;
+ static constexpr std::array<uint8_t, 256> resp_bytes256{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
+ 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B,
+ 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29,
+ 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
+ 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53,
+ 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61,
+ 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D,
+ 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B,
+ 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
+ 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
+ 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5,
+ 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3,
+ 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1,
+ 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
+ 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED,
+ 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB,
+ 0xFC, 0xFD, 0xFE, 0xFF};
+
+ // Generate a response buffer of the selected length containing valid
+ // BER TLV bytes.
+ static std::vector<uint8_t> GenerateBerTLVBytes(uint16_t le) {
+ // Support length from 0x00 - 0x7FFF.
+ uint16_t le_len = 1;
+ if (le < (uint16_t)0x80) {
+ le_len = 1;
+ } else if (le < (uint16_t)0x100) {
+ le_len = 2;
+ } else {
+ le_len = 3;
+ }
+
+ uint16_t total_len = (uint16_t)(le + 2 + le_len);
+ std::vector<uint8_t> output(total_len);
+ uint16_t i = 0;
+
+ output[i++] = BER_TLV_TYPE;
+ output[i++] = 0x00; // second byte of Type
+ if (le < 0x80) {
+ output[i++] = le;
+ } else if (le < 0x100) {
+ output[i++] = 0x81;
+ output[i++] = le;
+ } else {
+ output[i++] = 0x82;
+ output[i++] = (le >> 8);
+ output[i++] = (le & 0xFF);
+ }
+ while (i < total_len) {
+ output[i++] = ((i - 2 - le_len) & 0xFF);
+ }
+
+ // Set the last byte to 0xFF for CTS validation.
+ output[total_len - 1] = 0xFF;
+ return output;
+ }
+
+ // Generate a response buffer of the selected length using the
+ // array resp_bytes256 as input.
+ static std::vector<uint8_t> GeneratesBytes(uint16_t total_len) {
+ std::vector<uint8_t> output(total_len);
+ uint16_t i = 0;
+
+ while (i < total_len) {
+ if ((total_len - i) >= resp_bytes256.size()) {
+ std::memcpy(&output[i], resp_bytes256.data(), resp_bytes256.size());
+ i += resp_bytes256.size();
+ } else {
+ output[i] = i & 0xFF;
+ i += 1;
+ }
+ }
+
+ // Set the last byte to 0xFF for CTS validation.
+ output[total_len - 1] = 0xFF;
+ return output;
+ }
+};
+
+class EmulatedSecureElement : public BnSecureElement {
+ public:
+ EmulatedSecureElement() {
+ std::shared_ptr<CtsAndroidOmapiTestApplet> test_applet =
+ std::make_shared<CtsAndroidOmapiTestApplet>();
+
+ applets_.push_back(std::pair{se::Aid{0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64, 0x72,
+ 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x31},
+ test_applet});
+
+ applets_.push_back(std::pair{se::Aid{0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64, 0x72,
+ 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x32},
+ test_applet});
+ }
+
ScopedAStatus init(const std::shared_ptr<ISecureElementCallback>& clientCallback) override {
LOG(INFO) << __func__ << " callback: " << clientCallback.get();
if (!clientCallback) {
return ScopedAStatus::fromExceptionCode(EX_NULL_POINTER);
}
- mCb = clientCallback;
- mCb->onStateChange(true, "");
+ client_callback_ = clientCallback;
+ client_callback_->onStateChange(true, "init");
return ScopedAStatus::ok();
}
- ScopedAStatus isCardPresent(bool* _aidl_return) override {
+
+ ScopedAStatus getAtr(std::vector<uint8_t>* aidl_return) override {
LOG(INFO) << __func__;
- *_aidl_return = true;
+ *aidl_return = atr_;
return ScopedAStatus::ok();
}
+
+ ScopedAStatus reset() override {
+ LOG(INFO) << __func__;
+ CHECK(client_callback_ != nullptr) << " init not invoked";
+ client_callback_->onStateChange(false, "reset");
+ client_callback_->onStateChange(true, "reset");
+ // All channels are closed after reset.
+ for (auto channel : channels_) {
+ channel = Channel();
+ }
+ return ScopedAStatus::ok();
+ }
+
+ ScopedAStatus isCardPresent(bool* aidl_return) override {
+ LOG(INFO) << __func__;
+ *aidl_return = true;
+ return ScopedAStatus::ok();
+ }
+
ScopedAStatus openBasicChannel(const std::vector<uint8_t>& aid, int8_t p2,
- std::vector<uint8_t>* _aidl_return) override {
+ std::vector<uint8_t>* aidl_return) override {
LOG(INFO) << __func__ << " aid: " << HexString(aid.data(), aid.size()) << " (" << aid.size()
<< ") p2 " << p2;
- // TODO(b/123254068) - this is not an implementation of the OMAPI protocol or APDU.
- // The functionality here is enough to exercise the framework, but actual
- // calls to the secure element will fail. This implementation does not model
- // channel isolation or any other aspects important to implementing secure element.
- *_aidl_return = {0x90, 0x00, 0x00}; // DO NOT COPY
+ std::vector<uint8_t> select_response;
+ std::shared_ptr<se::Applet> applet = nullptr;
+
+ // The basic channel can only be opened once, and stays opened
+ // and locked until the channel is closed.
+ if (channels_[0].opened) {
+ LOG(INFO) << __func__ << " basic channel already opened";
+ return ScopedAStatus::fromServiceSpecificError(CHANNEL_NOT_AVAILABLE);
+ }
+
+ // If the AID is defined (the AID is not Null and the length of the
+ // AID is not 0) and the channel is not locked then the corresponding
+ // applet shall be selected.
+ if (aid.size() > 0) {
+ applet = SelectApplet(aid);
+ if (applet == nullptr) {
+ // No applet registered with matching AID.
+ LOG(INFO) << __func__ << " basic channel AID not found";
+ return ScopedAStatus::fromServiceSpecificError(NO_SUCH_ELEMENT_ERROR);
+ }
+ select_response = applet->Select(aid, p2);
+ }
+
+ // If the AID is a 0 length AID and the channel is not locked, the
+ // method will select the Issuer Security Domain of the SE by sending a
+ // SELECT command with a 0 length AID as defined in
+ // [GP Card specification].
+ if (aid.size() == 0) {
+ select_response = kIssuerSecurityDomainSelectResponse;
+ }
+
+ LOG(INFO) << __func__ << " sending response: "
+ << HexString(select_response.data(), select_response.size());
+
+ // TODO(b/123254068) - this is not an implementation of the OMAPI protocol
+ // or APDU. The functionality here is enough to exercise the framework,
+ // but actual calls to the secure element will fail. This implementation
+ // does not model channel isolation or any other aspects important to
+ // implementing secure element.
+ channels_[0] = Channel(aid, p2, applet);
+ *aidl_return = select_response;
return ScopedAStatus::ok();
}
+
ScopedAStatus openLogicalChannel(
const std::vector<uint8_t>& aid, int8_t p2,
- ::aidl::android::hardware::secure_element::LogicalChannelResponse* _aidl_return)
+ ::aidl::android::hardware::secure_element::LogicalChannelResponse* aidl_return)
override {
LOG(INFO) << __func__ << " aid: " << HexString(aid.data(), aid.size()) << " (" << aid.size()
<< ") p2 " << p2;
- if (aid != kAndroidTestAid && aid != kLongAndroidTestAid) {
- return ScopedAStatus::fromServiceSpecificError(NO_SUCH_ELEMENT_ERROR);
+ size_t channel_number = 1;
+ std::vector<uint8_t> select_response;
+ std::shared_ptr<se::Applet> applet = nullptr;
+
+ // Look for an available channel number.
+ for (; channel_number < channels_.size(); channel_number++) {
+ if (channels_[channel_number].opened == false) {
+ break;
+ }
}
- *_aidl_return = LogicalChannelResponse{.channelNumber = 1, .selectResponse = {}};
+ // All channels are currently allocated.
+ if (channel_number >= channels_.size()) {
+ LOG(INFO) << __func__ << " all logical channels already opened";
+ return ScopedAStatus::fromServiceSpecificError(CHANNEL_NOT_AVAILABLE);
+ }
- // TODO(b/123254068) - this is not an implementation of the OMAPI protocol or APDU.
- // The functionality here is enough to exercise the framework, but actual
- // calls to the secure element will fail. This implementation does not model
- // channel isolation or any other aspects important to implementing secure element.
- if (aid == kAndroidTestAid) { // DO NOT COPY
- size_t size = 2050; // DO NOT COPY
- _aidl_return->selectResponse.resize(size); // DO NOT COPY
- _aidl_return->selectResponse[size - 1] = 0x00; // DO NOT COPY
- _aidl_return->selectResponse[size - 2] = 0x90; // DO NOT COPY
- } else { // DO NOT COPY
- _aidl_return->selectResponse = {0x00, 0x00, 0x90, 0x00}; // DO NOT COPY
- } // DO NOT COPY
+ // If the AID is defined (the AID is not Null and the length of the
+ // AID is not 0) then the corresponding applet shall be selected.
+ if (aid.size() > 0) {
+ applet = SelectApplet(aid);
+ if (applet == nullptr) {
+ // No applet registered with matching AID.
+ LOG(INFO) << __func__ << " logical channel AID not found";
+ return ScopedAStatus::fromServiceSpecificError(NO_SUCH_ELEMENT_ERROR);
+ }
+ select_response = applet->Select(aid, p2);
+ }
+
+ // If the length of the AID is 0, the method will select the
+ // Issuer Security Domain of the SE by sending a SELECT command
+ // with 0 length AID as defined in [GPCS].
+ if (aid.size() == 0) {
+ select_response = kIssuerSecurityDomainSelectResponse;
+ }
LOG(INFO) << __func__ << " sending response: "
- << HexString(_aidl_return->selectResponse.data(),
- _aidl_return->selectResponse.size());
+ << HexString(select_response.data(), select_response.size());
+ // TODO(b/123254068) - this is not an implementation of the OMAPI protocol
+ // or APDU. The functionality here is enough to exercise the framework,
+ // but actual calls to the secure element will fail. This implementation
+ // does not model channel isolation or any other aspects important to
+ // implementing secure element.
+ channels_[channel_number] = Channel(aid, p2, applet);
+ *aidl_return = LogicalChannelResponse{
+ .channelNumber = static_cast<int8_t>(channel_number),
+ .selectResponse = select_response,
+ };
return ScopedAStatus::ok();
}
- ScopedAStatus reset() override {
- LOG(INFO) << __func__;
- mCb->onStateChange(false, "reset");
- mCb->onStateChange(true, "reset");
+
+ ScopedAStatus closeChannel(int8_t channel_number) override {
+ LOG(INFO) << __func__ << " channel number: " << static_cast<int>(channel_number);
+ // The selected basic or logical channel is not opened.
+ if (channel_number >= channels_.size() || !channels_[channel_number].opened) {
+ return ScopedAStatus::ok();
+ }
+
+ // TODO(b/123254068) - this is not an implementation of the OMAPI protocol
+ // or APDU. The functionality here is enough to exercise the framework,
+ // but actual calls to the secure element will fail. This implementation
+ // does not model channel isolation or any other aspects important to
+ // implementing secure element.
+ channels_[channel_number].opened = false;
return ScopedAStatus::ok();
}
+
ScopedAStatus transmit(const std::vector<uint8_t>& data,
- std::vector<uint8_t>* _aidl_return) override {
+ std::vector<uint8_t>* aidl_return) override {
LOG(INFO) << __func__ << " data: " << HexString(data.data(), data.size()) << " ("
<< data.size() << ")";
- // TODO(b/123254068) - this is not an implementation of the OMAPI protocol or APDU.
- // The functionality here is enough to exercise the framework, but actual
- // calls to the secure element will fail. This implementation does not model
- // channel isolation or any other aspects important to implementing secure element.
+ se::Apdu apdu(data);
+ uint8_t channel_number = apdu.get_channel_number();
+ std::vector<uint8_t> response_apdu;
- std::string hex = HexString(data.data(), data.size()); // DO NOT COPY
- if (hex == "01a4040210a000000476416e64726f696443545331") { // DO NOT COPY
- *_aidl_return = {0x00, 0x6A, 0x00}; // DO NOT COPY
- } else if (data == std::vector<uint8_t>{0x00, 0xF4, 0x00, 0x00, 0x00}) { // DO NOT COPY
- // CHECK_SELECT_P2_APDU w/ channel 1 // DO NOT COPY
- *_aidl_return = {0x00, 0x90, 0x00}; // DO NOT COPY
- } else if (data == std::vector<uint8_t>{0x01, 0xF4, 0x00, 0x00, 0x00}) { // DO NOT COPY
- // CHECK_SELECT_P2_APDU w/ channel 1 // DO NOT COPY
- *_aidl_return = {0x00, 0x90, 0x00}; // DO NOT COPY
- } else if (data.size() == 5 || data.size() == 8) { // DO NOT COPY
- // SEGMENTED_RESP_APDU - happens to use length 5 and 8 // DO NOT COPY
- size_t size = (data[2] << 8 | data[3]) + 2; // DO NOT COPY
- _aidl_return->resize(size); // DO NOT COPY
- (*_aidl_return)[size - 1] = 0x00; // DO NOT COPY
- (*_aidl_return)[size - 2] = 0x90; // DO NOT COPY
- if (size >= 3) (*_aidl_return)[size - 3] = 0xFF; // DO NOT COPY
- } else { // DO NOT COPY
- *_aidl_return = {0x90, 0x00, 0x00}; // DO NOT COPY
- } // DO NOT COPY
+ switch (apdu.get_ins()) {
+ // TODO(b/123254068) - Implement support channel management APDUs.
+ case MANAGE_CHANNEL_INS:
+ // P1 = '00' to open
+ // P1 = '80' to close
+ LOG(INFO) << __func__ << " MANAGE_CHANNEL apdu";
+ response_apdu =
+ se::Apdu::CreateResponse(se::Status::SW_LOGICAL_CHANNEL_NOT_SUPPORTED);
+ break;
+ // TODO(b/123254068) - Implement support channel management APDUs.
+ case SELECT_INS:
+ LOG(INFO) << __func__ << " SELECT apdu";
+ response_apdu =
+ se::Apdu::CreateResponse(se::Status::SW_LOGICAL_CHANNEL_NOT_SUPPORTED);
+ break;
+
+ default:
+ CHECK(channel_number < channels_.size()) << " invalid channel number";
+ if (!channels_[channel_number].opened) {
+ LOG(INFO) << __func__ << " the channel " << static_cast<int>(channel_number)
+ << " is not opened";
+ response_apdu =
+ se::Apdu::CreateResponse(se::Status::SW_LOGICAL_CHANNEL_NOT_SUPPORTED);
+ break;
+ }
+ // Send the APDU to the applet for processing.
+ // Applet implementation is optional, default to sending
+ // SW_INS_NOT_SUPPORTED.
+ if (channels_[channel_number].applet == nullptr) {
+ response_apdu = se::Apdu::CreateResponse(se::Status::SW_INS_NOT_SUPPORTED);
+ } else {
+ response_apdu = channels_[channel_number].applet->Process(apdu);
+ }
+ break;
+ }
+
+ aidl_return->assign(response_apdu.begin(), response_apdu.end());
+ LOG(INFO) << __func__
+ << " response: " << HexString(aidl_return->data(), aidl_return->size()) << " ("
+ << aidl_return->size() << ")";
return ScopedAStatus::ok();
}
private:
- std::shared_ptr<ISecureElementCallback> mCb;
+ struct Channel {
+ public:
+ Channel() = default;
+ Channel(Channel const&) = default;
+ Channel(se::Aid const& aid, uint8_t p2, std::shared_ptr<se::Applet> applet)
+ : opened(true), aid(aid), p2(p2), applet(std::move(applet)) {}
+ Channel& operator=(Channel const&) = default;
+
+ bool opened{false};
+ se::Aid aid{};
+ uint8_t p2{0};
+ std::shared_ptr<se::Applet> applet{nullptr};
+ };
+
+ // OMAPI abstraction.
+
+ // Channel 0 is the basic channel, channels 1-19 are the logical channels.
+ std::array<Channel, 20> channels_{};
+ std::shared_ptr<ISecureElementCallback> client_callback_;
+
+ // Secure element abstraction.
+
+ static const uint8_t MANAGE_CHANNEL_INS = 0x70;
+ static const uint8_t SELECT_INS = 0xa4;
+
+ // Secure element ATR (Answer-To-Reset).
+ // The format is specified by ISO/IEC 1816-4 2020 and lists
+ // the capabilities of the card.
+ //
+ // TODO(b/123254068): encode the default SE properties in the ATR:
+ // support for extended Lc / Le fields, maximum number of logical channels.
+ // The CTS tests are *not* checking this value.
+ std::vector<uint8_t> const atr_{};
+
+ // Applet registration.
+ std::vector<std::pair<se::Aid, std::shared_ptr<se::Applet>>> applets_{};
+
+ // Return the first applet that matches the selected aid.
+ std::shared_ptr<se::Applet> SelectApplet(se::Aid const& aid) {
+ for (auto& [applet_aid, applet] : applets_) {
+ if (applet_aid == aid) {
+ return applet;
+ }
+ }
+ return nullptr;
+ }
};
int main() {
ABinderProcess_setThreadPoolMaxThreadCount(0);
- auto se = ndk::SharedRefBase::make<MySecureElement>();
+ auto se = ndk::SharedRefBase::make<EmulatedSecureElement>();
const std::string name = std::string() + BnSecureElement::descriptor + "/eSE1";
binder_status_t status = AServiceManager_addService(se->asBinder().get(), name.c_str());
CHECK_EQ(status, STATUS_OK);
diff --git a/security/keymint/aidl/vts/functional/Android.bp b/security/keymint/aidl/vts/functional/Android.bp
index e7f5a0f..88badc7 100644
--- a/security/keymint/aidl/vts/functional/Android.bp
+++ b/security/keymint/aidl/vts/functional/Android.bp
@@ -57,6 +57,7 @@
srcs: [
"AttestKeyTest.cpp",
"DeviceUniqueAttestationTest.cpp",
+ "KeyBlobUpgradeTest.cpp",
"KeyMintTest.cpp",
"SecureElementProvisioningTest.cpp",
],
diff --git a/security/keymint/aidl/vts/functional/KeyBlobUpgradeTest.cpp b/security/keymint/aidl/vts/functional/KeyBlobUpgradeTest.cpp
new file mode 100644
index 0000000..c952012
--- /dev/null
+++ b/security/keymint/aidl/vts/functional/KeyBlobUpgradeTest.cpp
@@ -0,0 +1,609 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// The tests in this file are intended to be run manually, to allow testing of whether
+// keyblob upgrade works correctly. The manual procedure is roughly:
+//
+// 1) Run the "*Before*" subset of these tests with the `--keyblob_dir <dir>` command-line argument
+// so that keyblobs are saved to a directory on the device:
+//
+// VtsAidlKeyMintTargetTest --gtest_filter="*KeyBlobUpgradeTest*Before*" \
+// --keyblob_dir /data/local/tmp/keymint-blobs
+//
+// All tests should pass, and the `UpgradeKeyBlobs` test should indicate that no keyblob
+// upgrades were needed.
+//
+// 2) Copy the generated keyblobs off the device into a safe place.
+//
+// adb pull /data/local/tmp/keymint-blobs
+//
+// 3) Upgrade the device to a new version.
+//
+// 4) Push the saved keyblobs back onto the upgraded device.
+//
+// adb push keymint-blobs /data/local/tmp/keymint-blobs
+//
+// 5) Run the "*After*" subset of these tests with the `--keyblob_dir <dir>` command-line argument
+// pointing to the directory with the keyblobs:
+//
+// VtsAidlKeyMintTargetTest --gtest_filter="*KeyBlobUpgradeTest*After*" \
+// --keyblob_dir /data/local/tmp/keymint-blobs
+//
+// (Note that this skips the `CreateKeyBlobs` test, which would otherwise replace the saved
+// keyblobs with freshly generated ones.).
+//
+// All tests should pass, and the `UpgradeKeyBlobs` test should have output that matches whether
+// upgrade was expected or not.
+
+#define LOG_TAG "keymint_1_test"
+#include <cutils/log.h>
+
+#include <algorithm>
+#include <fstream>
+#include <iostream>
+
+#include <unistd.h>
+
+#include <openssl/curve25519.h>
+#include <openssl/ec.h>
+#include <openssl/evp.h>
+#include <openssl/mem.h>
+#include <openssl/x509v3.h>
+
+#include "KeyMintAidlTestBase.h"
+
+using aidl::android::hardware::security::keymint::KeyCharacteristics;
+
+namespace aidl::android::hardware::security::keymint::test {
+
+namespace {
+
+std::vector<std::string> keyblob_names_tee = {
+ "aes-key", "aes-key-rr", "des-key", "hmac-key",
+ "rsa-key", "p256-key", "ed25519-key", "x25519-key",
+ "rsa-attest-key", "p256-attest-key", "ed25519-attest-key"};
+
+std::vector<std::string> keyblob_names_sb = {"aes-key", "aes-key-rr", "des-key",
+ "hmac-key", "rsa-key", "p256-key",
+ "rsa-attest-key", "p256-attest-key"};
+
+const std::vector<std::string>& keyblob_names(SecurityLevel sec_level) {
+ if (sec_level == SecurityLevel::STRONGBOX) {
+ return keyblob_names_sb;
+ } else {
+ return keyblob_names_tee;
+ }
+}
+
+bool requires_rr(const std::string& name) {
+ return name.find("-rr") != std::string::npos;
+}
+
+bool is_asymmetric(const std::string& name) {
+ return (name.find("rsa") != std::string::npos || name.find("25519") != std::string::npos ||
+ name.find("p256") != std::string::npos);
+}
+
+std::string keyblob_subdir(const std::string& keyblob_dir, const std::string& full_name,
+ bool create) {
+ if (keyblob_dir.empty()) {
+ return "";
+ }
+
+ // Use a subdirectory for the specific instance, so two different KeyMint instances won't
+ // clash with each other.
+ size_t found = full_name.find_last_of('/');
+ std::string subdir = keyblob_dir + "/" + full_name.substr(found + 1);
+
+ if (create) {
+ mkdir(keyblob_dir.c_str(), 0777);
+ mkdir(subdir.c_str(), 0777);
+ }
+ return subdir;
+}
+
+void save_keyblob(const std::string& subdir, const std::string& name,
+ const vector<uint8_t>& keyblob,
+ const std::vector<KeyCharacteristics>& key_characteristics) {
+ // Write the keyblob out to a file.
+ std::string blobname(subdir + "/" + name + ".keyblob");
+ std::ofstream blobfile(blobname, std::ios::out | std::ios::trunc | std::ios::binary);
+ blobfile.write(reinterpret_cast<const char*>(keyblob.data()), keyblob.size());
+ blobfile.close();
+
+ // Dump the characteristics too.
+ std::string charsname(subdir + "/" + name + ".chars");
+ std::ofstream charsfile(charsname, std::ios::out | std::ios::trunc);
+ charsfile << "{\n";
+ for (const auto& characteristic : key_characteristics) {
+ charsfile << " " << characteristic.toString() << "\n";
+ }
+ charsfile << "}\n";
+ charsfile.close();
+
+ // Also write out a hexdump of the keyblob for convenience.
+ std::string hexname(subdir + "/" + name + ".hex");
+ std::ofstream hexfile(hexname, std::ios::out | std::ios::trunc);
+ hexfile << bin2hex(keyblob) << "\n";
+ hexfile.close();
+}
+
+void save_keyblob_and_cert(const std::string& subdir, const std::string& name,
+ const vector<uint8_t>& keyblob,
+ const std::vector<KeyCharacteristics>& key_characteristics,
+ const std::vector<Certificate>& cert_chain) {
+ save_keyblob(subdir, name, keyblob, key_characteristics);
+
+ if (is_asymmetric(name)) {
+ // Dump the leaf certificate as DER.
+ if (cert_chain.empty()) {
+ FAIL() << "No cert available for " << name;
+ } else {
+ const vector<uint8_t>& certdata = cert_chain[0].encodedCertificate;
+ std::string certname(subdir + "/" + name + ".cert");
+ std::ofstream certfile(certname, std::ios::out | std::ios::trunc | std::ios::binary);
+ certfile.write(reinterpret_cast<const char*>(certdata.data()), certdata.size());
+ certfile.close();
+ }
+ }
+}
+
+void delete_keyblob(const std::string& subdir, const std::string& name) {
+ std::string blobname(subdir + "/" + name + ".keyblob");
+ unlink(blobname.c_str());
+ std::string charsname(subdir + "/" + name + ".chars");
+ unlink(charsname.c_str());
+ std::string hexname(subdir + "/" + name + ".hex");
+ unlink(hexname.c_str());
+ std::string certname(subdir + "/" + name + ".cert");
+ unlink(certname.c_str());
+}
+
+std::vector<uint8_t> load_file(const std::string& subdir, const std::string& name,
+ const std::string& suffix) {
+ std::string blobname(subdir + "/" + name + suffix);
+ std::ifstream blobfile(blobname, std::ios::in | std::ios::binary);
+
+ std::vector<uint8_t> data((std::istreambuf_iterator<char>(blobfile)),
+ std::istreambuf_iterator<char>());
+ return data;
+}
+
+std::vector<uint8_t> load_keyblob(const std::string& subdir, const std::string& name) {
+ return load_file(subdir, name, ".keyblob");
+}
+
+std::vector<uint8_t> load_cert(const std::string& subdir, const std::string& name) {
+ return load_file(subdir, name, ".cert");
+}
+
+} // namespace
+
+class KeyBlobUpgradeTest : public KeyMintAidlTestBase {
+ protected:
+ void UpgradeKeyBlobs(bool expectUpgrade) {
+ std::string subdir = keyblob_subdir(keyblob_dir, GetParam(), /* create? */ false);
+ if (subdir.empty()) {
+ GTEST_SKIP() << "No keyblob directory provided";
+ }
+
+ for (std::string name : keyblob_names(SecLevel())) {
+ for (bool with_hidden : {false, true}) {
+ std::string app_id;
+ std::string app_data;
+ auto builder = AuthorizationSetBuilder();
+ if (with_hidden) {
+ // Build a variant keyblob that requires app_id/app_data
+ app_id = "appid";
+ app_data = "appdata";
+ builder.Authorization(TAG_APPLICATION_ID, "appid")
+ .Authorization(TAG_APPLICATION_DATA, "appdata");
+ name += "-hidden";
+ }
+ SCOPED_TRACE(testing::Message() << name);
+
+ // Load the old format keyblob.
+ std::vector<uint8_t> keyblob = load_keyblob(subdir, name);
+ if (keyblob.empty()) {
+ if (requires_rr(name)) {
+ std::cerr << "Skipping missing keyblob file '" << name
+ << "', assuming rollback resistance unavailable\n";
+ } else {
+ FAIL() << "Missing keyblob file '" << name << "'";
+ }
+ continue;
+ }
+
+ // An upgrade will either produce a new keyblob or no data (if upgrade isn't
+ // needed).
+ std::vector<uint8_t> upgraded_keyblob;
+ Status result =
+ keymint_->upgradeKey(keyblob, builder.vector_data(), &upgraded_keyblob);
+ ASSERT_EQ(ErrorCode::OK, GetReturnErrorCode(result));
+
+ if (upgraded_keyblob.empty()) {
+ std::cerr << "Keyblob '" << name << "' did not require upgrade\n";
+ EXPECT_TRUE(!expectUpgrade) << "Keyblob '" << name << "' unexpectedly upgraded";
+ } else {
+ // Ensure the old format keyblob is deleted (so any secure deletion data is
+ // cleaned up).
+ EXPECT_EQ(ErrorCode::OK, DeleteKey(&keyblob));
+
+ std::vector<uint8_t> app_id_v(app_id.begin(), app_id.end());
+ std::vector<uint8_t> app_data_v(app_data.begin(), app_data.end());
+ std::vector<KeyCharacteristics> key_characteristics;
+ result = keymint_->getKeyCharacteristics(upgraded_keyblob, app_id_v, app_data_v,
+ &key_characteristics);
+ ASSERT_EQ(ErrorCode::OK, GetReturnErrorCode(result))
+ << "Failed getKeyCharacteristics() after upgrade";
+
+ save_keyblob(subdir, name, upgraded_keyblob, key_characteristics);
+ // Cert file is left unchanged.
+ std::cerr << "Keyblob '" << name << "' upgraded\n";
+ EXPECT_TRUE(expectUpgrade)
+ << "Keyblob '" << name << "' unexpectedly left as-is";
+ }
+ }
+ }
+ }
+};
+
+// To save off keyblobs before upgrade, use:
+//
+// VtsAidlKeyMintTargetTest --gtest_filter="*KeyBlobUpgradeTest.CreateKeyBlobs*" \
+// --keyblob_dir /data/local/tmp/keymint-blobs
+//
+// Then copy the contents of the /data/local/tmp/keymint-blobs/ directory somewhere safe:
+//
+// adb pull /data/local/tmp/keymint-blobs/
+TEST_P(KeyBlobUpgradeTest, CreateKeyBlobsBefore) {
+ std::string subdir = keyblob_subdir(keyblob_dir, GetParam(), /* create? */ true);
+
+ std::map<const std::string, AuthorizationSetBuilder> keys_info = {
+ {"aes-key", AuthorizationSetBuilder()
+ .AesEncryptionKey(256)
+ .BlockMode(BlockMode::ECB)
+ .Padding(PaddingMode::PKCS7)
+ .Authorization(TAG_NO_AUTH_REQUIRED)},
+ {"aes-key-rr", AuthorizationSetBuilder()
+ .AesEncryptionKey(256)
+ .BlockMode(BlockMode::ECB)
+ .Padding(PaddingMode::PKCS7)
+ .Authorization(TAG_ROLLBACK_RESISTANCE)
+ .Authorization(TAG_NO_AUTH_REQUIRED)},
+ {"des-key", AuthorizationSetBuilder()
+ .TripleDesEncryptionKey(168)
+ .BlockMode(BlockMode::ECB)
+ .Padding(PaddingMode::PKCS7)
+ .Authorization(TAG_NO_AUTH_REQUIRED)},
+ {"hmac-key", AuthorizationSetBuilder()
+ .HmacKey(128)
+ .Digest(Digest::SHA1)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)
+ .Authorization(TAG_NO_AUTH_REQUIRED)},
+ {"rsa-key", AuthorizationSetBuilder()
+ .RsaEncryptionKey(2048, 65537)
+ .Authorization(TAG_PURPOSE, KeyPurpose::SIGN)
+ .Digest(Digest::NONE)
+ .Digest(Digest::SHA1)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .SetDefaultValidity()},
+ {
+ "p256-key",
+ AuthorizationSetBuilder()
+ .EcdsaSigningKey(EcCurve::P_256)
+ .Authorization(TAG_PURPOSE, KeyPurpose::AGREE_KEY)
+ .Digest(Digest::NONE)
+ .Digest(Digest::SHA1)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .SetDefaultValidity(),
+ },
+ {
+ "ed25519-key",
+ AuthorizationSetBuilder()
+ .EcdsaSigningKey(EcCurve::CURVE_25519)
+ .Digest(Digest::NONE)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .SetDefaultValidity(),
+ },
+ {"x25519-key", AuthorizationSetBuilder()
+ .Authorization(TAG_EC_CURVE, EcCurve::CURVE_25519)
+ .Authorization(TAG_PURPOSE, KeyPurpose::AGREE_KEY)
+ .Authorization(TAG_ALGORITHM, Algorithm::EC)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .SetDefaultValidity()},
+ {"rsa-attest-key", AuthorizationSetBuilder()
+ .RsaKey(2048, 65537)
+ .AttestKey()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .SetDefaultValidity()},
+ {
+ "p256-attest-key",
+ AuthorizationSetBuilder()
+ .EcdsaKey(EcCurve::P_256)
+ .AttestKey()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .SetDefaultValidity(),
+ },
+ {
+ "ed25519-attest-key",
+ AuthorizationSetBuilder()
+ .EcdsaKey(EcCurve::CURVE_25519)
+ .AttestKey()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .SetDefaultValidity(),
+ }};
+
+ for (std::string name : keyblob_names(SecLevel())) {
+ auto entry = keys_info.find(name);
+ ASSERT_NE(entry, keys_info.end()) << "no builder for " << name;
+ auto builder = entry->second;
+ for (bool with_hidden : {false, true}) {
+ if (with_hidden) {
+ // Build a variant keyblob that requires app_id/app_data
+ builder.Authorization(TAG_APPLICATION_ID, "appid")
+ .Authorization(TAG_APPLICATION_DATA, "appdata");
+ name += "-hidden";
+ }
+ SCOPED_TRACE(testing::Message() << name);
+
+ vector<uint8_t> keyblob;
+ vector<KeyCharacteristics> key_characteristics;
+ vector<Certificate> cert_chain;
+ auto result =
+ GenerateKey(builder, std::nullopt, &keyblob, &key_characteristics, &cert_chain);
+
+ if (requires_rr(name) && result == ErrorCode::ROLLBACK_RESISTANCE_UNAVAILABLE) {
+ // Rollback resistance support is optional.
+ std::cerr << "Skipping '" << name << "' key as rollback resistance unavailable\n";
+ continue;
+ }
+ ASSERT_EQ(ErrorCode::OK, result) << " failed for " << name;
+
+ if (!subdir.empty()) {
+ save_keyblob_and_cert(subdir, name, keyblob, key_characteristics, cert_chain);
+ }
+ }
+ }
+
+ if (!subdir.empty()) {
+ std::cerr << "Save generated keyblobs with:\n\n adb pull " << keyblob_dir << "\n\n";
+ }
+}
+
+TEST_P(KeyBlobUpgradeTest, UpgradeKeyBlobsBefore) {
+ // Check that attempting to upgrade valid keyblobs does nothing.
+ UpgradeKeyBlobs(/* expectUpgrade= */ false);
+}
+
+// To run this test:
+//
+// - save off some keyblobs before upgrade as per the CreateKeyBlobs test above.
+// - upgrade the device to a version that should trigger keyblob upgrade (e.g. different patchlevel)
+// - put the saved keyblobs back onto the upgraded device:
+//
+// adb push keymint-blobs /data/local/tmp/keymint-blobs
+//
+// - run the test with:
+//
+// VtsAidlKeyMintTargetTest --gtest_filter="*KeyBlobUpgradeTest.UpgradeKeyBlobsAfter*" \
+// --keyblob_dir /data/local/tmp/keymint-blobs
+//
+// - this replaces the keyblob contents in that directory; if needed, save the upgraded keyblobs
+// with:
+// adb pull /data/local/tmp/keymint-blobs/
+TEST_P(KeyBlobUpgradeTest, UpgradeKeyBlobsAfter) {
+ UpgradeKeyBlobs(/* expectUpgrade= */ true);
+}
+
+// To run this test:
+//
+// - save off some keyblobs before upgrade as per the CreateKeyBlobs test above
+// - if needed, upgrade the saved keyblobs as per the UpgradeKeyBlobs test above
+// - run the test with:
+//
+// VtsAidlKeyMintTargetTest --gtest_filter="*KeyBlobUpgradeTest.UseKeyBlobs*" \
+// --keyblob_dir /data/local/tmp/keymint-blobs
+TEST_P(KeyBlobUpgradeTest, UseKeyBlobsBeforeOrAfter) {
+ std::string subdir = keyblob_subdir(keyblob_dir, GetParam(), /* create? */ false);
+ if (subdir.empty()) {
+ GTEST_SKIP() << "No keyblob directory provided with (e.g.) --keyblob_dir "
+ "/data/local/tmp/keymint-blobs";
+ }
+
+ for (std::string name : keyblob_names(SecLevel())) {
+ for (bool with_hidden : {false, true}) {
+ auto builder = AuthorizationSetBuilder();
+ if (with_hidden) {
+ // Build a variant keyblob that requires app_id/app_data
+ builder.Authorization(TAG_APPLICATION_ID, "appid")
+ .Authorization(TAG_APPLICATION_DATA, "appdata");
+ name += "-hidden";
+ }
+ SCOPED_TRACE(testing::Message() << name);
+ std::vector<uint8_t> keyblob = load_keyblob(subdir, name);
+ if (keyblob.empty()) {
+ if (requires_rr(name)) {
+ std::cerr << "Skipping missing keyblob file '" << name
+ << "', assuming rollback resistance unavailable\n";
+ } else {
+ FAIL() << "Missing keyblob file '" << name << "'";
+ }
+ continue;
+ }
+
+ std::vector<uint8_t> cert;
+ if (is_asymmetric(name)) {
+ cert = load_cert(subdir, name);
+ }
+
+ // Perform an algorithm-specific operation with the keyblob.
+ string message = "Hello World!";
+ AuthorizationSet out_params;
+ if (name.find("aes-key") != std::string::npos) {
+ builder.BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+ string ciphertext = EncryptMessage(keyblob, message, builder, &out_params);
+ string plaintext = DecryptMessage(keyblob, ciphertext, builder);
+ EXPECT_EQ(message, plaintext);
+ } else if (name.find("des-key") != std::string::npos) {
+ builder.BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+ string ciphertext = EncryptMessage(keyblob, message, builder, &out_params);
+ string plaintext = DecryptMessage(keyblob, ciphertext, builder);
+ EXPECT_EQ(message, plaintext);
+ } else if (name.find("hmac-key") != std::string::npos) {
+ builder.Digest(Digest::SHA1);
+ auto sign_builder = builder;
+ sign_builder.Authorization(TAG_MAC_LENGTH, 128);
+ string tag = SignMessage(keyblob, message, sign_builder);
+ VerifyMessage(keyblob, message, tag, builder);
+ } else if (name.find("rsa-key") != std::string::npos) {
+ builder.Digest(Digest::NONE).Padding(PaddingMode::NONE);
+ string signature = SignMessage(keyblob, message, builder);
+ LocalVerifyMessage(cert, message, signature, builder);
+ } else if (name.find("p256-key") != std::string::npos) {
+ builder.Digest(Digest::SHA1);
+ string signature = SignMessage(keyblob, message, builder);
+ LocalVerifyMessage(cert, message, signature, builder);
+ } else if (name.find("ed25519-key") != std::string::npos) {
+ builder.Digest(Digest::NONE);
+ string signature = SignMessage(keyblob, message, builder);
+ LocalVerifyMessage(cert, message, signature, builder);
+ } else if (name.find("x25519-key") != std::string::npos) {
+ // Generate EC key on same curve locally (with access to private key material).
+ uint8_t localPrivKeyData[32];
+ uint8_t localPubKeyData[32];
+ X25519_keypair(localPubKeyData, localPrivKeyData);
+ EVP_PKEY_Ptr localPrivKey(EVP_PKEY_new_raw_private_key(
+ EVP_PKEY_X25519, nullptr, localPrivKeyData, sizeof(localPrivKeyData)));
+ // Get encoded form of the public part of the locally generated key.
+ unsigned char* p = nullptr;
+ int localPublicKeySize = i2d_PUBKEY(localPrivKey.get(), &p);
+ ASSERT_GT(localPublicKeySize, 0);
+ vector<uint8_t> localPublicKey(
+ reinterpret_cast<const uint8_t*>(p),
+ reinterpret_cast<const uint8_t*>(p + localPublicKeySize));
+ OPENSSL_free(p);
+
+ // Agree on a key between local and KeyMint.
+ string data;
+ ASSERT_EQ(ErrorCode::OK,
+ Begin(KeyPurpose::AGREE_KEY, keyblob, builder, &out_params));
+ ASSERT_EQ(ErrorCode::OK,
+ Finish(string(localPublicKey.begin(), localPublicKey.end()), &data));
+ vector<uint8_t> keymint_data(data.begin(), data.end());
+
+ // Extract the public key for the KeyMint key from the cert.
+ X509_Ptr kmKeyCert(parse_cert_blob(cert));
+ ASSERT_NE(kmKeyCert, nullptr);
+ EVP_PKEY_Ptr kmPubKey = EVP_PKEY_Ptr(X509_get_pubkey(kmKeyCert.get()));
+ ASSERT_NE(kmPubKey.get(), nullptr);
+
+ size_t kmPubKeySize = 32;
+ uint8_t kmPubKeyData[32];
+ ASSERT_EQ(1,
+ EVP_PKEY_get_raw_public_key(kmPubKey.get(), kmPubKeyData, &kmPubKeySize));
+ ASSERT_EQ(kmPubKeySize, 32);
+
+ // Agree on a key between KeyMint and local.
+ uint8_t sharedKey[32];
+ ASSERT_EQ(1, X25519(sharedKey, localPrivKeyData, kmPubKeyData));
+ vector<uint8_t> local_data(sharedKey, sharedKey + 32);
+
+ // Both ways round should agree.
+ EXPECT_EQ(keymint_data, local_data);
+ } else if (name.find("-attest-key") != std::string::npos) {
+ // Covers rsa-attest-key, p256-attest-key, ed25519-attest-key.
+
+ // Use attestation key to sign RSA signing key
+ AttestationKey attest_key;
+ attest_key.keyBlob = keyblob;
+ attest_key.attestKeyParams = builder.vector_data();
+ attest_key.issuerSubjectName = make_name_from_str("Android Keystore Key");
+ vector<uint8_t> attested_key_blob;
+ vector<KeyCharacteristics> attested_key_characteristics;
+ vector<Certificate> attested_key_cert_chain;
+ EXPECT_EQ(ErrorCode::OK,
+ GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(2048, 65537)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AttestationChallenge("challenge")
+ .AttestationApplicationId("app-id")
+ .SetDefaultValidity(),
+ attest_key, &attested_key_blob, &attested_key_characteristics,
+ &attested_key_cert_chain));
+ CheckedDeleteKey(&attested_key_blob);
+ } else {
+ FAIL() << "Unexpected name: " << name;
+ }
+ }
+ }
+}
+
+// This test target deletes any keys from the keyblob subdirectory that have rollback resistance
+// enabled.
+TEST_P(KeyBlobUpgradeTest, DeleteRRKeyBlobsAfter) {
+ std::string subdir = keyblob_subdir(keyblob_dir, GetParam(), /* create? */ false);
+ if (subdir.empty()) {
+ GTEST_SKIP() << "No keyblob directory provided with (e.g.) --keyblob_dir "
+ "/data/local/tmp/keymint-blobs";
+ }
+
+ for (std::string name : keyblob_names(SecLevel())) {
+ for (bool with_hidden : {false, true}) {
+ auto builder = AuthorizationSetBuilder();
+ if (with_hidden) {
+ // Build a variant keyblob that requires app_id/app_data
+ builder.Authorization(TAG_APPLICATION_ID, "appid")
+ .Authorization(TAG_APPLICATION_DATA, "appdata");
+ name += "-hidden";
+ }
+ if (!requires_rr(name)) {
+ std::cerr << "Skipping keyblob file '" << name
+ << "' which does not use rollback resistance\n";
+ continue;
+ }
+ SCOPED_TRACE(testing::Message() << name);
+ std::vector<uint8_t> keyblob = load_keyblob(subdir, name);
+ if (keyblob.empty()) {
+ std::cerr << "Skipping missing keyblob file '" << name
+ << "', assuming rollback resistance unavailable\n";
+ continue;
+ }
+
+ // Delete the key
+ ASSERT_EQ(ErrorCode::OK, DeleteKey(&keyblob));
+
+ // Remove all files relating to the deleted key.
+ std::cerr << "Deleting files for deleted key '" << name << ";";
+ delete_keyblob(subdir, name);
+
+ // Attempting to use the keyblob after deletion should fail.
+ AuthorizationSet out_params;
+ if (name.find("aes-key") != std::string::npos) {
+ builder.BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+ EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
+ Begin(KeyPurpose::ENCRYPT, keyblob, builder, &out_params));
+ } else {
+ FAIL() << "Unexpected name: " << name;
+ }
+ }
+ }
+}
+
+INSTANTIATE_KEYMINT_AIDL_TEST(KeyBlobUpgradeTest);
+
+} // namespace aidl::android::hardware::security::keymint::test
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
index 43ad30a..6c012fa 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
@@ -184,6 +184,7 @@
bool KeyMintAidlTestBase::arm_deleteAllKeys = false;
bool KeyMintAidlTestBase::dump_Attestations = false;
+std::string KeyMintAidlTestBase::keyblob_dir;
uint32_t KeyMintAidlTestBase::boot_patch_level(
const vector<KeyCharacteristics>& key_characteristics) {
@@ -946,9 +947,15 @@
const AuthorizationSet& params) {
SCOPED_TRACE("LocalVerifyMessage");
- // Retrieve the public key from the leaf certificate.
ASSERT_GT(cert_chain_.size(), 0);
- X509_Ptr key_cert(parse_cert_blob(cert_chain_[0].encodedCertificate));
+ LocalVerifyMessage(cert_chain_[0].encodedCertificate, message, signature, params);
+}
+
+void KeyMintAidlTestBase::LocalVerifyMessage(const vector<uint8_t>& der_cert, const string& message,
+ const string& signature,
+ const AuthorizationSet& params) {
+ // Retrieve the public key from the leaf certificate.
+ X509_Ptr key_cert(parse_cert_blob(der_cert));
ASSERT_TRUE(key_cert.get());
EVP_PKEY_Ptr pub_key(X509_get_pubkey(key_cert.get()));
ASSERT_TRUE(pub_key.get());
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
index 5b09ca5..908eeab 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
@@ -64,6 +64,10 @@
static bool arm_deleteAllKeys;
static bool dump_Attestations;
+ // Directory to store/retrieve keyblobs, using subdirectories named for the
+ // KeyMint instance in question (e.g. "./default/", "./strongbox/").
+ static std::string keyblob_dir;
+
void SetUp() override;
void TearDown() override {
if (key_blob_.size()) {
@@ -206,6 +210,8 @@
const string& signature, const AuthorizationSet& params);
void VerifyMessage(const string& message, const string& signature,
const AuthorizationSet& params);
+ void LocalVerifyMessage(const vector<uint8_t>& der_cert, const string& message,
+ const string& signature, const AuthorizationSet& params);
void LocalVerifyMessage(const string& message, const string& signature,
const AuthorizationSet& params);
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index ca18082..2440977 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -1136,8 +1136,8 @@
* that has been generated using an associate IRemotelyProvisionedComponent.
*/
TEST_P(NewKeyGenerationTest, RsaWithRkpAttestation) {
- if (AidlVersion() < 2) {
- GTEST_SKIP() << "Only required starting with KeyMint v2";
+ if (get_vsr_api_level() < 32 || AidlVersion() < 2) {
+ GTEST_SKIP() << "Only required for VSR 12+ and KeyMint 2+";
}
// There should be an IRemotelyProvisionedComponent instance associated with the KeyMint
@@ -1214,8 +1214,8 @@
* that has been generated using an associate IRemotelyProvisionedComponent.
*/
TEST_P(NewKeyGenerationTest, EcdsaWithRkpAttestation) {
- if (AidlVersion() < 2) {
- GTEST_SKIP() << "Only required starting with KeyMint v2";
+ if (get_vsr_api_level() < 32 || AidlVersion() < 2) {
+ GTEST_SKIP() << "Only required for VSR 12+ and KeyMint 2+";
}
// There should be an IRemotelyProvisionedComponent instance associated with the KeyMint
@@ -8649,6 +8649,15 @@
// interactions.
aidl::android::hardware::security::keymint::test::check_boot_pl = false;
}
+ if (std::string(argv[i]) == "--keyblob_dir") {
+ if (i + 1 >= argc) {
+ std::cerr << "Missing argument for --keyblob_dir\n";
+ return 1;
+ }
+ aidl::android::hardware::security::keymint::test::KeyMintAidlTestBase::keyblob_dir =
+ std::string(argv[i + 1]);
+ ++i;
+ }
}
}
return RUN_ALL_TESTS();
diff --git a/security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl b/security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
index 5485db3..ff710f1 100644
--- a/security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
+++ b/security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
@@ -115,11 +115,9 @@
interface IRemotelyProvisionedComponent {
const int STATUS_FAILED = 1;
const int STATUS_INVALID_MAC = 2;
- // --------- START: Versions 1 and 2 Only ----------
- const int STATUS_PRODUCTION_KEY_IN_TEST_REQUEST = 3;
+ const int STATUS_PRODUCTION_KEY_IN_TEST_REQUEST = 3; // Versions 1 and 2 Only
const int STATUS_TEST_KEY_IN_PRODUCTION_REQUEST = 4;
- const int STATUS_INVALID_EEK = 5;
- // --------- END: Versions 1 and 2 Only ------------
+ const int STATUS_INVALID_EEK = 5; // Versions 1 and 2 Only
const int STATUS_REMOVED = 6;
/**
@@ -224,7 +222,7 @@
* 2 : bstr ; KID : EEK ID
* 3 : -25, ; Algorithm : ECDH-ES + HKDF-256
* -1 : 4, ; Curve : X25519
- * -2 : bstr ; X25519 public key
+ * -2 : bstr ; X25519 public key, little-endian
* }
*
* EekP256 = { ; COSE_Key
@@ -347,8 +345,8 @@
* protected: bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 },
* unprotected: {},
* payload: bstr .cbor Data / nil,
- * signature: bstr ; PureEd25519(CDI_Leaf_Priv, bstr .cbor SignedDataSigStruct<Data>) /
- * ; ECDSA(CDI_Leaf_Priv, bstr .cbor SignedDataSigStruct<Data>)
+ * signature: bstr ; PureEd25519(CDI_Leaf_Priv, SignedDataSigStruct<Data>) /
+ * ; ECDSA(CDI_Leaf_Priv, SignedDataSigStruct<Data>)
* ]
*
* ; Sig_structure for SignedData
@@ -427,8 +425,8 @@
* protected : bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 },
* unprotected: {},
* payload: bstr .cbor DiceChainEntryPayload,
- * signature: bstr ; PureEd25519(SigningKey, bstr .cbor DiceChainEntryInput) /
- * ; ECDSA(SigningKey, bstr .cbor DiceChainEntryInput)
+ * signature: bstr ; PureEd25519(SigningKey, DiceChainEntryInput) /
+ * ; ECDSA(SigningKey, DiceChainEntryInput)
* ; See RFC 8032 for details of how to encode the signature value
* ; for Ed25519.
* ]
@@ -442,12 +440,9 @@
*
* ; The following section defines some types that are reused throughout the above
* ; data structures.
- * PubKeyX25519 = { ; COSE_Key
- * 1 : 1, ; Key type : Octet Key Pair
- * -1 : 4, ; Curve : X25519
- * -2 : bstr ; Sender X25519 public key
- * }
- *
+ * ; NOTE: Integer encoding is different for Ed25519 and P256 keys:
+ * ; - Ed25519 is LE: https://www.rfc-editor.org/rfc/rfc8032#section-3.1
+ * ; - P256 is BE: https://www.secg.org/sec1-v2.pdf#page=19 (section 2.3.7)
* PubKeyEd25519 = { ; COSE_Key
* 1 : 1, ; Key type : octet key pair
* 3 : AlgorithmEdDSA, ; Algorithm : EdDSA
@@ -455,19 +450,12 @@
* -2 : bstr ; X coordinate, little-endian
* }
*
- * PubKeyEcdhP256 = { ; COSE_Key
- * 1 : 2, ; Key type : EC2
- * -1 : 1, ; Curve : P256
- * -2 : bstr ; Sender X coordinate
- * -3 : bstr ; Sender Y coordinate
- * }
- *
* PubKeyECDSA256 = { ; COSE_Key
* 1 : 2, ; Key type : EC2
* 3 : AlgorithmES256, ; Algorithm : ECDSA w/ SHA-256
* -1 : 1, ; Curve: P256
- * -2 : bstr, ; X coordinate
- * -3 : bstr ; Y coordinate
+ * -2 : bstr, ; X coordinate, big-endian
+ * -3 : bstr ; Y coordinate, big-endian
* }
*
* AlgorithmES256 = -7
diff --git a/security/rkp/aidl/android/hardware/security/keymint/MacedPublicKey.aidl b/security/rkp/aidl/android/hardware/security/keymint/MacedPublicKey.aidl
index 275e322..1e41d1b 100644
--- a/security/rkp/aidl/android/hardware/security/keymint/MacedPublicKey.aidl
+++ b/security/rkp/aidl/android/hardware/security/keymint/MacedPublicKey.aidl
@@ -36,12 +36,15 @@
* ]
*
* ; NOTE: -70000 is deprecated for v3 HAL implementations.
+ * ; NOTE: Integer encoding is different for Ed25519 and P256 keys:
+ * ; - Ed25519 is LE: https://www.rfc-editor.org/rfc/rfc8032#section-3.1
+ * ; - P256 is BE: https://www.secg.org/sec1-v2.pdf#page=19 (section 2.3.7)
* PublicKey = { ; COSE_Key
* 1 : 2, ; Key type : EC2
* 3 : -7, ; Algorithm : ES256
* -1 : 1, ; Curve : P256
- * -2 : bstr, ; X coordinate, little-endian
- * -3 : bstr, ; Y coordinate, little-endian
+ * -2 : bstr, ; X coordinate, big-endian
+ * -3 : bstr, ; Y coordinate, big-endian
* -70000 : nil ; Presence indicates this is a test key. If set, K_mac is
* ; all zeros.
* },
diff --git a/security/rkp/aidl/android/hardware/security/keymint/ProtectedData.aidl b/security/rkp/aidl/android/hardware/security/keymint/ProtectedData.aidl
index d59508b..3f699bc 100644
--- a/security/rkp/aidl/android/hardware/security/keymint/ProtectedData.aidl
+++ b/security/rkp/aidl/android/hardware/security/keymint/ProtectedData.aidl
@@ -209,7 +209,7 @@
* PubKeyX25519 = { ; COSE_Key
* 1 : 1, ; Key type : Octet Key Pair
* -1 : 4, ; Curve : X25519
- * -2 : bstr ; Sender X25519 public key
+ * -2 : bstr ; Sender X25519 public key, little-endian
* }
*
* PubKeyEd25519 = { ; COSE_Key
@@ -222,16 +222,16 @@
* PubKeyEcdhP256 = { ; COSE_Key
* 1 : 2, ; Key type : EC2
* -1 : 1, ; Curve : P256
- * -2 : bstr ; Sender X coordinate
- * -3 : bstr ; Sender Y coordinate
+ * -2 : bstr ; Sender X coordinate, big-endian
+ * -3 : bstr ; Sender Y coordinate, big-endian
* }
*
* PubKeyECDSA256 = { ; COSE_Key
* 1 : 2, ; Key type : EC2
* 3 : AlgorithmES256, ; Algorithm : ECDSA w/ SHA-256
* -1 : 1, ; Curve: P256
- * -2 : bstr, ; X coordinate
- * -3 : bstr ; Y coordinate
+ * -2 : bstr, ; X coordinate, big-endian
+ * -3 : bstr ; Y coordinate, big-endian
* }
*
* AlgorithmES256 = -7
diff --git a/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp b/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
index aebcf67..bbda56d 100644
--- a/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
+++ b/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
@@ -223,6 +223,20 @@
ASSERT_TRUE(provisionable_->getHardwareInfo(&hwInfo).isOk());
const std::set<int> validCurves = {RpcHardwareInfo::CURVE_P256, RpcHardwareInfo::CURVE_25519};
+ // First check for the implementations that supports only IRPC V3+.
+ if (rpcHardwareInfo.versionNumber >= VERSION_WITHOUT_TEST_MODE) {
+ bytevec keysToSignMac;
+ DeviceInfo deviceInfo;
+ ProtectedData protectedData;
+ auto status = provisionable_->generateCertificateRequest(false, {}, {}, {}, &deviceInfo,
+ &protectedData, &keysToSignMac);
+ if (!status.isOk() &&
+ (status.getServiceSpecificError() == BnRemotelyProvisionedComponent::STATUS_REMOVED)) {
+ ASSERT_EQ(hwInfo.supportedEekCurve, RpcHardwareInfo::CURVE_NONE)
+ << "Invalid curve: " << hwInfo.supportedEekCurve;
+ return;
+ }
+ }
ASSERT_EQ(validCurves.count(hwInfo.supportedEekCurve), 1)
<< "Invalid curve: " << hwInfo.supportedEekCurve;
}
diff --git a/sensors/1.0/default/OWNERS b/sensors/1.0/default/OWNERS
deleted file mode 100644
index 90c2330..0000000
--- a/sensors/1.0/default/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-arthuri@google.com
-bduddie@google.com
-stange@google.com
diff --git a/sensors/1.0/vts/functional/OWNERS b/sensors/1.0/vts/functional/OWNERS
deleted file mode 100644
index e20125b..0000000
--- a/sensors/1.0/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 62965
-include ../../../common/vts/OWNERS
diff --git a/sensors/2.0/default/OWNERS b/sensors/2.0/default/OWNERS
deleted file mode 100644
index 90c2330..0000000
--- a/sensors/2.0/default/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-arthuri@google.com
-bduddie@google.com
-stange@google.com
diff --git a/sensors/2.0/multihal/OWNERS b/sensors/2.0/multihal/OWNERS
deleted file mode 100644
index e955670..0000000
--- a/sensors/2.0/multihal/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-arthuri@google.com
-bduddie@google.com
-stange@google.com
\ No newline at end of file
diff --git a/sensors/2.0/vts/functional/OWNERS b/sensors/2.0/vts/functional/OWNERS
deleted file mode 100644
index e20125b..0000000
--- a/sensors/2.0/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 62965
-include ../../../common/vts/OWNERS
diff --git a/sensors/2.1/default/OWNERS b/sensors/2.1/default/OWNERS
deleted file mode 100644
index 90c2330..0000000
--- a/sensors/2.1/default/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-arthuri@google.com
-bduddie@google.com
-stange@google.com
diff --git a/sensors/2.1/multihal/OWNERS b/sensors/2.1/multihal/OWNERS
deleted file mode 100644
index e955670..0000000
--- a/sensors/2.1/multihal/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-arthuri@google.com
-bduddie@google.com
-stange@google.com
\ No newline at end of file
diff --git a/sensors/2.1/vts/functional/OWNERS b/sensors/2.1/vts/functional/OWNERS
deleted file mode 100644
index e20125b..0000000
--- a/sensors/2.1/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 62965
-include ../../../common/vts/OWNERS
diff --git a/sensors/common/vts/OWNERS b/sensors/OWNERS
similarity index 83%
rename from sensors/common/vts/OWNERS
rename to sensors/OWNERS
index 1b9a2f8..e7ebd3e 100644
--- a/sensors/common/vts/OWNERS
+++ b/sensors/OWNERS
@@ -1,5 +1,5 @@
# Bug component: 62965
-# Sensors team
+
arthuri@google.com
bduddie@google.com
stange@google.com
diff --git a/sensors/aidl/default/OWNERS b/sensors/aidl/default/OWNERS
deleted file mode 100644
index e955670..0000000
--- a/sensors/aidl/default/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-arthuri@google.com
-bduddie@google.com
-stange@google.com
\ No newline at end of file
diff --git a/sensors/aidl/multihal/OWNERS b/sensors/aidl/multihal/OWNERS
deleted file mode 100644
index e955670..0000000
--- a/sensors/aidl/multihal/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-arthuri@google.com
-bduddie@google.com
-stange@google.com
\ No newline at end of file
diff --git a/sensors/aidl/vts/OWNERS b/sensors/aidl/vts/OWNERS
deleted file mode 100644
index 90c2330..0000000
--- a/sensors/aidl/vts/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-arthuri@google.com
-bduddie@google.com
-stange@google.com
diff --git a/sensors/common/default/2.X/OWNERS b/sensors/common/default/2.X/OWNERS
deleted file mode 100644
index 90c2330..0000000
--- a/sensors/common/default/2.X/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-arthuri@google.com
-bduddie@google.com
-stange@google.com
diff --git a/sensors/common/utils/OWNERS b/sensors/common/utils/OWNERS
deleted file mode 100644
index 90c2330..0000000
--- a/sensors/common/utils/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-arthuri@google.com
-bduddie@google.com
-stange@google.com
diff --git a/sensors/common/vts/utils/OWNERS b/sensors/common/vts/utils/OWNERS
deleted file mode 100644
index 892da15..0000000
--- a/sensors/common/vts/utils/OWNERS
+++ /dev/null
@@ -1,8 +0,0 @@
-# Sensors team
-arthuri@google.com
-bduddie@google.com
-stange@google.com
-
-# VTS team
-trong@google.com
-yim@google.com
diff --git a/tv/earc/aidl/Android.bp b/tv/earc/aidl/Android.bp
new file mode 100644
index 0000000..5db6032
--- /dev/null
+++ b/tv/earc/aidl/Android.bp
@@ -0,0 +1,29 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+aidl_interface {
+ name: "android.hardware.tv.earc",
+ vendor_available: true,
+ srcs: ["android/hardware/tv/earc/*.aidl"],
+ stability: "vintf",
+ backend: {
+ java: {
+ sdk_version: "module_current",
+ },
+ },
+}
diff --git a/tv/earc/aidl/OWNERS b/tv/earc/aidl/OWNERS
new file mode 100644
index 0000000..d9c6783
--- /dev/null
+++ b/tv/earc/aidl/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 826094
+include platform/frameworks/base:/core/java/android/hardware/hdmi/OWNERS
\ No newline at end of file
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LocationResponseType.aidl b/tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/IEArc.aidl
similarity index 82%
copy from radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LocationResponseType.aidl
copy to tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/IEArc.aidl
index e89a40f..552bb46 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LocationResponseType.aidl
+++ b/tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/IEArc.aidl
@@ -31,10 +31,12 @@
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
-package android.hardware.radio.network;
-@Backing(type="int") @JavaDerive(toString=true) @VintfStability
-enum LocationResponseType {
- REJECTED = 0,
- ACCEPTED_NO_LOCATION_PROVIDED = 1,
- ACCEPTED_LOCATION_PROVIDED = 2,
+package android.hardware.tv.earc;
+@VintfStability
+interface IEArc {
+ void setEArcEnabled(in boolean enabled);
+ boolean isEArcEnabled();
+ void setCallback(in android.hardware.tv.earc.IEArcCallback callback);
+ android.hardware.tv.earc.IEArcStatus getState(in int portId);
+ byte[] getLastReportedAudioCapabilities(in int portId);
}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LocationResponseType.aidl b/tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/IEArcCallback.aidl
similarity index 86%
copy from radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LocationResponseType.aidl
copy to tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/IEArcCallback.aidl
index e89a40f..ef99824 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LocationResponseType.aidl
+++ b/tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/IEArcCallback.aidl
@@ -31,10 +31,9 @@
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
-package android.hardware.radio.network;
-@Backing(type="int") @JavaDerive(toString=true) @VintfStability
-enum LocationResponseType {
- REJECTED = 0,
- ACCEPTED_NO_LOCATION_PROVIDED = 1,
- ACCEPTED_LOCATION_PROVIDED = 2,
+package android.hardware.tv.earc;
+@VintfStability
+interface IEArcCallback {
+ oneway void onStateChange(in android.hardware.tv.earc.IEArcStatus status, in int portId);
+ oneway void onCapabilitiesReported(in byte[] rawCapabilities, in int portId);
}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LocationResponseType.aidl b/tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/IEArcStatus.aidl
similarity index 87%
copy from radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LocationResponseType.aidl
copy to tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/IEArcStatus.aidl
index e89a40f..729c657 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LocationResponseType.aidl
+++ b/tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/IEArcStatus.aidl
@@ -31,10 +31,11 @@
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
-package android.hardware.radio.network;
-@Backing(type="int") @JavaDerive(toString=true) @VintfStability
-enum LocationResponseType {
- REJECTED = 0,
- ACCEPTED_NO_LOCATION_PROVIDED = 1,
- ACCEPTED_LOCATION_PROVIDED = 2,
+package android.hardware.tv.earc;
+@Backing(type="byte") @VintfStability
+enum IEArcStatus {
+ STATUS_IDLE = 0,
+ STATUS_EARC_PENDING = 1,
+ STATUS_ARC_PENDING = 2,
+ STATUS_EARC_CONNECTED = 3,
}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LocationResponseType.aidl b/tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/Result.aidl
similarity index 87%
rename from radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LocationResponseType.aidl
rename to tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/Result.aidl
index e89a40f..3679d3b 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LocationResponseType.aidl
+++ b/tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/Result.aidl
@@ -31,10 +31,11 @@
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
-package android.hardware.radio.network;
-@Backing(type="int") @JavaDerive(toString=true) @VintfStability
-enum LocationResponseType {
- REJECTED = 0,
- ACCEPTED_NO_LOCATION_PROVIDED = 1,
- ACCEPTED_LOCATION_PROVIDED = 2,
+package android.hardware.tv.earc;
+@VintfStability
+enum Result {
+ SUCCESS = 0,
+ FAILURE_UNKNOWN = 1,
+ FAILURE_INVALID_ARGS = 2,
+ FAILURE_NOT_SUPPORTED = 4,
}
diff --git a/tv/earc/aidl/android/hardware/tv/earc/IEArc.aidl b/tv/earc/aidl/android/hardware/tv/earc/IEArc.aidl
new file mode 100644
index 0000000..bb8dabf
--- /dev/null
+++ b/tv/earc/aidl/android/hardware/tv/earc/IEArc.aidl
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tv.earc;
+
+import android.hardware.tv.earc.IEArcCallback;
+import android.hardware.tv.earc.IEArcStatus;
+
+/**
+ * eARC HAL interface definition
+ */
+@VintfStability
+interface IEArc {
+ /**
+ * Function to enable or disable eARC in the device's driver and HAL. If enabled, the driver and
+ * HAL shall attempt to establish an eARC connection and inform the Android framework about
+ * updates with IEArcCallback callbacks. If disabled, the driver and HAL shall not attempt to
+ * establish an eARC connection and shall not send any IEArcCallback callbacks to the Android
+ * framework.
+ * The error status is set to
+ * {@code SUCCESS} if the setting could be changed to the value passed.
+ * {@code FAILURE_NOT_SUPPORTED} if the setting is not supported.
+ * {@code FAILURE_INVALID_ARGS} if the setting value is invalid.
+ * {@code FAILURE_UNKNOWN} if there was an unknown failure.
+ */
+ void setEArcEnabled(in boolean enabled);
+
+ /**
+ * Function to check if eARC is enabled in the device's driver and HAL.
+ */
+ boolean isEArcEnabled();
+
+ /**
+ * Function to set callback that the HAL will use to notify the system of connection state
+ * changes and capabilities of connected devices.
+ *
+ * @param callback The callback object to pass the events to the system. A previously registered
+ * callback should be replaced by this new object. If callback is {@code null} the
+ * previously registered callback should be deregistered.
+ */
+ void setCallback(in IEArcCallback callback);
+
+ /**
+ * Getter for the current eARC state of a port.
+ *
+ * @param portId The port ID for which the state is to be reported.
+ * @return The state of the port.
+ */
+ IEArcStatus getState(in int portId);
+
+ /**
+ * Getter for the most recent capabilities reported by the device connected to port.
+ *
+ * @param portId The port ID on which the device is connected.
+ * @return The raw, unparsed audio capabilities
+ */
+ byte[] getLastReportedAudioCapabilities(in int portId);
+}
diff --git a/tv/earc/aidl/android/hardware/tv/earc/IEArcCallback.aidl b/tv/earc/aidl/android/hardware/tv/earc/IEArcCallback.aidl
new file mode 100644
index 0000000..c70191f
--- /dev/null
+++ b/tv/earc/aidl/android/hardware/tv/earc/IEArcCallback.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.tv.earc;
+
+import android.hardware.tv.earc.IEArcStatus;
+
+/**
+ * eARC HAL callback methods
+ */
+@VintfStability
+oneway interface IEArcCallback {
+ /**
+ * The callback function that must be called by the eARC driver and HAL implementation to notify
+ * the Android framework of an eARC status change.
+ * @param status The new status of the port
+ * @param portId The port ID for which the state change is being reported
+ */
+ void onStateChange(in IEArcStatus status, in int portId);
+
+ /**
+ * The callback function that must be called by the eARC driver and HAL implementation to
+ * notify the Android framework of the audio capabilities reported by the connected device. On
+ * every state change to {@code STATUS_EARC_CONNECTED}, the driver shall read the capabilities
+ * reported by the eARC RX. The onStateChange callback shall always be invoked first and the
+ * onCapabilitiesReported callback shall be invoked second.
+ * @param rawCapabilities The raw unparsed audio capabilities (Ref "Section 9.5.3.6 - eARC RX
+ * Capabilities Data Structure" in HDMI 2.1 specification).
+ * @param portId The port ID for which the audio capabilities are being reported
+ */
+ void onCapabilitiesReported(in byte[] rawCapabilities, in int portId);
+}
diff --git a/tv/earc/aidl/android/hardware/tv/earc/IEArcStatus.aidl b/tv/earc/aidl/android/hardware/tv/earc/IEArcStatus.aidl
new file mode 100644
index 0000000..ecb1c85
--- /dev/null
+++ b/tv/earc/aidl/android/hardware/tv/earc/IEArcStatus.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tv.earc;
+
+/**
+ * eARC HAL connection states
+ */
+@VintfStability
+@Backing(type="byte")
+enum IEArcStatus {
+ STATUS_IDLE = 0,
+ STATUS_EARC_PENDING = 1,
+ STATUS_ARC_PENDING = 2,
+ STATUS_EARC_CONNECTED = 3,
+}
diff --git a/tv/earc/aidl/android/hardware/tv/earc/Result.aidl b/tv/earc/aidl/android/hardware/tv/earc/Result.aidl
new file mode 100644
index 0000000..054518a
--- /dev/null
+++ b/tv/earc/aidl/android/hardware/tv/earc/Result.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tv.earc;
+
+/**
+ * Result enum for return values. Used by the HDMI related AIDL.
+ */
+@VintfStability
+enum Result {
+ /**
+ * The eARC enabled setting was set successfully.
+ */
+ SUCCESS = 0,
+
+ /**
+ * The eARC enabled setting could not be set because of an unknown failure.
+ */
+ FAILURE_UNKNOWN = 1,
+
+ /**
+ * The eARC enabled setting could not be set because the arguments were invalid.
+ */
+ FAILURE_INVALID_ARGS = 2,
+
+ /**
+ * The eARC enabled setting could not be set because eARC feature is not supported.
+ */
+ FAILURE_NOT_SUPPORTED = 4,
+}
diff --git a/tv/earc/aidl/default/Android.bp b/tv/earc/aidl/default/Android.bp
new file mode 100644
index 0000000..399f029
--- /dev/null
+++ b/tv/earc/aidl/default/Android.bp
@@ -0,0 +1,58 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_binary {
+ name: "android.hardware.tv.earc-service",
+ vintf_fragments: ["android.hardware.tv.earc-service.xml"],
+ relative_install_path: "hw",
+ vendor: true,
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ ],
+ init_rc: ["android.hardware.tv.earc-service.rc"],
+ srcs: [
+ "serviceMock.cpp",
+ "EArcMock.cpp",
+ ],
+ shared_libs: [
+ "libbinder_ndk",
+ "liblog",
+ "libbase",
+ "libutils",
+ "libhardware",
+ "libhidlbase",
+ "android.hardware.tv.earc-V1-ndk",
+ ],
+}
+
+cc_fuzz {
+ name: "android.hardware.tv.earc-service_fuzzer",
+ defaults: ["service_fuzzer_defaults"],
+ static_libs: [
+ "android.hardware.tv.earc-V1-ndk",
+ "liblog",
+ ],
+ srcs: [
+ "fuzzer.cpp",
+ "EArcMock.cpp",
+ ],
+ fuzz_config: {
+ componentid: 826094,
+ },
+}
diff --git a/tv/earc/aidl/default/EArcMock.cpp b/tv/earc/aidl/default/EArcMock.cpp
new file mode 100644
index 0000000..9bccc18
--- /dev/null
+++ b/tv/earc/aidl/default/EArcMock.cpp
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.tv.earc"
+#include <android-base/logging.h>
+#include <fcntl.h>
+#include <utils/Log.h>
+
+#include "EArcMock.h"
+
+using ndk::ScopedAStatus;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace earc {
+namespace implementation {
+
+void EArcMock::serviceDied(void* cookie) {
+ ALOGE("EArcMock died");
+ auto eArc = static_cast<EArcMock*>(cookie);
+ eArc->mEArcEnabled = false;
+}
+
+ScopedAStatus EArcMock::setEArcEnabled(bool in_enabled) {
+ mEArcEnabled = in_enabled;
+ if (mEArcEnabled != in_enabled) {
+ return ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(Result::FAILURE_UNKNOWN));
+ } else {
+ return ScopedAStatus::ok();
+ }
+}
+
+ScopedAStatus EArcMock::isEArcEnabled(bool* _aidl_return) {
+ *_aidl_return = mEArcEnabled;
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus EArcMock::getState(int32_t portId, IEArcStatus* _aidl_return) {
+ // Maintain port connection status and update on hotplug event
+ if (portId <= mTotalPorts && portId >= 1) {
+ *_aidl_return = mPortStatus[portId];
+ } else {
+ return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus EArcMock::getLastReportedAudioCapabilities(int32_t portId,
+ std::vector<uint8_t>* _aidl_return) {
+ if (portId <= mTotalPorts && portId >= 1) {
+ *_aidl_return = mCapabilities[portId];
+ } else {
+ return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus EArcMock::setCallback(const std::shared_ptr<IEArcCallback>& callback) {
+ if (mCallback != nullptr) {
+ mCallback = nullptr;
+ }
+
+ if (callback != nullptr) {
+ mCallback = callback;
+ AIBinder_linkToDeath(this->asBinder().get(), mDeathRecipient.get(), 0 /* cookie */);
+ }
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus EArcMock::reportCapabilities(const std::vector<uint8_t> capabilities,
+ int32_t portId) {
+ if (mCallback != nullptr) {
+ mCallback->onCapabilitiesReported(capabilities, portId);
+ return ScopedAStatus::ok();
+ } else {
+ return ScopedAStatus::fromExceptionCode(EX_NULL_POINTER);
+ }
+}
+
+ScopedAStatus EArcMock::changeState(const IEArcStatus status, int32_t portId) {
+ if (mCallback != nullptr) {
+ mCallback->onStateChange(status, portId);
+ return ScopedAStatus::ok();
+ } else {
+ return ScopedAStatus::fromExceptionCode(EX_NULL_POINTER);
+ }
+}
+
+EArcMock::EArcMock() {
+ ALOGE("[halimp_aidl] Opening a virtual eARC HAL for testing and virtual machine.");
+ mCallback = nullptr;
+ mCapabilities.resize(mTotalPorts);
+ mPortStatus.resize(mTotalPorts);
+ mPortStatus[0] = IEArcStatus::STATUS_IDLE;
+ mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient_new(serviceDied));
+}
+
+} // namespace implementation
+} // namespace earc
+} // namespace tv
+} // namespace hardware
+} // namespace android
diff --git a/tv/earc/aidl/default/EArcMock.h b/tv/earc/aidl/default/EArcMock.h
new file mode 100644
index 0000000..9081950
--- /dev/null
+++ b/tv/earc/aidl/default/EArcMock.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/android/hardware/tv/earc/BnEArc.h>
+#include <aidl/android/hardware/tv/earc/Result.h>
+#include <algorithm>
+#include <vector>
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace earc {
+namespace implementation {
+
+using ::aidl::android::hardware::tv::earc::BnEArc;
+using ::aidl::android::hardware::tv::earc::IEArc;
+using ::aidl::android::hardware::tv::earc::IEArcCallback;
+using ::aidl::android::hardware::tv::earc::IEArcStatus;
+using ::aidl::android::hardware::tv::earc::Result;
+
+struct EArcMock : public BnEArc {
+ EArcMock();
+
+ ::ndk::ScopedAStatus setEArcEnabled(bool in_enabled) override;
+ ::ndk::ScopedAStatus isEArcEnabled(bool* _aidl_return) override;
+ ::ndk::ScopedAStatus setCallback(const std::shared_ptr<IEArcCallback>& in_callback) override;
+ ::ndk::ScopedAStatus getState(int32_t in_portId, IEArcStatus* _aidl_return) override;
+ ::ndk::ScopedAStatus getLastReportedAudioCapabilities(
+ int32_t in_portId, std::vector<uint8_t>* _aidl_return) override;
+ ::ndk::ScopedAStatus reportCapabilities(const std::vector<uint8_t> capabilities,
+ int32_t portId);
+ ::ndk::ScopedAStatus changeState(const IEArcStatus status, int32_t portId);
+
+ private:
+ static void* __threadLoop(void* data);
+ void threadLoop();
+
+ private:
+ static void serviceDied(void* cookie);
+ std::shared_ptr<IEArcCallback> mCallback;
+
+ // Variables for the virtual EARC hal impl
+ std::vector<std::vector<uint8_t>> mCapabilities;
+ std::vector<IEArcStatus> mPortStatus;
+ bool mEArcEnabled = true;
+
+ // Port configuration
+ int mTotalPorts = 1;
+
+ // Testing variables
+ pthread_t mThreadId = 0;
+
+ ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
+};
+} // namespace implementation
+} // namespace earc
+} // Namespace tv
+} // namespace hardware
+} // namespace android
diff --git a/tv/earc/aidl/default/android.hardware.tv.earc-service.rc b/tv/earc/aidl/default/android.hardware.tv.earc-service.rc
new file mode 100644
index 0000000..0d9063e
--- /dev/null
+++ b/tv/earc/aidl/default/android.hardware.tv.earc-service.rc
@@ -0,0 +1,5 @@
+service vendor.earc-default /vendor/bin/hw/android.hardware.tv.earc-service
+ interface aidl android.hardware.tv.earc.IEArc/default
+ class hal
+ user system
+ group system
diff --git a/tv/earc/aidl/default/android.hardware.tv.earc-service.xml b/tv/earc/aidl/default/android.hardware.tv.earc-service.xml
new file mode 100644
index 0000000..4d66d98
--- /dev/null
+++ b/tv/earc/aidl/default/android.hardware.tv.earc-service.xml
@@ -0,0 +1,10 @@
+<manifest version="1.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.tv.earc</name>
+ <version>1</version>
+ <interface>
+ <name>IEArc</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/tv/earc/aidl/default/fuzzer.cpp b/tv/earc/aidl/default/fuzzer.cpp
new file mode 100644
index 0000000..5036853
--- /dev/null
+++ b/tv/earc/aidl/default/fuzzer.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <EArcMock.h>
+#include <fuzzbinder/libbinder_ndk_driver.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+using android::fuzzService;
+using android::hardware::tv::earc::implementation::EArcMock;
+using ndk::SharedRefBase;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ auto earcAidl = SharedRefBase::make<EArcMock>();
+
+ fuzzService(earcAidl->asBinder().get(), FuzzedDataProvider(data, size));
+
+ return 0;
+}
diff --git a/tv/earc/aidl/default/serviceMock.cpp b/tv/earc/aidl/default/serviceMock.cpp
new file mode 100644
index 0000000..1ea7262
--- /dev/null
+++ b/tv/earc/aidl/default/serviceMock.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.tv.earc-service-shim"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <hidl/HidlTransportSupport.h>
+#include <utils/Log.h>
+#include "EArcMock.h"
+
+using android::hardware::tv::earc::implementation::EArcMock;
+
+int main() {
+ ABinderProcess_setThreadPoolMaxThreadCount(1);
+ ABinderProcess_startThreadPool();
+
+ std::shared_ptr<EArcMock> earcAidl = ndk::SharedRefBase::make<EArcMock>();
+ const std::string instance = std::string() + EArcMock::descriptor + "/default";
+ binder_status_t status =
+ AServiceManager_addService(earcAidl->asBinder().get(), instance.c_str());
+ CHECK_EQ(status, STATUS_OK);
+
+ ABinderProcess_joinThreadPool();
+ return 0;
+}
diff --git a/tv/earc/aidl/vts/functional/Android.bp b/tv/earc/aidl/vts/functional/Android.bp
new file mode 100644
index 0000000..797547e
--- /dev/null
+++ b/tv/earc/aidl/vts/functional/Android.bp
@@ -0,0 +1,37 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_test {
+ name: "VtsHalTvEArcAidlTargetTest",
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "use_libaidlvintf_gtest_helper_static",
+ ],
+ srcs: ["VtsHalTvEArcAidlTargetTest.cpp"],
+ static_libs: [
+ "android.hardware.tv.earc-V1-ndk",
+ ],
+ shared_libs: [
+ "libbinder_ndk",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+ disable_framework: true,
+}
diff --git a/tv/earc/aidl/vts/functional/VtsHalTvEArcAidlTargetTest.cpp b/tv/earc/aidl/vts/functional/VtsHalTvEArcAidlTargetTest.cpp
new file mode 100644
index 0000000..12f48c3
--- /dev/null
+++ b/tv/earc/aidl/vts/functional/VtsHalTvEArcAidlTargetTest.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "EArc_hal_test"
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/tv/earc/BnEArcCallback.h>
+#include <aidl/android/hardware/tv/earc/IEArc.h>
+#include <aidl/android/hardware/tv/earc/IEArcStatus.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <gtest/gtest.h>
+#include <log/log.h>
+#include <sstream>
+#include <vector>
+
+using ::aidl::android::hardware::tv::earc::BnEArcCallback;
+using ::aidl::android::hardware::tv::earc::IEArc;
+using ::aidl::android::hardware::tv::earc::IEArcCallback;
+using ::aidl::android::hardware::tv::earc::IEArcStatus;
+using ::ndk::SpAIBinder;
+
+// The main test class for TV EARC HAL.
+class EArcTest : public ::testing::TestWithParam<std::string> {
+ static void serviceDied(void* /* cookie */) { ALOGE("VtsHalTvCecAidlTargetTest died"); }
+
+ public:
+ void SetUp() override {
+ eArc = IEArc::fromBinder(SpAIBinder(AServiceManager_waitForService(GetParam().c_str())));
+ ASSERT_NE(eArc, nullptr);
+ ALOGI("%s: getService() for eArc is %s", __func__, eArc->isRemote() ? "remote" : "local");
+
+ eArcCallback = ::ndk::SharedRefBase::make<EArcCallback>();
+ ASSERT_NE(eArcCallback, nullptr);
+ eArcDeathRecipient =
+ ndk::ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient_new(&serviceDied));
+ ASSERT_EQ(AIBinder_linkToDeath(eArc->asBinder().get(), eArcDeathRecipient.get(), 0),
+ STATUS_OK);
+ }
+
+ class EArcCallback : public BnEArcCallback {
+ public:
+ ::ndk::ScopedAStatus onStateChange(IEArcStatus connected __unused,
+ int32_t portId __unused) {
+ return ::ndk::ScopedAStatus::ok();
+ };
+ ::ndk::ScopedAStatus onCapabilitiesReported(
+ const std::vector<uint8_t>& capabilities __unused, int32_t portId __unused) {
+ return ::ndk::ScopedAStatus::ok();
+ };
+ };
+
+ std::shared_ptr<IEArc> eArc;
+ std::shared_ptr<IEArcCallback> eArcCallback;
+ ::ndk::ScopedAIBinder_DeathRecipient eArcDeathRecipient;
+};
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EArcTest);
+INSTANTIATE_TEST_SUITE_P(PerInstance, EArcTest,
+ testing::ValuesIn(android::getAidlHalInstanceNames(IEArc::descriptor)),
+ android::PrintInstanceNameToString);
+
+TEST_P(EArcTest, setGetEArcEnabled) {
+ bool initial_state;
+ bool changed_state;
+ ASSERT_TRUE(eArc->isEArcEnabled(&initial_state).isOk());
+ ASSERT_TRUE(eArc->setEArcEnabled(!initial_state).isOk());
+ ASSERT_TRUE(eArc->isEArcEnabled(&changed_state).isOk());
+ ASSERT_TRUE(initial_state != changed_state);
+ ASSERT_TRUE(eArc->setEArcEnabled(initial_state).isOk());
+}
+
+TEST_P(EArcTest, SetCallback) {
+ ASSERT_TRUE(eArc->setCallback(eArcCallback).isOk());
+}
+
+TEST_P(EArcTest, GetState) {
+ IEArcStatus connectionStatus;
+ ASSERT_TRUE(eArc->getState(1, &connectionStatus).isOk());
+}
+
+TEST_P(EArcTest, GetLastReportedAudioCapabilities) {
+ std::vector<uint8_t> capabilities;
+ ASSERT_TRUE(eArc->getLastReportedAudioCapabilities(1, &capabilities).isOk());
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LocationResponseType.aidl b/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/HpdSignal.aidl
similarity index 87%
copy from radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LocationResponseType.aidl
copy to tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/HpdSignal.aidl
index e89a40f..eef4025 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LocationResponseType.aidl
+++ b/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/HpdSignal.aidl
@@ -31,10 +31,9 @@
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
-package android.hardware.radio.network;
-@Backing(type="int") @JavaDerive(toString=true) @VintfStability
-enum LocationResponseType {
- REJECTED = 0,
- ACCEPTED_NO_LOCATION_PROVIDED = 1,
- ACCEPTED_LOCATION_PROVIDED = 2,
+package android.hardware.tv.hdmi;
+@Backing(type="byte") @VintfStability
+enum HpdSignal {
+ HDMI_HPD_PHYSICAL = 0,
+ HDMI_HPD_STATUS_BIT = 1,
}
diff --git a/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/IHdmi.aidl b/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/IHdmi.aidl
index 3fc7f41..809d392 100644
--- a/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/IHdmi.aidl
+++ b/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/IHdmi.aidl
@@ -37,4 +37,6 @@
android.hardware.tv.hdmi.HdmiPortInfo[] getPortInfo();
boolean isConnected(in int portId);
void setCallback(in android.hardware.tv.hdmi.IHdmiCallback callback);
+ void setHpdSignal(android.hardware.tv.hdmi.HpdSignal signal);
+ android.hardware.tv.hdmi.HpdSignal getHpdSignal();
}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LocationResponseType.aidl b/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/Result.aidl
similarity index 87%
copy from radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LocationResponseType.aidl
copy to tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/Result.aidl
index e89a40f..b6b0eb3 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/LocationResponseType.aidl
+++ b/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/Result.aidl
@@ -31,10 +31,12 @@
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
-package android.hardware.radio.network;
-@Backing(type="int") @JavaDerive(toString=true) @VintfStability
-enum LocationResponseType {
- REJECTED = 0,
- ACCEPTED_NO_LOCATION_PROVIDED = 1,
- ACCEPTED_LOCATION_PROVIDED = 2,
+package android.hardware.tv.hdmi;
+@VintfStability
+enum Result {
+ SUCCESS = 0,
+ FAILURE_UNKNOWN = 1,
+ FAILURE_INVALID_ARGS = 2,
+ FAILURE_INVALID_STATE = 3,
+ FAILURE_NOT_SUPPORTED = 4,
}
diff --git a/tv/hdmi/aidl/android/hardware/tv/hdmi/HpdSignal.aidl b/tv/hdmi/aidl/android/hardware/tv/hdmi/HpdSignal.aidl
new file mode 100644
index 0000000..05963f2
--- /dev/null
+++ b/tv/hdmi/aidl/android/hardware/tv/hdmi/HpdSignal.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tv.hdmi;
+
+/**
+ * HPD (Hotplug Detection) Signal Types
+ */
+@VintfStability
+@Backing(type="byte")
+enum HpdSignal {
+ HDMI_HPD_PHYSICAL = 0,
+ HDMI_HPD_STATUS_BIT = 1,
+}
diff --git a/tv/hdmi/aidl/android/hardware/tv/hdmi/IHdmi.aidl b/tv/hdmi/aidl/android/hardware/tv/hdmi/IHdmi.aidl
index 5536846..457234d 100644
--- a/tv/hdmi/aidl/android/hardware/tv/hdmi/IHdmi.aidl
+++ b/tv/hdmi/aidl/android/hardware/tv/hdmi/IHdmi.aidl
@@ -17,6 +17,7 @@
package android.hardware.tv.hdmi;
import android.hardware.tv.hdmi.HdmiPortInfo;
+import android.hardware.tv.hdmi.HpdSignal;
import android.hardware.tv.hdmi.IHdmiCallback;
/**
@@ -48,4 +49,17 @@
* setCallback(null) should deregister the callback.
*/
void setCallback(in IHdmiCallback callback);
+
+ /**
+ * Method to set the HPD (Hot Plug Detection) signal the HAL should use for HPD signaling (e.g.
+ * signaling EDID updates). By default, the HAL will use {@code HDMI_HPD_PHYSICAL} (the physical
+ * hotplug signal). When set to {@code HDMI_HPD_STATUS_BIT} the HAL should use the HDP status
+ * bit.
+ */
+ void setHpdSignal(HpdSignal signal);
+
+ /**
+ * Get the current signal the HAL is using for HPD
+ */
+ HpdSignal getHpdSignal();
}
diff --git a/tv/hdmi/aidl/android/hardware/tv/hdmi/Result.aidl b/tv/hdmi/aidl/android/hardware/tv/hdmi/Result.aidl
new file mode 100644
index 0000000..d2a1fef
--- /dev/null
+++ b/tv/hdmi/aidl/android/hardware/tv/hdmi/Result.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tv.hdmi;
+
+/**
+ * Result enum for return values. Used by the HDMI related AIDL.
+ */
+@VintfStability
+enum Result {
+ /**
+ * The HPD Signal type was set successfully.
+ */
+ SUCCESS = 0,
+
+ /**
+ * The HPD Signal type could not be set because of an unknown failure.
+ */
+ FAILURE_UNKNOWN = 1,
+
+ /**
+ * The HPD Signal type could not be set because the arguments were invalid.
+ */
+ FAILURE_INVALID_ARGS = 2,
+
+ /**
+ * The HPD Signal type could not be set because the HAL is in an invalid state.
+ */
+ FAILURE_INVALID_STATE = 3,
+
+ /**
+ * The HPD Signal type could not be set as the signal type is not supported.
+ */
+ FAILURE_NOT_SUPPORTED = 4,
+}
diff --git a/tv/hdmi/aidl/default/HdmiMock.cpp b/tv/hdmi/aidl/default/HdmiMock.cpp
index bbc4705..7cd9bb7 100644
--- a/tv/hdmi/aidl/default/HdmiMock.cpp
+++ b/tv/hdmi/aidl/default/HdmiMock.cpp
@@ -67,6 +67,21 @@
return ScopedAStatus::ok();
}
+ScopedAStatus HdmiMock::setHpdSignal(HpdSignal signal) {
+ if (mHdmiThreadRun) {
+ mHpdSignal = signal;
+ return ScopedAStatus::ok();
+ } else {
+ return ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(Result::FAILURE_INVALID_STATE));
+ }
+}
+
+ScopedAStatus HdmiMock::getHpdSignal(HpdSignal* _aidl_return) {
+ *_aidl_return = mHpdSignal;
+ return ScopedAStatus::ok();
+}
+
void* HdmiMock::__threadLoop(void* user) {
HdmiMock* const self = static_cast<HdmiMock*>(user);
self->threadLoop();
diff --git a/tv/hdmi/aidl/default/HdmiMock.h b/tv/hdmi/aidl/default/HdmiMock.h
index 05795dd..51abaff 100644
--- a/tv/hdmi/aidl/default/HdmiMock.h
+++ b/tv/hdmi/aidl/default/HdmiMock.h
@@ -15,6 +15,7 @@
*/
#include <aidl/android/hardware/tv/hdmi/BnHdmi.h>
+#include <aidl/android/hardware/tv/hdmi/Result.h>
#include <algorithm>
#include <vector>
@@ -29,8 +30,10 @@
using ::aidl::android::hardware::tv::hdmi::BnHdmi;
using ::aidl::android::hardware::tv::hdmi::HdmiPortInfo;
using ::aidl::android::hardware::tv::hdmi::HdmiPortType;
+using ::aidl::android::hardware::tv::hdmi::HpdSignal;
using ::aidl::android::hardware::tv::hdmi::IHdmi;
using ::aidl::android::hardware::tv::hdmi::IHdmiCallback;
+using ::aidl::android::hardware::tv::hdmi::Result;
#define HDMI_MSG_IN_FIFO "/dev/hdmi_in_pipe"
#define MESSAGE_BODY_MAX_LENGTH 4
@@ -41,6 +44,8 @@
::ndk::ScopedAStatus getPortInfo(std::vector<HdmiPortInfo>* _aidl_return) override;
::ndk::ScopedAStatus isConnected(int32_t portId, bool* _aidl_return) override;
::ndk::ScopedAStatus setCallback(const std::shared_ptr<IHdmiCallback>& callback) override;
+ ::ndk::ScopedAStatus setHpdSignal(HpdSignal signal) override;
+ ::ndk::ScopedAStatus getHpdSignal(HpdSignal* _aidl_return) override;
void printEventBuf(const char* msg_buf, int len);
@@ -62,6 +67,9 @@
uint16_t mPhysicalAddress = 0xFFFF;
int mTotalPorts = 1;
+ // HPD Signal being used
+ HpdSignal mHpdSignal = HpdSignal::HDMI_HPD_PHYSICAL;
+
// Testing variables
// Input file descriptor
int mInputFile;
diff --git a/tv/hdmi/aidl/vts/functional/VtsHalTvHdmiAidlTargetTest.cpp b/tv/hdmi/aidl/vts/functional/VtsHalTvHdmiAidlTargetTest.cpp
index 78c2590..fd4d94f 100644
--- a/tv/hdmi/aidl/vts/functional/VtsHalTvHdmiAidlTargetTest.cpp
+++ b/tv/hdmi/aidl/vts/functional/VtsHalTvHdmiAidlTargetTest.cpp
@@ -31,6 +31,7 @@
using ::aidl::android::hardware::tv::hdmi::BnHdmiCallback;
using ::aidl::android::hardware::tv::hdmi::HdmiPortInfo;
using ::aidl::android::hardware::tv::hdmi::HdmiPortType;
+using ::aidl::android::hardware::tv::hdmi::HpdSignal;
using ::aidl::android::hardware::tv::hdmi::IHdmi;
using ::aidl::android::hardware::tv::hdmi::IHdmiCallback;
using ::ndk::SpAIBinder;
@@ -101,3 +102,18 @@
ASSERT_TRUE(hdmi->isConnected(ports[i].portId, &connected).isOk());
}
}
+
+TEST_P(HdmiTest, HdpSignal) {
+ HpdSignal originalSignal;
+ HpdSignal signal = HpdSignal::HDMI_HPD_STATUS_BIT;
+ HpdSignal readSignal;
+ ASSERT_TRUE(hdmi->getHpdSignal(&originalSignal).isOk());
+ ASSERT_TRUE(hdmi->setHpdSignal(signal).isOk());
+ ASSERT_TRUE(hdmi->getHpdSignal(&readSignal).isOk());
+ EXPECT_EQ(readSignal, signal);
+ signal = HpdSignal::HDMI_HPD_PHYSICAL;
+ ASSERT_TRUE(hdmi->setHpdSignal(signal).isOk());
+ ASSERT_TRUE(hdmi->getHpdSignal(&readSignal).isOk());
+ EXPECT_EQ(readSignal, signal);
+ ASSERT_TRUE(hdmi->setHpdSignal(originalSignal).isOk());
+}
diff --git a/tv/tuner/aidl/default/Frontend.cpp b/tv/tuner/aidl/default/Frontend.cpp
index 0573d08..997d9de 100644
--- a/tv/tuner/aidl/default/Frontend.cpp
+++ b/tv/tuner/aidl/default/Frontend.cpp
@@ -182,7 +182,9 @@
// Reset callback
mCallback = nullptr;
mIsLocked = false;
- mTuner->removeFrontend(mId);
+ if (mTuner != nullptr) {
+ mTuner->removeFrontend(mId);
+ }
mTuner = nullptr;
return ::ndk::ScopedAStatus::ok();
diff --git a/usb/1.0/default/OWNERS b/usb/1.0/default/OWNERS
deleted file mode 100644
index fefae56..0000000
--- a/usb/1.0/default/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-badhri@google.com
diff --git a/usb/1.0/vts/OWNERS b/usb/1.0/vts/OWNERS
deleted file mode 100644
index 54f268f..0000000
--- a/usb/1.0/vts/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-badhri@google.com
-yim@google.com
-trong@google.com
diff --git a/usb/1.1/vts/OWNERS b/usb/1.1/vts/OWNERS
deleted file mode 100644
index 54f268f..0000000
--- a/usb/1.1/vts/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-badhri@google.com
-yim@google.com
-trong@google.com
diff --git a/usb/1.2/vts/OWNERS b/usb/1.2/vts/OWNERS
deleted file mode 100644
index f60d39a..0000000
--- a/usb/1.2/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-badhri@google.com
-yim@google.com
diff --git a/usb/1.3/vts/OWNERS b/usb/OWNERS
similarity index 62%
rename from usb/1.3/vts/OWNERS
rename to usb/OWNERS
index a6a1e54..2b1d34d 100644
--- a/usb/1.3/vts/OWNERS
+++ b/usb/OWNERS
@@ -1,2 +1,4 @@
+# Bug component: 175220
+
albertccwang@google.com
badhri@google.com
diff --git a/usb/aidl/OWNERS b/usb/aidl/OWNERS
deleted file mode 100644
index fefae56..0000000
--- a/usb/aidl/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-badhri@google.com
diff --git a/usb/aidl/vts/VtsAidlUsbTargetTest.cpp b/usb/aidl/vts/VtsAidlUsbTargetTest.cpp
index d87f1f4..aec9954 100644
--- a/usb/aidl/vts/VtsAidlUsbTargetTest.cpp
+++ b/usb/aidl/vts/VtsAidlUsbTargetTest.cpp
@@ -307,7 +307,7 @@
}
}
}
- EXPECT_LE(1, disabledCount);
+ EXPECT_GE(1, disabledCount);
ALOGI("UsbAidlTest DataStatusCheck end");
}
diff --git a/vibrator/1.0/vts/OWNERS b/vibrator/1.0/vts/OWNERS
deleted file mode 100644
index 75b9a4b..0000000
--- a/vibrator/1.0/vts/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 345036
-michaelwr@google.com
-leungv@google.com
diff --git a/vibrator/1.1/vts/OWNERS b/vibrator/1.1/vts/OWNERS
deleted file mode 100644
index 44bfe56..0000000
--- a/vibrator/1.1/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 345036
-include ../../1.0/vts/OWNERS
diff --git a/vibrator/1.2/vts/OWNERS b/vibrator/1.2/vts/OWNERS
deleted file mode 100644
index 44bfe56..0000000
--- a/vibrator/1.2/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 345036
-include ../../1.0/vts/OWNERS
diff --git a/vibrator/1.3/example/OWNERS b/vibrator/1.3/example/OWNERS
deleted file mode 100644
index 4b34968..0000000
--- a/vibrator/1.3/example/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-eliptus@google.com
-michaelwr@google.com
diff --git a/vibrator/1.3/vts/OWNERS b/vibrator/1.3/vts/OWNERS
deleted file mode 100644
index 44bfe56..0000000
--- a/vibrator/1.3/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 345036
-include ../../1.0/vts/OWNERS
diff --git a/vibrator/aidl/OWNERS b/vibrator/OWNERS
similarity index 68%
rename from vibrator/aidl/OWNERS
rename to vibrator/OWNERS
index 3982c7b..05e2e73 100644
--- a/vibrator/aidl/OWNERS
+++ b/vibrator/OWNERS
@@ -1,4 +1,9 @@
# Bug component: 345036
+
include platform/frameworks/base:/services/core/java/com/android/server/vibrator/OWNERS
+
chasewu@google.com
+chrispaulo@google.com
+michaelwr@google.com
+nathankulczak@google.com
taikuo@google.com
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiChip.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiChip.aidl
index f800e8f..2ebe145 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiChip.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiChip.aidl
@@ -80,24 +80,25 @@
void startLoggingToDebugRingBuffer(in String ringName, in android.hardware.wifi.WifiDebugRingBufferVerboseLevel verboseLevel, in int maxIntervalInSec, in int minDataSizeInBytes);
void stopLoggingToDebugRingBuffer();
void triggerSubsystemRestart();
- const int NO_POWER_CAP_CONSTANT = 2147483647;
+ void enableStaChannelForPeerNetwork(in android.hardware.wifi.IWifiChip.ChannelCategoryMask channelCategoryEnableFlag);
+ const int NO_POWER_CAP_CONSTANT = 0x7FFFFFFF;
@Backing(type="int") @VintfStability
enum ChipCapabilityMask {
- DEBUG_MEMORY_FIRMWARE_DUMP = 1,
- DEBUG_MEMORY_DRIVER_DUMP = 2,
- DEBUG_RING_BUFFER_CONNECT_EVENT = 4,
- DEBUG_RING_BUFFER_POWER_EVENT = 8,
- DEBUG_RING_BUFFER_WAKELOCK_EVENT = 16,
- DEBUG_RING_BUFFER_VENDOR_DATA = 32,
- DEBUG_HOST_WAKE_REASON_STATS = 64,
- DEBUG_ERROR_ALERTS = 128,
- SET_TX_POWER_LIMIT = 256,
- D2D_RTT = 512,
- D2AP_RTT = 1024,
- USE_BODY_HEAD_SAR = 2048,
- SET_LATENCY_MODE = 4096,
- P2P_RAND_MAC = 8192,
- WIGIG = 16384,
+ DEBUG_MEMORY_FIRMWARE_DUMP = (1 << 0),
+ DEBUG_MEMORY_DRIVER_DUMP = (1 << 1),
+ DEBUG_RING_BUFFER_CONNECT_EVENT = (1 << 2),
+ DEBUG_RING_BUFFER_POWER_EVENT = (1 << 3),
+ DEBUG_RING_BUFFER_WAKELOCK_EVENT = (1 << 4),
+ DEBUG_RING_BUFFER_VENDOR_DATA = (1 << 5),
+ DEBUG_HOST_WAKE_REASON_STATS = (1 << 6),
+ DEBUG_ERROR_ALERTS = (1 << 7),
+ SET_TX_POWER_LIMIT = (1 << 8),
+ D2D_RTT = (1 << 9),
+ D2AP_RTT = (1 << 10),
+ USE_BODY_HEAD_SAR = (1 << 11),
+ SET_LATENCY_MODE = (1 << 12),
+ P2P_RAND_MAC = (1 << 13),
+ WIGIG = (1 << 14),
}
@VintfStability
parcelable ChipConcurrencyCombinationLimit {
@@ -129,9 +130,9 @@
}
@Backing(type="int") @VintfStability
enum CoexRestriction {
- WIFI_DIRECT = 1,
- SOFTAP = 2,
- WIFI_AWARE = 4,
+ WIFI_DIRECT = (1 << 0),
+ SOFTAP = (1 << 1),
+ WIFI_AWARE = (1 << 2),
}
@VintfStability
parcelable CoexUnsafeChannel {
@@ -159,8 +160,13 @@
}
@Backing(type="int") @VintfStability
enum UsableChannelFilter {
- CELLULAR_COEXISTENCE = 1,
- CONCURRENCY = 2,
- NAN_INSTANT_MODE = 4,
+ CELLULAR_COEXISTENCE = (1 << 0),
+ CONCURRENCY = (1 << 1),
+ NAN_INSTANT_MODE = (1 << 2),
+ }
+ @Backing(type="int") @VintfStability
+ enum ChannelCategoryMask {
+ INDOOR_CHANNEL = (1 << 0),
+ DFS_CHANNEL = (1 << 1),
}
}
diff --git a/wifi/aidl/android/hardware/wifi/IWifiChip.aidl b/wifi/aidl/android/hardware/wifi/IWifiChip.aidl
index 64692af..5ffea56 100644
--- a/wifi/aidl/android/hardware/wifi/IWifiChip.aidl
+++ b/wifi/aidl/android/hardware/wifi/IWifiChip.aidl
@@ -1106,4 +1106,29 @@
* |WifiStatusCode.ERROR_UNKNOWN|
*/
void triggerSubsystemRestart();
+
+ /**
+ * Channel category mask.
+ */
+ @VintfStability
+ @Backing(type="int")
+ enum ChannelCategoryMask {
+ INDOOR_CHANNEL = 1 << 0,
+ DFS_CHANNEL = 1 << 1,
+ }
+
+ /**
+ * API to enable or disable the feature of allowing current STA-connected channel for WFA GO,
+ * SAP and Aware when the regulatory allows.
+ * If the channel category is enabled and allowed by the regulatory, the HAL method
+ * getUsableChannels() will contain the current STA-connected channel if that channel belongs
+ * to that category.
+ * @param channelCategoryEnableFlag bitmask of |ChannelCategoryMask|.
+ * For each bit, 1 enables the channel category and 0 disables that channel category.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.FAILURE_UNKNOWN|
+ */
+ void enableStaChannelForPeerNetwork(in ChannelCategoryMask channelCategoryEnableFlag);
}
diff --git a/wifi/aidl/default/aidl_struct_util.cpp b/wifi/aidl/default/aidl_struct_util.cpp
index 6869ac3..ba7d2db 100644
--- a/wifi/aidl/default/aidl_struct_util.cpp
+++ b/wifi/aidl/default/aidl_struct_util.cpp
@@ -3314,6 +3314,19 @@
return true;
}
+uint32_t convertAidlChannelCategoryToLegacy(uint32_t aidl_channel_category_mask) {
+ uint32_t channel_category_mask = 0;
+ if (aidl_channel_category_mask &
+ static_cast<int32_t>(IWifiChip::ChannelCategoryMask::INDOOR_CHANNEL)) {
+ channel_category_mask |= legacy_hal::WIFI_INDOOR_CHANNEL;
+ }
+ if (aidl_channel_category_mask &
+ static_cast<int32_t>(IWifiChip::ChannelCategoryMask::DFS_CHANNEL)) {
+ channel_category_mask |= legacy_hal::WIFI_DFS_CHANNEL;
+ }
+ return channel_category_mask;
+}
+
} // namespace aidl_struct_util
} // namespace wifi
} // namespace hardware
diff --git a/wifi/aidl/default/aidl_struct_util.h b/wifi/aidl/default/aidl_struct_util.h
index e478fed..6407d32 100644
--- a/wifi/aidl/default/aidl_struct_util.h
+++ b/wifi/aidl/default/aidl_struct_util.h
@@ -200,6 +200,7 @@
bool convertLegacyNanBootstrappingConfirmIndToAidl(
const legacy_hal::NanBootstrappingConfirmInd& legacy_ind,
NanBootstrappingConfirmInd* aidl_ind);
+uint32_t convertAidlChannelCategoryToLegacy(uint32_t aidl_channel_category_mask);
} // namespace aidl_struct_util
} // namespace wifi
} // namespace hardware
diff --git a/wifi/aidl/default/wifi_chip.cpp b/wifi/aidl/default/wifi_chip.cpp
index 4061699..5597001 100644
--- a/wifi/aidl/default/wifi_chip.cpp
+++ b/wifi/aidl/default/wifi_chip.cpp
@@ -34,6 +34,7 @@
using aidl::android::hardware::wifi::IfaceType;
using aidl::android::hardware::wifi::IWifiChip;
using CoexRestriction = aidl::android::hardware::wifi::IWifiChip::CoexRestriction;
+using ChannelCategoryMask = aidl::android::hardware::wifi::IWifiChip::ChannelCategoryMask;
using android::base::unique_fd;
constexpr char kCpioMagic[] = "070701";
@@ -685,6 +686,13 @@
&WifiChip::getWifiChipCapabilitiesInternal, _aidl_return);
}
+ndk::ScopedAStatus WifiChip::enableStaChannelForPeerNetwork(
+ ChannelCategoryMask in_channelCategoryEnableFlag) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::enableStaChannelForPeerNetworkInternal,
+ in_channelCategoryEnableFlag);
+}
+
void WifiChip::invalidateAndRemoveAllIfaces() {
invalidateAndClearBridgedApAll();
invalidateAndClearAll(ap_ifaces_);
@@ -1428,6 +1436,14 @@
return {aidl_chip_capabilities, ndk::ScopedAStatus::ok()};
}
+ndk::ScopedAStatus WifiChip::enableStaChannelForPeerNetworkInternal(
+ ChannelCategoryMask channelCategoryEnableFlag) {
+ auto legacy_status = legacy_hal_.lock()->enableStaChannelForPeerNetwork(
+ aidl_struct_util::convertAidlChannelCategoryToLegacy(
+ static_cast<uint32_t>(channelCategoryEnableFlag)));
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
ndk::ScopedAStatus WifiChip::triggerSubsystemRestartInternal() {
auto legacy_status = legacy_hal_.lock()->triggerSubsystemRestart();
return createWifiStatusFromLegacyError(legacy_status);
diff --git a/wifi/aidl/default/wifi_chip.h b/wifi/aidl/default/wifi_chip.h
index 7b04e85..c69c7fe 100644
--- a/wifi/aidl/default/wifi_chip.h
+++ b/wifi/aidl/default/wifi_chip.h
@@ -145,6 +145,8 @@
ndk::ScopedAStatus getSupportedRadioCombinationsMatrix(
WifiRadioCombinationMatrix* _aidl_return) override;
ndk::ScopedAStatus getWifiChipCapabilities(WifiChipCapabilities* _aidl_return) override;
+ ndk::ScopedAStatus enableStaChannelForPeerNetwork(
+ ChannelCategoryMask in_channelCategoryEnableFlag) override;
binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
private:
@@ -214,6 +216,8 @@
ndk::ScopedAStatus setCountryCodeInternal(const std::array<uint8_t, 2>& in_code);
std::pair<std::vector<WifiUsableChannel>, ndk::ScopedAStatus> getUsableChannelsInternal(
WifiBand band, WifiIfaceMode ifaceModeMask, UsableChannelFilter filterMask);
+ ndk::ScopedAStatus enableStaChannelForPeerNetworkInternal(
+ ChannelCategoryMask channelCategoryEnableFlag);
ndk::ScopedAStatus handleChipConfiguration(std::unique_lock<std::recursive_mutex>* lock,
int32_t mode_id);
ndk::ScopedAStatus registerDebugRingBufferCallback();
diff --git a/wifi/aidl/default/wifi_legacy_hal.cpp b/wifi/aidl/default/wifi_legacy_hal.cpp
index 54e91d4..f03835f 100644
--- a/wifi/aidl/default/wifi_legacy_hal.cpp
+++ b/wifi/aidl/default/wifi_legacy_hal.cpp
@@ -1835,6 +1835,11 @@
return {status, chip_capabilities};
}
+wifi_error WifiLegacyHal::enableStaChannelForPeerNetwork(uint32_t channelCategoryEnableFlag) {
+ return global_func_table_.wifi_enable_sta_channel_for_peer_network(global_handle_,
+ channelCategoryEnableFlag);
+}
+
void WifiLegacyHal::invalidate() {
global_handle_ = nullptr;
iface_name_to_handle_.clear();
diff --git a/wifi/aidl/default/wifi_legacy_hal.h b/wifi/aidl/default/wifi_legacy_hal.h
index 5620280..2300cb7 100644
--- a/wifi/aidl/default/wifi_legacy_hal.h
+++ b/wifi/aidl/default/wifi_legacy_hal.h
@@ -256,12 +256,14 @@
using ::WIFI_CHAN_WIDTH_80;
using ::WIFI_CHAN_WIDTH_80P80;
using ::WIFI_CHAN_WIDTH_INVALID;
+using ::wifi_channel_category;
using ::wifi_channel_info;
using ::wifi_channel_stat;
using ::wifi_channel_width;
using ::wifi_chip_capabilities;
using ::wifi_coex_restriction;
using ::wifi_coex_unsafe_channel;
+using ::WIFI_DFS_CHANNEL;
using ::WIFI_DUAL_STA_NON_TRANSIENT_UNBIASED;
using ::WIFI_DUAL_STA_TRANSIENT_PREFER_PRIMARY;
using ::wifi_error;
@@ -278,6 +280,7 @@
using ::WIFI_ERROR_UNKNOWN;
using ::wifi_gscan_capabilities;
using ::wifi_hal_fn;
+using ::WIFI_INDOOR_CHANNEL;
using ::wifi_information_element;
using ::WIFI_INTERFACE_IBSS;
using ::WIFI_INTERFACE_MESH;
@@ -755,6 +758,7 @@
wifi_error getWifiCachedScanResults(const std::string& iface_name,
const CachedScanResultsCallbackHandlers& handler);
std::pair<wifi_error, wifi_chip_capabilities> getWifiChipCapabilities();
+ wifi_error enableStaChannelForPeerNetwork(uint32_t channelCategoryEnableFlag);
private:
// Retrieve interface handles for all the available interfaces.
diff --git a/wifi/aidl/default/wifi_legacy_hal_stubs.cpp b/wifi/aidl/default/wifi_legacy_hal_stubs.cpp
index a0cb2c0..11da373 100644
--- a/wifi/aidl/default/wifi_legacy_hal_stubs.cpp
+++ b/wifi/aidl/default/wifi_legacy_hal_stubs.cpp
@@ -172,6 +172,7 @@
populateStubFor(&hal_fn->wifi_enable_tx_power_limits);
populateStubFor(&hal_fn->wifi_get_cached_scan_results);
populateStubFor(&hal_fn->wifi_get_chip_capabilities);
+ populateStubFor(&hal_fn->wifi_enable_sta_channel_for_peer_network);
return true;
}