Merge "wifi: Send channel change event to framework"
diff --git a/audio/aidl/Android.bp b/audio/aidl/Android.bp
index 691cf34..6b948dd 100644
--- a/audio/aidl/Android.bp
+++ b/audio/aidl/Android.bp
@@ -41,6 +41,7 @@
"android/hardware/audio/common/SinkMetadata.aidl",
"android/hardware/audio/common/SourceMetadata.aidl",
],
+ frozen: true,
imports: [
"android.media.audio.common.types-V2",
],
@@ -177,6 +178,7 @@
"android/hardware/audio/effect/Descriptor.aidl",
"android/hardware/audio/effect/Downmix.aidl",
"android/hardware/audio/effect/DynamicsProcessing.aidl",
+ "android/hardware/audio/effect/EnvironmentalReverb.aidl",
"android/hardware/audio/effect/Equalizer.aidl",
"android/hardware/audio/effect/Flags.aidl",
"android/hardware/audio/effect/HapticGenerator.aidl",
@@ -184,8 +186,8 @@
"android/hardware/audio/effect/IFactory.aidl",
"android/hardware/audio/effect/LoudnessEnhancer.aidl",
"android/hardware/audio/effect/Parameter.aidl",
+ "android/hardware/audio/effect/PresetReverb.aidl",
"android/hardware/audio/effect/Processing.aidl",
- "android/hardware/audio/effect/Reverb.aidl",
"android/hardware/audio/effect/State.aidl",
"android/hardware/audio/effect/VendorExtension.aidl",
"android/hardware/audio/effect/Virtualizer.aidl",
diff --git a/audio/aidl/TEST_MAPPING b/audio/aidl/TEST_MAPPING
index 6473d23..484320f 100644
--- a/audio/aidl/TEST_MAPPING
+++ b/audio/aidl/TEST_MAPPING
@@ -2,6 +2,18 @@
"presubmit": [
{
"name": "VtsHalAudioCoreTargetTest"
+ },
+ {
+ "name": "VtsHalAudioEffectFactoryTargetTest"
+ },
+ {
+ "name": "VtsHalAudioEffectTargetTest"
+ },
+ {
+ "name": "VtsHalEqualizerTargetTest"
+ },
+ {
+ "name": "VtsHalLoudnessEnhancerTargetTest"
}
]
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IConfig.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IConfig.aidl
index 163b7a0..9ce45bb 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IConfig.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IConfig.aidl
@@ -35,4 +35,5 @@
@VintfStability
interface IConfig {
android.hardware.audio.core.SurroundSoundConfig getSurroundSoundConfig();
+ android.media.audio.common.AudioHalEngineConfig getEngineConfig();
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/BassBoost.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/BassBoost.aidl
index 979ebb8..09ad015 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/BassBoost.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/BassBoost.aidl
@@ -36,6 +36,8 @@
union BassBoost {
android.hardware.audio.effect.VendorExtension vendor;
int strengthPm;
+ const int MIN_PER_MILLE_STRENGTH = 0;
+ const int MAX_PER_MILLE_STRENGTH = 1000;
@VintfStability
union Id {
int vendorExtensionTag;
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Capability.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Capability.aidl
index 06f2bfe..60c88d3 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Capability.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Capability.aidl
@@ -38,10 +38,11 @@
android.hardware.audio.effect.BassBoost.Capability bassBoost;
android.hardware.audio.effect.Downmix.Capability downmix;
android.hardware.audio.effect.DynamicsProcessing.Capability dynamicsProcessing;
+ android.hardware.audio.effect.EnvironmentalReverb.Capability environmentalReverb;
android.hardware.audio.effect.Equalizer.Capability equalizer;
android.hardware.audio.effect.HapticGenerator.Capability hapticGenerator;
android.hardware.audio.effect.LoudnessEnhancer.Capability loudnessEnhancer;
- android.hardware.audio.effect.Reverb.Capability reverb;
+ android.hardware.audio.effect.PresetReverb.Capability presetReverb;
android.hardware.audio.effect.Virtualizer.Capability virtualizer;
android.hardware.audio.effect.Visualizer.Capability visualizer;
android.hardware.audio.effect.Volume.Capability volume;
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/EnvironmentalReverb.aidl
similarity index 95%
rename from audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
rename to audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/EnvironmentalReverb.aidl
index 8ad4848..fcf08c3 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/EnvironmentalReverb.aidl
@@ -33,7 +33,7 @@
package android.hardware.audio.effect;
@VintfStability
-union Reverb {
+union EnvironmentalReverb {
android.hardware.audio.effect.VendorExtension vendor;
int roomLevelMb;
int roomHfLevelMb;
@@ -47,7 +47,7 @@
@VintfStability
union Id {
int vendorExtensionTag;
- android.hardware.audio.effect.Reverb.Tag commonTag;
+ android.hardware.audio.effect.EnvironmentalReverb.Tag commonTag;
}
@VintfStability
parcelable Capability {
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/IFactory.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/IFactory.aidl
index 5b85d33..a6c138c 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/IFactory.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/IFactory.aidl
@@ -34,7 +34,7 @@
package android.hardware.audio.effect;
@VintfStability
interface IFactory {
- android.hardware.audio.effect.Descriptor.Identity[] queryEffects(in @nullable android.media.audio.common.AudioUuid type, in @nullable android.media.audio.common.AudioUuid implementation, in @nullable android.media.audio.common.AudioUuid proxy);
+ android.hardware.audio.effect.Descriptor[] queryEffects(in @nullable android.media.audio.common.AudioUuid type, in @nullable android.media.audio.common.AudioUuid implementation, in @nullable android.media.audio.common.AudioUuid proxy);
android.hardware.audio.effect.Processing[] queryProcessing(in @nullable android.hardware.audio.effect.Processing.Type type);
android.hardware.audio.effect.IEffect createEffect(in android.media.audio.common.AudioUuid implUuid);
void destroyEffect(in android.hardware.audio.effect.IEffect handle);
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Parameter.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Parameter.aidl
index 321c286..0635c13 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Parameter.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Parameter.aidl
@@ -46,10 +46,11 @@
android.hardware.audio.effect.BassBoost.Id bassBoostTag;
android.hardware.audio.effect.Downmix.Id downmixTag;
android.hardware.audio.effect.DynamicsProcessing.Id dynamicsProcessingTag;
+ android.hardware.audio.effect.EnvironmentalReverb.Id environmentalReverbTag;
android.hardware.audio.effect.Equalizer.Id equalizerTag;
android.hardware.audio.effect.HapticGenerator.Id hapticGeneratorTag;
android.hardware.audio.effect.LoudnessEnhancer.Id loudnessEnhancerTag;
- android.hardware.audio.effect.Reverb.Id reverbTag;
+ android.hardware.audio.effect.PresetReverb.Id presetReverbTag;
android.hardware.audio.effect.Virtualizer.Id virtualizerTag;
android.hardware.audio.effect.Visualizer.Id visualizerTag;
android.hardware.audio.effect.Volume.Id volumeTag;
@@ -73,10 +74,11 @@
android.hardware.audio.effect.BassBoost bassBoost;
android.hardware.audio.effect.Downmix downmix;
android.hardware.audio.effect.DynamicsProcessing dynamicsProcessing;
+ android.hardware.audio.effect.EnvironmentalReverb environmentalReverb;
android.hardware.audio.effect.Equalizer equalizer;
- android.hardware.audio.effect.LoudnessEnhancer loudnessEnhancer;
android.hardware.audio.effect.HapticGenerator hapticGenerator;
- android.hardware.audio.effect.Reverb reverb;
+ android.hardware.audio.effect.LoudnessEnhancer loudnessEnhancer;
+ android.hardware.audio.effect.PresetReverb presetReverb;
android.hardware.audio.effect.Virtualizer virtualizer;
android.hardware.audio.effect.Visualizer visualizer;
android.hardware.audio.effect.Volume volume;
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/PresetReverb.aidl
similarity index 83%
copy from audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
copy to audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/PresetReverb.aidl
index 8ad4848..24a9ce1 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/PresetReverb.aidl
@@ -33,25 +33,27 @@
package android.hardware.audio.effect;
@VintfStability
-union Reverb {
+union PresetReverb {
android.hardware.audio.effect.VendorExtension vendor;
- int roomLevelMb;
- int roomHfLevelMb;
- int decayTimeMs;
- int decayHfRatioPm;
- int levelMb;
- int delayMs;
- int diffusionPm;
- int densityPm;
- boolean bypass;
+ 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,
+ }
@VintfStability
union Id {
int vendorExtensionTag;
- android.hardware.audio.effect.Reverb.Tag commonTag;
+ android.hardware.audio.effect.PresetReverb.Tag commonTag;
}
@VintfStability
parcelable Capability {
android.hardware.audio.effect.VendorExtension extension;
- int maxDecayTimeMs;
+ android.hardware.audio.effect.PresetReverb.Presets[] supportedPresets;
}
}
diff --git a/audio/aidl/android/hardware/audio/core/IConfig.aidl b/audio/aidl/android/hardware/audio/core/IConfig.aidl
index c8ba6be..094d233 100644
--- a/audio/aidl/android/hardware/audio/core/IConfig.aidl
+++ b/audio/aidl/android/hardware/audio/core/IConfig.aidl
@@ -17,6 +17,7 @@
package android.hardware.audio.core;
import android.hardware.audio.core.SurroundSoundConfig;
+import android.media.audio.common.AudioHalEngineConfig;
/**
* This interface provides system-wide configuration parameters for audio I/O
@@ -34,4 +35,19 @@
* @return The surround sound configuration
*/
SurroundSoundConfig getSurroundSoundConfig();
+ /**
+ * Returns the configuration items used to determine the audio policy engine
+ * flavor and initial configuration.
+ *
+ * Engine flavor is determined by presence of capSpecificConfig, which must
+ * only be present if the device uses the Configurable Audio Policy (CAP)
+ * engine. Clients normally use the default audio policy engine. The client
+ * will use the CAP engine only when capSpecificConfig has a non-null value.
+ *
+ * This method is expected to only be called during the initialization of
+ * the audio policy engine, and must always return the same result.
+ *
+ * @return The engine configuration
+ */
+ AudioHalEngineConfig getEngineConfig();
}
diff --git a/audio/aidl/android/hardware/audio/effect/BassBoost.aidl b/audio/aidl/android/hardware/audio/effect/BassBoost.aidl
index 810c188..9e5d8aa 100644
--- a/audio/aidl/android/hardware/audio/effect/BassBoost.aidl
+++ b/audio/aidl/android/hardware/audio/effect/BassBoost.aidl
@@ -59,6 +59,16 @@
}
/**
+ * Minimal possible per mille strength.
+ */
+ const int MIN_PER_MILLE_STRENGTH = 0;
+
+ /**
+ * Maximum possible per mille strength.
+ */
+ const int MAX_PER_MILLE_STRENGTH = 1000;
+
+ /**
* The per mille strength of the bass boost effect.
*
* If the implementation does not support per mille accuracy for setting the strength, it is
diff --git a/audio/aidl/android/hardware/audio/effect/Capability.aidl b/audio/aidl/android/hardware/audio/effect/Capability.aidl
index f741f33..4149783 100644
--- a/audio/aidl/android/hardware/audio/effect/Capability.aidl
+++ b/audio/aidl/android/hardware/audio/effect/Capability.aidl
@@ -19,10 +19,11 @@
import android.hardware.audio.effect.BassBoost;
import android.hardware.audio.effect.Downmix;
import android.hardware.audio.effect.DynamicsProcessing;
+import android.hardware.audio.effect.EnvironmentalReverb;
import android.hardware.audio.effect.Equalizer;
import android.hardware.audio.effect.HapticGenerator;
import android.hardware.audio.effect.LoudnessEnhancer;
-import android.hardware.audio.effect.Reverb;
+import android.hardware.audio.effect.PresetReverb;
import android.hardware.audio.effect.VendorExtension;
import android.hardware.audio.effect.Virtualizer;
import android.hardware.audio.effect.Visualizer;
@@ -51,10 +52,11 @@
BassBoost.Capability bassBoost;
Downmix.Capability downmix;
DynamicsProcessing.Capability dynamicsProcessing;
+ EnvironmentalReverb.Capability environmentalReverb;
Equalizer.Capability equalizer;
HapticGenerator.Capability hapticGenerator;
LoudnessEnhancer.Capability loudnessEnhancer;
- Reverb.Capability reverb;
+ PresetReverb.Capability presetReverb;
Virtualizer.Capability virtualizer;
Visualizer.Capability visualizer;
Volume.Capability volume;
diff --git a/audio/aidl/android/hardware/audio/effect/Reverb.aidl b/audio/aidl/android/hardware/audio/effect/EnvironmentalReverb.aidl
similarity index 82%
rename from audio/aidl/android/hardware/audio/effect/Reverb.aidl
rename to audio/aidl/android/hardware/audio/effect/EnvironmentalReverb.aidl
index f60c2ea..3df0d27 100644
--- a/audio/aidl/android/hardware/audio/effect/Reverb.aidl
+++ b/audio/aidl/android/hardware/audio/effect/EnvironmentalReverb.aidl
@@ -19,24 +19,26 @@
import android.hardware.audio.effect.VendorExtension;
/**
- * Reverb specific definitions.
+ * Environmental Reverb specific definitions.
*
- * All parameters defined in union Reverb must be gettable and settable. The capabilities defined in
- * Reverb.Capability can only acquired with IEffect.getDescriptor() and not settable.
+ * All parameters defined in union Environmental must be gettable and settable. The capabilities
+ * * defined in EnvironmentalReverb.Capability can only acquired with IEffect.getDescriptor() and
+ * not * settable.
*/
+
@VintfStability
-union Reverb {
+union EnvironmentalReverb {
/**
* Effect parameter tag to identify the parameters for getParameter().
*/
@VintfStability
union Id {
int vendorExtensionTag;
- Reverb.Tag commonTag;
+ EnvironmentalReverb.Tag commonTag;
}
/**
- * Vendor Reverb implementation definition for additional parameters.
+ * Vendor EnvironmentalReverb implementation definition for additional parameters.
*/
VendorExtension vendor;
diff --git a/audio/aidl/android/hardware/audio/effect/IFactory.aidl b/audio/aidl/android/hardware/audio/effect/IFactory.aidl
index 5943359..b80e6ac 100644
--- a/audio/aidl/android/hardware/audio/effect/IFactory.aidl
+++ b/audio/aidl/android/hardware/audio/effect/IFactory.aidl
@@ -31,8 +31,8 @@
@VintfStability
interface IFactory {
/**
- * Return a list of effect identities supported by this device, with the optional
- * filter by type and/or by instance UUID.
+ * Return a list of effect descriptors supported by this device, with the optional filter by
+ * type and/or by instance UUID.
*
* @param type UUID identifying the effect type.
* This is an optional parameter, pass in null if this parameter is not necessary; if non
@@ -43,9 +43,9 @@
* @param proxy Indicates the proxy UUID filter to query.
* This is an optional parameter, pass in null if this parameter is not necessary; if
* non null, used as a filter for effect proxy UUIDs.
- * @return List of effect identities supported and filtered by type/implementation UUID.
+ * @return List of effect Descriptors supported and filtered by type/implementation/proxy UUID.
*/
- Descriptor.Identity[] queryEffects(in @nullable AudioUuid type,
+ Descriptor[] queryEffects(in @nullable AudioUuid type,
in @nullable AudioUuid implementation, in @nullable AudioUuid proxy);
/**
diff --git a/audio/aidl/android/hardware/audio/effect/Parameter.aidl b/audio/aidl/android/hardware/audio/effect/Parameter.aidl
index e7d3d5e..d7a6a27 100644
--- a/audio/aidl/android/hardware/audio/effect/Parameter.aidl
+++ b/audio/aidl/android/hardware/audio/effect/Parameter.aidl
@@ -19,10 +19,11 @@
import android.hardware.audio.effect.BassBoost;
import android.hardware.audio.effect.Downmix;
import android.hardware.audio.effect.DynamicsProcessing;
+import android.hardware.audio.effect.EnvironmentalReverb;
import android.hardware.audio.effect.Equalizer;
import android.hardware.audio.effect.HapticGenerator;
import android.hardware.audio.effect.LoudnessEnhancer;
-import android.hardware.audio.effect.Reverb;
+import android.hardware.audio.effect.PresetReverb;
import android.hardware.audio.effect.VendorExtension;
import android.hardware.audio.effect.Virtualizer;
import android.hardware.audio.effect.Visualizer;
@@ -73,10 +74,11 @@
BassBoost.Id bassBoostTag;
Downmix.Id downmixTag;
DynamicsProcessing.Id dynamicsProcessingTag;
+ EnvironmentalReverb.Id environmentalReverbTag;
Equalizer.Id equalizerTag;
HapticGenerator.Id hapticGeneratorTag;
LoudnessEnhancer.Id loudnessEnhancerTag;
- Reverb.Id reverbTag;
+ PresetReverb.Id presetReverbTag;
Virtualizer.Id virtualizerTag;
Visualizer.Id visualizerTag;
Volume.Id volumeTag;
@@ -150,10 +152,11 @@
BassBoost bassBoost;
Downmix downmix;
DynamicsProcessing dynamicsProcessing;
+ EnvironmentalReverb environmentalReverb;
Equalizer equalizer;
- LoudnessEnhancer loudnessEnhancer;
HapticGenerator hapticGenerator;
- Reverb reverb;
+ LoudnessEnhancer loudnessEnhancer;
+ PresetReverb presetReverb;
Virtualizer virtualizer;
Visualizer visualizer;
Volume volume;
diff --git a/audio/aidl/android/hardware/audio/effect/PresetReverb.aidl b/audio/aidl/android/hardware/audio/effect/PresetReverb.aidl
new file mode 100644
index 0000000..6048eea
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/PresetReverb.aidl
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect;
+
+import android.hardware.audio.effect.VendorExtension;
+
+/**
+ * PresetReverb specific definitions.
+ *
+ * All parameters defined in union PresetReverb must be gettable and settable. The capabilities
+ * defined in PresetReverb.Capability can only acquired with IEffect.getDescriptor() and not
+ * settable.
+ */
+@VintfStability
+union PresetReverb {
+ /**
+ * Presets enum definition.
+ */
+ @VintfStability
+ @Backing(type="int")
+ enum Presets {
+ /**
+ * No reverb or reflections
+ */
+ NONE,
+ /**
+ * A small room less than five meters in length
+ */
+ SMALLROOM,
+ /**
+ * A medium room with a length of ten meters or less.
+ */
+ MEDIUMROOM,
+ /**
+ * A large-sized room suitable for live performances.
+ */
+ LARGEROOM,
+ /**
+ * A medium-sized hall.
+ */
+ MEDIUMHALL,
+ /**
+ * a large-sized hall suitable for a full orchestra.
+ */
+ LARGEHALL,
+ /**
+ * Synthesis of the traditional plate reverb.
+ */
+ PLATE,
+ }
+
+ /**
+ * Effect parameter tag to identify the parameters for getParameter().
+ */
+ @VintfStability
+ union Id {
+ int vendorExtensionTag;
+ PresetReverb.Tag commonTag;
+ }
+
+ /**
+ * Vendor PresetReverb implementation definition for additional parameters.
+ */
+ VendorExtension vendor;
+
+ /**
+ * Capability supported by effect implementation.
+ */
+ @VintfStability
+ parcelable Capability {
+ VendorExtension extension;
+
+ /**
+ * List of presets supported.
+ */
+ Presets[] supportedPresets;
+ }
+
+ /**
+ * Get current reverb preset when used in getParameter.
+ * Enable a preset reverb when used in setParameter.
+ */
+ Presets preset;
+}
diff --git a/audio/aidl/android/hardware/audio/effect/state.gv b/audio/aidl/android/hardware/audio/effect/state.gv
index e19e6c7..c88521e 100644
--- a/audio/aidl/android/hardware/audio/effect/state.gv
+++ b/audio/aidl/android/hardware/audio/effect/state.gv
@@ -16,21 +16,21 @@
// To render: "dot -Tpng state.gv -o state.png"
digraph effect_state_machine {
- node [shape=point style=filled fillcolor=black width=0.5] I;
- node [shape=doublecircle] F;
- node [shape=oval width=1];
- node [fillcolor=lightgreen] INIT;
- node [fillcolor=lightblue] IDLE;
- node [fillcolor=lightyellow] PROCESSING;
+ node[shape = point style = filled fillcolor = black width = 0.5] I;
+ node[shape = doublecircle] F;
+ node[shape = oval width = 1];
+ node[fillcolor = lightgreen] INIT;
+ node[fillcolor = lightblue] IDLE;
+ node[fillcolor = lightyellow] PROCESSING;
- I -> INIT [label="IFactory.createEffect" labelfontcolor="navy"];
- INIT -> F [label="IFactory.destroyEffect"];
- INIT -> IDLE [label="open()" labelfontcolor="lime"];
- IDLE -> PROCESSING [label="command(START"];
- PROCESSING -> IDLE [label="command(STOP)\ncommand(RESET)"];
- IDLE -> INIT [label="close()"];
+ I -> INIT[label = "IFactory.createEffect" labelfontcolor = "navy"];
+ INIT -> F[label = "IFactory.destroyEffect"];
+ INIT -> IDLE[label = "open()" labelfontcolor = "lime"];
+ IDLE -> PROCESSING[label = "command(START"];
+ PROCESSING -> IDLE[label = "command(STOP)\ncommand(RESET)"];
+ IDLE -> INIT[label = "close()"];
- INIT -> INIT [label="getState\ngetDescriptor"];
- IDLE -> IDLE [label="getXXX\nsetParameter\ncommand(RESET)"];
- PROCESSING -> PROCESSING [label="getXXX\nsetParameter"];
-}
\ No newline at end of file
+ INIT -> INIT[label = "getState\ngetDescriptor"];
+ IDLE -> IDLE[label = "getXXX\nsetParameter\ncommand(RESET)"];
+ PROCESSING -> PROCESSING[label = "getXXX\nsetParameter"];
+}
diff --git a/audio/aidl/common/include/Utils.h b/audio/aidl/common/include/Utils.h
index 1026134..990cff9 100644
--- a/audio/aidl/common/include/Utils.h
+++ b/audio/aidl/common/include/Utils.h
@@ -20,6 +20,7 @@
#include <type_traits>
#include <aidl/android/media/audio/common/AudioChannelLayout.h>
+#include <aidl/android/media/audio/common/AudioDeviceType.h>
#include <aidl/android/media/audio/common/AudioFormatDescription.h>
#include <aidl/android/media/audio/common/AudioInputFlags.h>
#include <aidl/android/media/audio/common/AudioOutputFlags.h>
@@ -83,6 +84,12 @@
return 0;
}
+constexpr bool isTelephonyDeviceType(
+ ::aidl::android::media::audio::common::AudioDeviceType device) {
+ return device == ::aidl::android::media::audio::common::AudioDeviceType::IN_TELEPHONY_RX ||
+ device == ::aidl::android::media::audio::common::AudioDeviceType::OUT_TELEPHONY_TX;
+}
+
// The helper functions defined below are only applicable to the case when an enum type
// specifies zero-based bit positions, not bit masks themselves. This is why instantiation
// is restricted to certain enum types.
diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp
index 2b9ed5b..f2cebbf 100644
--- a/audio/aidl/default/Android.bp
+++ b/audio/aidl/default/Android.bp
@@ -18,11 +18,14 @@
"libfmq",
"libstagefright_foundation",
"libutils",
+ "libxml2",
"android.hardware.common-V2-ndk",
"android.hardware.common.fmq-V1-ndk",
],
header_libs: [
+ "libaudio_system_headers",
"libaudioaidl_headers",
+ "libxsdc-utils",
],
}
@@ -35,12 +38,26 @@
],
export_include_dirs: ["include"],
srcs: [
+ "AudioPolicyConfigXmlConverter.cpp",
"Config.cpp",
"Configuration.cpp",
+ "EngineConfigXmlConverter.cpp",
"Module.cpp",
"Stream.cpp",
"Telephony.cpp",
],
+ generated_sources: [
+ "audio_policy_configuration_aidl_default",
+ "audio_policy_engine_configuration_aidl_default",
+ ],
+ generated_headers: [
+ "audio_policy_configuration_aidl_default",
+ "audio_policy_engine_configuration_aidl_default",
+ ],
+ export_generated_headers: [
+ "audio_policy_configuration_aidl_default",
+ "audio_policy_engine_configuration_aidl_default",
+ ],
visibility: [
":__subpackages__",
],
diff --git a/audio/aidl/default/AudioPolicyConfigXmlConverter.cpp b/audio/aidl/default/AudioPolicyConfigXmlConverter.cpp
new file mode 100644
index 0000000..6290912
--- /dev/null
+++ b/audio/aidl/default/AudioPolicyConfigXmlConverter.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fcntl.h>
+#include <inttypes.h>
+#include <unistd.h>
+
+#include <functional>
+#include <unordered_map>
+
+#include <aidl/android/media/audio/common/AudioHalEngineConfig.h>
+#include <system/audio-base-utils.h>
+
+#include "core-impl/AudioPolicyConfigXmlConverter.h"
+
+using aidl::android::media::audio::common::AudioHalEngineConfig;
+using aidl::android::media::audio::common::AudioHalVolumeCurve;
+using aidl::android::media::audio::common::AudioHalVolumeGroup;
+using aidl::android::media::audio::common::AudioStreamType;
+
+namespace xsd = android::audio::policy::configuration;
+
+namespace aidl::android::hardware::audio::core::internal {
+
+static const int kDefaultVolumeIndexMin = 0;
+static const int kDefaultVolumeIndexMax = 100;
+static const int KVolumeIndexDeferredToAudioService = -1;
+/**
+ * Valid curve points take the form "<index>,<attenuationMb>", where the index
+ * must be in the range [0,100]. kInvalidCurvePointIndex is used to indicate
+ * that a point was formatted incorrectly (e.g. if a vendor accidentally typed a
+ * '.' instead of a ',' in their XML) -- using such a curve point will result in
+ * failed VTS tests.
+ */
+static const int8_t kInvalidCurvePointIndex = -1;
+
+AudioHalVolumeCurve::CurvePoint AudioPolicyConfigXmlConverter::convertCurvePointToAidl(
+ const std::string& xsdcCurvePoint) {
+ AudioHalVolumeCurve::CurvePoint aidlCurvePoint{};
+ if (sscanf(xsdcCurvePoint.c_str(), "%" SCNd8 ",%d", &aidlCurvePoint.index,
+ &aidlCurvePoint.attenuationMb) != 2) {
+ aidlCurvePoint.index = kInvalidCurvePointIndex;
+ }
+ return aidlCurvePoint;
+}
+
+AudioHalVolumeCurve AudioPolicyConfigXmlConverter::convertVolumeCurveToAidl(
+ const xsd::Volume& xsdcVolumeCurve) {
+ AudioHalVolumeCurve aidlVolumeCurve;
+ aidlVolumeCurve.deviceCategory =
+ static_cast<AudioHalVolumeCurve::DeviceCategory>(xsdcVolumeCurve.getDeviceCategory());
+ if (xsdcVolumeCurve.hasRef()) {
+ if (mVolumesReferenceMap.empty()) {
+ mVolumesReferenceMap = generateReferenceMap<xsd::Volumes, xsd::Reference>(
+ getXsdcConfig()->getVolumes());
+ }
+ aidlVolumeCurve.curvePoints =
+ convertCollectionToAidl<std::string, AudioHalVolumeCurve::CurvePoint>(
+ mVolumesReferenceMap.at(xsdcVolumeCurve.getRef()).getPoint(),
+ std::bind(&AudioPolicyConfigXmlConverter::convertCurvePointToAidl, this,
+ std::placeholders::_1));
+ } else {
+ aidlVolumeCurve.curvePoints =
+ convertCollectionToAidl<std::string, AudioHalVolumeCurve::CurvePoint>(
+ xsdcVolumeCurve.getPoint(),
+ std::bind(&AudioPolicyConfigXmlConverter::convertCurvePointToAidl, this,
+ std::placeholders::_1));
+ }
+ return aidlVolumeCurve;
+}
+
+void AudioPolicyConfigXmlConverter::mapStreamToVolumeCurve(const xsd::Volume& xsdcVolumeCurve) {
+ mStreamToVolumeCurvesMap[xsdcVolumeCurve.getStream()].push_back(
+ convertVolumeCurveToAidl(xsdcVolumeCurve));
+}
+
+const AudioHalEngineConfig& AudioPolicyConfigXmlConverter::getAidlEngineConfig() {
+ if (mAidlEngineConfig.volumeGroups.empty() && getXsdcConfig() &&
+ getXsdcConfig()->hasVolumes()) {
+ parseVolumes();
+ }
+ return mAidlEngineConfig;
+}
+
+void AudioPolicyConfigXmlConverter::mapStreamsToVolumeCurves() {
+ if (getXsdcConfig()->hasVolumes()) {
+ for (const xsd::Volumes& xsdcWrapperType : getXsdcConfig()->getVolumes()) {
+ for (const xsd::Volume& xsdcVolume : xsdcWrapperType.getVolume()) {
+ mapStreamToVolumeCurve(xsdcVolume);
+ }
+ }
+ }
+}
+
+void AudioPolicyConfigXmlConverter::addVolumeGroupstoEngineConfig() {
+ for (const auto& [xsdcStream, volumeCurves] : mStreamToVolumeCurvesMap) {
+ AudioHalVolumeGroup volumeGroup;
+ volumeGroup.name = xsd::toString(xsdcStream);
+ if (static_cast<int>(xsdcStream) >= AUDIO_STREAM_PUBLIC_CNT) {
+ volumeGroup.minIndex = kDefaultVolumeIndexMin;
+ volumeGroup.maxIndex = kDefaultVolumeIndexMax;
+ } else {
+ volumeGroup.minIndex = KVolumeIndexDeferredToAudioService;
+ volumeGroup.maxIndex = KVolumeIndexDeferredToAudioService;
+ }
+ volumeGroup.volumeCurves = volumeCurves;
+ mAidlEngineConfig.volumeGroups.push_back(std::move(volumeGroup));
+ }
+}
+
+void AudioPolicyConfigXmlConverter::parseVolumes() {
+ if (mStreamToVolumeCurvesMap.empty() && getXsdcConfig()->hasVolumes()) {
+ mapStreamsToVolumeCurves();
+ addVolumeGroupstoEngineConfig();
+ }
+}
+} // namespace aidl::android::hardware::audio::core::internal
diff --git a/audio/aidl/default/Config.cpp b/audio/aidl/default/Config.cpp
index 0fdd5b4..87c0ace 100644
--- a/audio/aidl/default/Config.cpp
+++ b/audio/aidl/default/Config.cpp
@@ -13,10 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#define LOG_TAG "AHAL_Module"
+
+#define LOG_TAG "AHAL_Config"
#include <android-base/logging.h>
+#include <system/audio_config.h>
+
+#include "core-impl/AudioPolicyConfigXmlConverter.h"
#include "core-impl/Config.h"
+#include "core-impl/EngineConfigXmlConverter.h"
+
+using aidl::android::media::audio::common::AudioHalEngineConfig;
namespace aidl::android::hardware::audio::core {
ndk::ScopedAStatus Config::getSurroundSoundConfig(SurroundSoundConfig* _aidl_return) {
@@ -26,4 +33,24 @@
LOG(DEBUG) << __func__ << ": returning " << _aidl_return->toString();
return ndk::ScopedAStatus::ok();
}
+
+ndk::ScopedAStatus Config::getEngineConfig(AudioHalEngineConfig* _aidl_return) {
+ static const AudioHalEngineConfig returnEngCfg = [this]() {
+ AudioHalEngineConfig engConfig;
+ if (mEngConfigConverter.getStatus() == ::android::OK) {
+ engConfig = mEngConfigConverter.getAidlEngineConfig();
+ } else {
+ LOG(INFO) << __func__ << mEngConfigConverter.getError();
+ if (mAudioPolicyConverter.getStatus() == ::android::OK) {
+ engConfig = mAudioPolicyConverter.getAidlEngineConfig();
+ } else {
+ LOG(WARNING) << __func__ << mAudioPolicyConverter.getError();
+ }
+ }
+ return engConfig;
+ }();
+ *_aidl_return = returnEngCfg;
+ LOG(DEBUG) << __func__ << ": returning " << _aidl_return->toString();
+ return ndk::ScopedAStatus::ok();
+}
} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/Configuration.cpp b/audio/aidl/default/Configuration.cpp
index 280814f..6d5357b 100644
--- a/audio/aidl/default/Configuration.cpp
+++ b/audio/aidl/default/Configuration.cpp
@@ -115,85 +115,150 @@
return config;
}
-static AudioRoute createRoute(const std::vector<int32_t>& sources, int32_t sink) {
+static AudioRoute createRoute(const std::vector<AudioPort>& sources, const AudioPort& sink) {
AudioRoute route;
- route.sinkPortId = sink;
- route.sourcePortIds.insert(route.sourcePortIds.end(), sources.begin(), sources.end());
+ route.sinkPortId = sink.id;
+ std::transform(sources.begin(), sources.end(), std::back_inserter(route.sourcePortIds),
+ [](const auto& port) { return port.id; });
return route;
}
-// Configuration:
+// Primary (default) configuration:
//
// Device ports:
-// * "Null", OUT_SPEAKER, default
+// * "Speaker", OUT_SPEAKER, default
// - no profiles specified
-// * "Loopback Out", OUT_SUBMIX
-// - profile PCM 24-bit; STEREO; 48000
+// * "Built-in Mic", IN_MICROPHONE, default
+// - no profiles specified
+// * "Telephony Tx", OUT_TELEPHONY_TX
+// - no profiles specified
+// * "Telephony Rx", IN_TELEPHONY_RX
+// - no profiles specified
+// * "FM Tuner", IN_FM_TUNER
+// - no profiles specified
// * "USB Out", OUT_DEVICE, CONNECTION_USB
// - no profiles specified
-// * "Zero", IN_MICROPHONE, default
-// - no profiles specified
-// * "Loopback In", IN_SUBMIX
-// - profile PCM 24-bit; STEREO; 48000
// * "USB In", IN_DEVICE, CONNECTION_USB
// - no profiles specified
//
// Mix ports:
// * "primary output", PRIMARY, 1 max open, 1 max active stream
-// - profile PCM 16-bit; MONO, STEREO; 44100, 48000
-// - profile PCM 24-bit; MONO, STEREO; 44100, 48000
+// - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
+// - profile PCM 24-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
// * "compressed offload", DIRECT|COMPRESS_OFFLOAD|NON_BLOCKING, 1 max open, 1 max active stream
// - profile MP3; MONO, STEREO; 44100, 48000
-// * "loopback output", stream count unlimited
-// - profile PCM 24-bit; STEREO; 48000
// * "primary input", 2 max open, 2 max active streams
// - profile PCM 16-bit; MONO, STEREO, FRONT_BACK;
// 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
// - profile PCM 24-bit; MONO, STEREO, FRONT_BACK;
// 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
-// * "loopback input", stream count unlimited
-// - profile PCM 24-bit; STEREO; 48000
+// * "telephony_tx", 1 max open, 1 max active stream
+// - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
+// - profile PCM 24-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
+// * "telephony_rx", 1 max open, 1 max active stream
+// - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
+// - profile PCM 24-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
+// * "fm_tuner", 1 max open, 1 max active stream
+// - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
+// - profile PCM 24-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
//
// Routes:
-// "primary out", "compressed offload" -> "Null"
+// "primary out", "compressed offload" -> "Speaker"
// "primary out", "compressed offload" -> "USB Out"
-// "loopback out" -> "Loopback Out"
-// "Zero", "USB In" -> "primary input"
-// "Loopback In" -> "loopback input"
+// "Built-in Mic", "USB In" -> "primary input"
+// "telephony_tx" -> "Telephony Tx"
+// "Telephony Rx" -> "telephony_rx"
+// "FM Tuner" -> "fm_tuner"
//
// Initial port configs:
-// * "Null" device port: PCM 24-bit; STEREO; 48000
-// * "Zero" device port: PCM 24-bit; MONO; 48000
+// * "Speaker" device port: PCM 24-bit; STEREO; 48000
+// * "Built-in Mic" device port: PCM 24-bit; MONO; 48000
+// * "Telephony Tx" device port: PCM 24-bit; MONO; 48000
+// * "Telephony Rx" device port: PCM 24-bit; MONO; 48000
+// * "FM Tuner" device port: PCM 24-bit; STEREO; 48000
//
// Profiles for device port connected state:
// * USB Out":
-// - profile PCM 16-bit; MONO, STEREO; 44100, 48000
-// - profile PCM 24-bit; MONO, STEREO; 44100, 48000
+// - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
+// - profile PCM 24-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
// * USB In":
-// - profile PCM 16-bit; MONO, STEREO; 44100, 48000
-// - profile PCM 24-bit; MONO, STEREO; 44100, 48000
+// - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
+// - profile PCM 24-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
//
-Configuration& getNullPrimaryConfiguration() {
- static Configuration configuration = []() {
+std::unique_ptr<Configuration> getPrimaryConfiguration() {
+ static const Configuration configuration = []() {
const std::vector<AudioProfile> standardPcmAudioProfiles = {
createProfile(PcmType::INT_16_BIT,
{AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
- {44100, 48000}),
+ {8000, 11025, 16000, 32000, 44100, 48000}),
createProfile(PcmType::INT_24_BIT,
{AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
- {44100, 48000})};
+ {8000, 11025, 16000, 32000, 44100, 48000})};
Configuration c;
- AudioPort nullOutDevice =
- createPort(c.nextPortId++, "Null", 0, false,
+ // Device ports
+
+ AudioPort speakerOutDevice =
+ createPort(c.nextPortId++, "Speaker", 0, false,
createDeviceExt(AudioDeviceType::OUT_SPEAKER,
1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE));
- c.ports.push_back(nullOutDevice);
+ c.ports.push_back(speakerOutDevice);
c.initialConfigs.push_back(
- createPortConfig(nullOutDevice.id, nullOutDevice.id, PcmType::INT_24_BIT,
+ createPortConfig(speakerOutDevice.id, speakerOutDevice.id, PcmType::INT_24_BIT,
AudioChannelLayout::LAYOUT_STEREO, 48000, 0, false,
createDeviceExt(AudioDeviceType::OUT_SPEAKER, 0)));
+ AudioPort micInDevice =
+ createPort(c.nextPortId++, "Built-in Mic", 0, true,
+ createDeviceExt(AudioDeviceType::IN_MICROPHONE,
+ 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE));
+ c.ports.push_back(micInDevice);
+ c.initialConfigs.push_back(
+ createPortConfig(micInDevice.id, micInDevice.id, PcmType::INT_24_BIT,
+ AudioChannelLayout::LAYOUT_MONO, 48000, 0, true,
+ createDeviceExt(AudioDeviceType::IN_MICROPHONE, 0)));
+
+ AudioPort telephonyTxOutDevice =
+ createPort(c.nextPortId++, "Telephony Tx", 0, false,
+ createDeviceExt(AudioDeviceType::OUT_TELEPHONY_TX, 0));
+ c.ports.push_back(telephonyTxOutDevice);
+ c.initialConfigs.push_back(
+ createPortConfig(telephonyTxOutDevice.id, telephonyTxOutDevice.id,
+ PcmType::INT_24_BIT, AudioChannelLayout::LAYOUT_MONO, 48000, 0,
+ false, createDeviceExt(AudioDeviceType::OUT_TELEPHONY_TX, 0)));
+
+ AudioPort telephonyRxInDevice =
+ createPort(c.nextPortId++, "Telephony Rx", 0, true,
+ createDeviceExt(AudioDeviceType::IN_TELEPHONY_RX, 0));
+ c.ports.push_back(telephonyRxInDevice);
+ c.initialConfigs.push_back(
+ createPortConfig(telephonyRxInDevice.id, telephonyRxInDevice.id,
+ PcmType::INT_24_BIT, AudioChannelLayout::LAYOUT_MONO, 48000, 0,
+ true, createDeviceExt(AudioDeviceType::IN_TELEPHONY_RX, 0)));
+
+ AudioPort fmTunerInDevice = createPort(c.nextPortId++, "FM Tuner", 0, true,
+ createDeviceExt(AudioDeviceType::IN_FM_TUNER, 0));
+ c.ports.push_back(fmTunerInDevice);
+ c.initialConfigs.push_back(
+ createPortConfig(fmTunerInDevice.id, fmTunerInDevice.id, PcmType::INT_24_BIT,
+ AudioChannelLayout::LAYOUT_STEREO, 48000, 0, true,
+ createDeviceExt(AudioDeviceType::IN_FM_TUNER, 0)));
+
+ AudioPort usbOutDevice =
+ createPort(c.nextPortId++, "USB Out", 0, false,
+ createDeviceExt(AudioDeviceType::OUT_DEVICE, 0,
+ AudioDeviceDescription::CONNECTION_USB));
+ c.ports.push_back(usbOutDevice);
+ c.connectedProfiles[usbOutDevice.id] = standardPcmAudioProfiles;
+
+ AudioPort usbInDevice = createPort(c.nextPortId++, "USB In", 0, true,
+ createDeviceExt(AudioDeviceType::IN_DEVICE, 0,
+ AudioDeviceDescription::CONNECTION_USB));
+ c.ports.push_back(usbInDevice);
+ c.connectedProfiles[usbInDevice.id] = standardPcmAudioProfiles;
+
+ // Mix ports
+
AudioPort primaryOutMix = createPort(c.nextPortId++, "primary output",
makeBitPositionFlagMask(AudioOutputFlags::PRIMARY),
false, createPortMixExt(1, 1));
@@ -214,42 +279,6 @@
{44100, 48000}));
c.ports.push_back(compressedOffloadOutMix);
- AudioPort loopOutDevice = createPort(c.nextPortId++, "Loopback Out", 0, false,
- createDeviceExt(AudioDeviceType::OUT_SUBMIX, 0));
- loopOutDevice.profiles.push_back(
- createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000}));
- c.ports.push_back(loopOutDevice);
-
- AudioPort loopOutMix =
- createPort(c.nextPortId++, "loopback output", 0, false, createPortMixExt(0, 0));
- loopOutMix.profiles.push_back(
- createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000}));
- c.ports.push_back(loopOutMix);
-
- AudioPort usbOutDevice =
- createPort(c.nextPortId++, "USB Out", 0, false,
- createDeviceExt(AudioDeviceType::OUT_DEVICE, 0,
- AudioDeviceDescription::CONNECTION_USB));
- c.ports.push_back(usbOutDevice);
- c.connectedProfiles[usbOutDevice.id] = standardPcmAudioProfiles;
-
- AudioPort zeroInDevice =
- createPort(c.nextPortId++, "Zero", 0, true,
- createDeviceExt(AudioDeviceType::IN_MICROPHONE,
- 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE));
- c.ports.push_back(zeroInDevice);
- c.initialConfigs.push_back(
- createPortConfig(zeroInDevice.id, zeroInDevice.id, PcmType::INT_24_BIT,
- AudioChannelLayout::LAYOUT_MONO, 48000, 0, true,
- createDeviceExt(AudioDeviceType::IN_MICROPHONE, 0)));
-
- MicrophoneInfo mic;
- mic.id = "zero";
- mic.device = zeroInDevice.ext.get<AudioPortExt::Tag::device>().device;
- mic.group = 0;
- mic.indexInTheGroup = 0;
- c.microphones = std::vector<MicrophoneInfo>{mic};
-
AudioPort primaryInMix =
createPort(c.nextPortId++, "primary input", 0, true, createPortMixExt(2, 2));
primaryInMix.profiles.push_back(
@@ -264,36 +293,104 @@
{8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000}));
c.ports.push_back(primaryInMix);
- AudioPort loopInDevice = createPort(c.nextPortId++, "Loopback In", 0, true,
- createDeviceExt(AudioDeviceType::IN_SUBMIX, 0));
- loopInDevice.profiles.push_back(
- createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000}));
- c.ports.push_back(loopInDevice);
+ AudioPort telephonyTxOutMix =
+ createPort(c.nextPortId++, "telephony_tx", 0, false, createPortMixExt(1, 1));
+ telephonyTxOutMix.profiles.insert(telephonyTxOutMix.profiles.begin(),
+ standardPcmAudioProfiles.begin(),
+ standardPcmAudioProfiles.end());
+ c.ports.push_back(telephonyTxOutMix);
- AudioPort loopInMix =
- createPort(c.nextPortId++, "loopback input", 0, true, createPortMixExt(0, 0));
- loopInMix.profiles.push_back(
- createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000}));
- c.ports.push_back(loopInMix);
+ AudioPort telephonyRxInMix =
+ createPort(c.nextPortId++, "telephony_rx", 0, true, createPortMixExt(1, 1));
+ telephonyRxInMix.profiles.insert(telephonyRxInMix.profiles.begin(),
+ standardPcmAudioProfiles.begin(),
+ standardPcmAudioProfiles.end());
+ c.ports.push_back(telephonyRxInMix);
- AudioPort usbInDevice = createPort(c.nextPortId++, "USB In", 0, true,
- createDeviceExt(AudioDeviceType::IN_DEVICE, 0,
- AudioDeviceDescription::CONNECTION_USB));
- c.ports.push_back(usbInDevice);
- c.connectedProfiles[usbInDevice.id] = standardPcmAudioProfiles;
+ AudioPort fmTunerInMix =
+ createPort(c.nextPortId++, "fm_tuner", 0, true, createPortMixExt(1, 1));
+ fmTunerInMix.profiles.insert(fmTunerInMix.profiles.begin(),
+ standardPcmAudioProfiles.begin(),
+ standardPcmAudioProfiles.end());
+ c.ports.push_back(fmTunerInMix);
- c.routes.push_back(
- createRoute({primaryOutMix.id, compressedOffloadOutMix.id}, nullOutDevice.id));
- c.routes.push_back(
- createRoute({primaryOutMix.id, compressedOffloadOutMix.id}, usbOutDevice.id));
- c.routes.push_back(createRoute({loopOutMix.id}, loopOutDevice.id));
- c.routes.push_back(createRoute({zeroInDevice.id, usbInDevice.id}, primaryInMix.id));
- c.routes.push_back(createRoute({loopInDevice.id}, loopInMix.id));
+ c.routes.push_back(createRoute({primaryOutMix, compressedOffloadOutMix}, speakerOutDevice));
+ c.routes.push_back(createRoute({primaryOutMix, compressedOffloadOutMix}, usbOutDevice));
+ c.routes.push_back(createRoute({micInDevice, usbInDevice}, primaryInMix));
+ c.routes.push_back(createRoute({telephonyTxOutMix}, telephonyTxOutDevice));
+ c.routes.push_back(createRoute({telephonyRxInDevice}, telephonyRxInMix));
+ c.routes.push_back(createRoute({fmTunerInDevice}, fmTunerInMix));
c.portConfigs.insert(c.portConfigs.end(), c.initialConfigs.begin(), c.initialConfigs.end());
+
+ MicrophoneInfo mic;
+ mic.id = "mic";
+ mic.device = micInDevice.ext.get<AudioPortExt::Tag::device>().device;
+ mic.group = 0;
+ mic.indexInTheGroup = 0;
+ c.microphones = std::vector<MicrophoneInfo>{mic};
+
return c;
}();
- return configuration;
+ return std::make_unique<Configuration>(configuration);
+}
+
+// Remote Submix configuration:
+//
+// Device ports:
+// * "Remote Submix Out", OUT_SUBMIX
+// - profile PCM 24-bit; STEREO; 48000
+// * "Remote Submix In", IN_SUBMIX
+// - profile PCM 24-bit; STEREO; 48000
+//
+// Mix ports:
+// * "r_submix output", stream count unlimited
+// - profile PCM 24-bit; STEREO; 48000
+// * "r_submix input", stream count unlimited
+// - profile PCM 24-bit; STEREO; 48000
+//
+// Routes:
+// "r_submix output" -> "Remote Submix Out"
+// "Remote Submix In" -> "r_submix input"
+//
+std::unique_ptr<Configuration> getRSubmixConfiguration() {
+ static const Configuration configuration = []() {
+ Configuration c;
+
+ // Device ports
+
+ AudioPort rsubmixOutDevice = createPort(c.nextPortId++, "Remote Submix Out", 0, false,
+ createDeviceExt(AudioDeviceType::OUT_SUBMIX, 0));
+ rsubmixOutDevice.profiles.push_back(
+ createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000}));
+ c.ports.push_back(rsubmixOutDevice);
+
+ AudioPort rsubmixInDevice = createPort(c.nextPortId++, "Remote Submix In", 0, true,
+ createDeviceExt(AudioDeviceType::IN_SUBMIX, 0));
+ rsubmixInDevice.profiles.push_back(
+ createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000}));
+ c.ports.push_back(rsubmixInDevice);
+
+ // Mix ports
+
+ AudioPort rsubmixOutMix =
+ createPort(c.nextPortId++, "r_submix output", 0, false, createPortMixExt(0, 0));
+ rsubmixOutMix.profiles.push_back(
+ createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000}));
+ c.ports.push_back(rsubmixOutMix);
+
+ AudioPort rsubmixInMix =
+ createPort(c.nextPortId++, "r_submix input", 0, true, createPortMixExt(0, 0));
+ rsubmixInMix.profiles.push_back(
+ createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000}));
+ c.ports.push_back(rsubmixInMix);
+
+ c.routes.push_back(createRoute({rsubmixOutMix}, rsubmixOutDevice));
+ c.routes.push_back(createRoute({rsubmixInDevice}, rsubmixInMix));
+
+ return c;
+ }();
+ return std::make_unique<Configuration>(configuration);
}
} // namespace aidl::android::hardware::audio::core::internal
diff --git a/audio/aidl/default/EffectFactory.cpp b/audio/aidl/default/EffectFactory.cpp
index 74ed780..7ae9a66 100644
--- a/audio/aidl/default/EffectFactory.cpp
+++ b/audio/aidl/default/EffectFactory.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+#include <iterator>
+#include <memory>
+#include <tuple>
+#include "include/effect-impl/EffectTypes.h"
#define LOG_TAG "AHAL_EffectFactory"
#include <dlfcn.h>
#include <unordered_set>
@@ -51,15 +55,29 @@
ndk::ScopedAStatus Factory::queryEffects(const std::optional<AudioUuid>& in_type_uuid,
const std::optional<AudioUuid>& in_impl_uuid,
const std::optional<AudioUuid>& in_proxy_uuid,
- std::vector<Descriptor::Identity>* _aidl_return) {
- std::copy_if(
- mIdentitySet.begin(), mIdentitySet.end(), std::back_inserter(*_aidl_return),
- [&](auto& desc) {
- return (!in_type_uuid.has_value() || in_type_uuid.value() == desc.type) &&
- (!in_impl_uuid.has_value() || in_impl_uuid.value() == desc.uuid) &&
- (!in_proxy_uuid.has_value() ||
- (desc.proxy.has_value() && in_proxy_uuid.value() == desc.proxy.value()));
- });
+ std::vector<Descriptor>* _aidl_return) {
+ // get the matching list
+ std::vector<Descriptor::Identity> idList;
+ std::copy_if(mIdentitySet.begin(), mIdentitySet.end(), std::back_inserter(idList),
+ [&](auto& id) {
+ return (!in_type_uuid.has_value() || in_type_uuid.value() == id.type) &&
+ (!in_impl_uuid.has_value() || in_impl_uuid.value() == id.uuid) &&
+ (!in_proxy_uuid.has_value() ||
+ (id.proxy.has_value() && in_proxy_uuid.value() == id.proxy.value()));
+ });
+ // query through the matching list
+ for (const auto& id : idList) {
+ if (mEffectLibMap.count(id.uuid)) {
+ Descriptor desc;
+ auto& entry = mEffectLibMap[id.uuid];
+ getDlSyms(entry);
+ auto& libInterface = std::get<kMapEntryInterfaceIndex>(entry);
+ RETURN_IF(!libInterface || !libInterface->queryEffectFunc, EX_NULL_POINTER,
+ "dlNullQueryEffectFunc");
+ RETURN_IF_BINDER_EXCEPTION(libInterface->queryEffectFunc(&id.uuid, &desc));
+ _aidl_return->emplace_back(std::move(desc));
+ }
+ }
return ndk::ScopedAStatus::ok();
}
@@ -74,37 +92,16 @@
return ndk::ScopedAStatus::ok();
}
-#define RETURN_IF_BINDER_EXCEPTION(functor) \
- { \
- binder_exception_t exception = functor; \
- if (EX_NONE != exception) { \
- LOG(ERROR) << #functor << ": failed with error " << exception; \
- return ndk::ScopedAStatus::fromExceptionCode(exception); \
- } \
- }
-
ndk::ScopedAStatus Factory::createEffect(const AudioUuid& in_impl_uuid,
std::shared_ptr<IEffect>* _aidl_return) {
LOG(DEBUG) << __func__ << ": UUID " << in_impl_uuid.toString();
if (mEffectLibMap.count(in_impl_uuid)) {
- auto& lib = mEffectLibMap[in_impl_uuid];
- // didn't do dlsym yet
- if (nullptr == lib.second) {
- void* libHandle = lib.first.get();
- auto dlInterface = std::make_unique<struct effect_dl_interface_s>();
- dlInterface->createEffectFunc = (EffectCreateFunctor)dlsym(libHandle, "createEffect");
- dlInterface->destroyEffectFunc =
- (EffectDestroyFunctor)dlsym(libHandle, "destroyEffect");
- if (!dlInterface->createEffectFunc || !dlInterface->destroyEffectFunc) {
- LOG(ERROR) << __func__
- << ": create or destroy symbol not exist in library: " << libHandle
- << " with dlerror: " << dlerror();
- return ndk::ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
- }
- lib.second = std::move(dlInterface);
- }
+ auto& entry = mEffectLibMap[in_impl_uuid];
+ getDlSyms(entry);
- auto& libInterface = lib.second;
+ auto& libInterface = std::get<kMapEntryInterfaceIndex>(entry);
+ RETURN_IF(!libInterface || !libInterface->createEffectFunc, EX_NULL_POINTER,
+ "dlNullcreateEffectFunc");
std::shared_ptr<IEffect> effectSp;
RETURN_IF_BINDER_EXCEPTION(libInterface->createEffectFunc(&in_impl_uuid, &effectSp));
if (!effectSp) {
@@ -131,9 +128,10 @@
auto& uuid = uuidIt->second;
// find implementation library with UUID
if (auto libIt = mEffectLibMap.find(uuid); libIt != mEffectLibMap.end()) {
- if (libIt->second.second->destroyEffectFunc) {
- RETURN_IF_BINDER_EXCEPTION(libIt->second.second->destroyEffectFunc(in_handle));
- }
+ auto& interface = std::get<kMapEntryInterfaceIndex>(libIt->second);
+ RETURN_IF(!interface || !interface->destroyEffectFunc, EX_NULL_POINTER,
+ "dlNulldestroyEffectFunc");
+ RETURN_IF_BINDER_EXCEPTION(interface->destroyEffectFunc(in_handle));
} else {
LOG(ERROR) << __func__ << ": UUID " << uuid.toString() << " does not exist in libMap!";
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
@@ -179,9 +177,13 @@
return;
}
- LOG(DEBUG) << __func__ << " dlopen lib:" << libName << "\nimpl:" << impl.toString()
- << "\nhandle:" << libHandle;
- mEffectLibMap.insert({impl, std::make_pair(std::move(libHandle), nullptr)});
+ LOG(INFO) << __func__ << " dlopen lib:" << libName << "\nimpl:" << impl.toString()
+ << "\nhandle:" << libHandle;
+ auto interface = new effect_dl_interface_s{nullptr, nullptr, nullptr};
+ mEffectLibMap.insert(
+ {impl,
+ std::make_tuple(std::move(libHandle),
+ std::unique_ptr<struct effect_dl_interface_s>(interface), libName)});
}
void Factory::createIdentityWithConfig(const EffectConfig::LibraryUuid& configLib,
@@ -226,4 +228,32 @@
}
}
+void Factory::getDlSyms(DlEntry& entry) {
+ auto& dlHandle = std::get<kMapEntryHandleIndex>(entry);
+ RETURN_VALUE_IF(!dlHandle, void(), "dlNullHandle");
+ // Get the reference of the DL interfaces in library map tuple.
+ auto& dlInterface = std::get<kMapEntryInterfaceIndex>(entry);
+ // return if interface already exist
+ if (!dlInterface->createEffectFunc) {
+ dlInterface->createEffectFunc = (EffectCreateFunctor)dlsym(dlHandle.get(), "createEffect");
+ }
+ if (!dlInterface->queryEffectFunc) {
+ dlInterface->queryEffectFunc = (EffectQueryFunctor)dlsym(dlHandle.get(), "queryEffect");
+ }
+ if (!dlInterface->destroyEffectFunc) {
+ dlInterface->destroyEffectFunc =
+ (EffectDestroyFunctor)dlsym(dlHandle.get(), "destroyEffect");
+ }
+
+ if (!dlInterface->createEffectFunc || !dlInterface->destroyEffectFunc ||
+ !dlInterface->queryEffectFunc) {
+ LOG(ERROR) << __func__ << ": create (" << dlInterface->createEffectFunc << "), query ("
+ << dlInterface->queryEffectFunc << "), or destroy ("
+ << dlInterface->destroyEffectFunc
+ << ") not exist in library: " << std::get<kMapEntryLibNameIndex>(entry)
+ << " handle: " << dlHandle << " with dlerror: " << dlerror();
+ return;
+ }
+}
+
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/EffectImpl.cpp b/audio/aidl/default/EffectImpl.cpp
index 2754bb6..139f262 100644
--- a/audio/aidl/default/EffectImpl.cpp
+++ b/audio/aidl/default/EffectImpl.cpp
@@ -19,47 +19,54 @@
#include "effect-impl/EffectTypes.h"
#include "include/effect-impl/EffectTypes.h"
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::State;
+
+extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
+ State state;
+ ndk::ScopedAStatus status = instanceSp->getState(&state);
+ if (!status.isOk() || State::INIT != state) {
+ LOG(ERROR) << __func__ << " instance " << instanceSp.get()
+ << " in state: " << toString(state) << ", status: " << status.getDescription();
+ return EX_ILLEGAL_STATE;
+ }
+ LOG(DEBUG) << __func__ << " instance " << instanceSp.get() << " destroyed";
+ return EX_NONE;
+}
+
namespace aidl::android::hardware::audio::effect {
ndk::ScopedAStatus EffectImpl::open(const Parameter::Common& common,
const std::optional<Parameter::Specific>& specific,
OpenEffectReturn* ret) {
LOG(DEBUG) << __func__;
- {
- std::lock_guard lg(mMutex);
- RETURN_OK_IF(mState != State::INIT);
- mContext = createContext(common);
- RETURN_IF(!mContext, EX_ILLEGAL_ARGUMENT, "createContextFailed");
- setContext(mContext);
- }
+ RETURN_OK_IF(mState != State::INIT);
+ auto context = createContext(common);
+ RETURN_IF(!context, EX_NULL_POINTER, "createContextFailed");
RETURN_IF_ASTATUS_NOT_OK(setParameterCommon(common), "setCommParamErr");
if (specific.has_value()) {
RETURN_IF_ASTATUS_NOT_OK(setParameterSpecific(specific.value()), "setSpecParamErr");
}
- RETURN_IF(createThread(LOG_TAG) != RetCode::SUCCESS, EX_UNSUPPORTED_OPERATION,
+ mState = State::IDLE;
+ context->dupeFmq(ret);
+ RETURN_IF(createThread(context, getEffectName()) != RetCode::SUCCESS, EX_UNSUPPORTED_OPERATION,
"FailedToCreateWorker");
-
- {
- std::lock_guard lg(mMutex);
- mContext->dupeFmq(ret);
- mState = State::IDLE;
- }
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus EffectImpl::close() {
- std::lock_guard lg(mMutex);
RETURN_OK_IF(mState == State::INIT);
RETURN_IF(mState == State::PROCESSING, EX_ILLEGAL_STATE, "closeAtProcessing");
// stop the worker thread, ignore the return code
RETURN_IF(destroyThread() != RetCode::SUCCESS, EX_UNSUPPORTED_OPERATION,
"FailedToDestroyWorker");
+ mState = State::INIT;
RETURN_IF(releaseContext() != RetCode::SUCCESS, EX_UNSUPPORTED_OPERATION,
"FailedToCreateWorker");
- mState = State::INIT;
+
LOG(DEBUG) << __func__;
return ndk::ScopedAStatus::ok();
}
@@ -113,29 +120,30 @@
}
ndk::ScopedAStatus EffectImpl::setParameterCommon(const Parameter& param) {
- std::lock_guard lg(mMutex);
- RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+ auto context = getContext();
+ RETURN_IF(!context, EX_NULL_POINTER, "nullContext");
+
auto tag = param.getTag();
switch (tag) {
case Parameter::common:
- RETURN_IF(mContext->setCommon(param.get<Parameter::common>()) != RetCode::SUCCESS,
+ RETURN_IF(context->setCommon(param.get<Parameter::common>()) != RetCode::SUCCESS,
EX_ILLEGAL_ARGUMENT, "setCommFailed");
break;
case Parameter::deviceDescription:
- RETURN_IF(mContext->setOutputDevice(param.get<Parameter::deviceDescription>()) !=
+ RETURN_IF(context->setOutputDevice(param.get<Parameter::deviceDescription>()) !=
RetCode::SUCCESS,
EX_ILLEGAL_ARGUMENT, "setDeviceFailed");
break;
case Parameter::mode:
- RETURN_IF(mContext->setAudioMode(param.get<Parameter::mode>()) != RetCode::SUCCESS,
+ RETURN_IF(context->setAudioMode(param.get<Parameter::mode>()) != RetCode::SUCCESS,
EX_ILLEGAL_ARGUMENT, "setModeFailed");
break;
case Parameter::source:
- RETURN_IF(mContext->setAudioSource(param.get<Parameter::source>()) != RetCode::SUCCESS,
+ RETURN_IF(context->setAudioSource(param.get<Parameter::source>()) != RetCode::SUCCESS,
EX_ILLEGAL_ARGUMENT, "setSourceFailed");
break;
case Parameter::volumeStereo:
- RETURN_IF(mContext->setVolumeStereo(param.get<Parameter::volumeStereo>()) !=
+ RETURN_IF(context->setVolumeStereo(param.get<Parameter::volumeStereo>()) !=
RetCode::SUCCESS,
EX_ILLEGAL_ARGUMENT, "setVolumeStereoFailed");
break;
@@ -149,27 +157,28 @@
}
ndk::ScopedAStatus EffectImpl::getParameterCommon(const Parameter::Tag& tag, Parameter* param) {
- std::lock_guard lg(mMutex);
- RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+ auto context = getContext();
+ RETURN_IF(!context, EX_NULL_POINTER, "nullContext");
+
switch (tag) {
case Parameter::common: {
- param->set<Parameter::common>(mContext->getCommon());
+ param->set<Parameter::common>(context->getCommon());
break;
}
case Parameter::deviceDescription: {
- param->set<Parameter::deviceDescription>(mContext->getOutputDevice());
+ param->set<Parameter::deviceDescription>(context->getOutputDevice());
break;
}
case Parameter::mode: {
- param->set<Parameter::mode>(mContext->getAudioMode());
+ param->set<Parameter::mode>(context->getAudioMode());
break;
}
case Parameter::source: {
- param->set<Parameter::source>(mContext->getAudioSource());
+ param->set<Parameter::source>(context->getAudioSource());
break;
}
case Parameter::volumeStereo: {
- param->set<Parameter::volumeStereo>(mContext->getVolumeStereo());
+ param->set<Parameter::volumeStereo>(context->getVolumeStereo());
break;
}
default: {
@@ -182,39 +191,30 @@
}
ndk::ScopedAStatus EffectImpl::getState(State* state) {
- std::lock_guard lg(mMutex);
*state = mState;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus EffectImpl::command(CommandId command) {
- std::lock_guard lg(mMutex);
+ RETURN_IF(mState == State::INIT, EX_ILLEGAL_STATE, "CommandStateError");
LOG(DEBUG) << __func__ << ": receive command: " << toString(command) << " at state "
<< toString(mState);
- RETURN_IF(mState == State::INIT, EX_ILLEGAL_STATE, "CommandStateError");
- RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
switch (command) {
case CommandId::START:
RETURN_IF(mState == State::INIT, EX_ILLEGAL_STATE, "instanceNotOpen");
RETURN_OK_IF(mState == State::PROCESSING);
- RETURN_IF_ASTATUS_NOT_OK(commandStart(), "commandStartFailed");
- mState = State::PROCESSING;
+ RETURN_IF_ASTATUS_NOT_OK(commandImpl(command), "commandImplFailed");
startThread();
- return ndk::ScopedAStatus::ok();
+ mState = State::PROCESSING;
+ break;
case CommandId::STOP:
- RETURN_OK_IF(mState == State::IDLE);
- mState = State::IDLE;
- RETURN_IF_ASTATUS_NOT_OK(commandStop(), "commandStopFailed");
- stopThread();
- return ndk::ScopedAStatus::ok();
case CommandId::RESET:
RETURN_OK_IF(mState == State::IDLE);
- mState = State::IDLE;
- RETURN_IF_ASTATUS_NOT_OK(commandStop(), "commandStopFailed");
stopThread();
- mContext->resetBuffer();
- return ndk::ScopedAStatus::ok();
+ RETURN_IF_ASTATUS_NOT_OK(commandImpl(command), "commandImplFailed");
+ mState = State::IDLE;
+ break;
default:
LOG(ERROR) << __func__ << " instance still processing";
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
@@ -224,6 +224,15 @@
return ndk::ScopedAStatus::ok();
}
+ndk::ScopedAStatus EffectImpl::commandImpl(CommandId command) {
+ auto context = getContext();
+ RETURN_IF(!context, EX_NULL_POINTER, "nullContext");
+ if (command == CommandId::RESET) {
+ context->resetBuffer();
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
void EffectImpl::cleanUp() {
command(CommandId::STOP);
close();
@@ -238,19 +247,12 @@
}
// A placeholder processing implementation to copy samples from input to output
-IEffect::Status EffectImpl::effectProcessImpl(float* in, float* out, int processSamples) {
- // lock before access context/parameters
- std::lock_guard lg(mMutex);
- IEffect::Status status = {EX_NULL_POINTER, 0, 0};
- RETURN_VALUE_IF(!mContext, status, "nullContext");
- auto frameSize = mContext->getInputFrameSize();
- RETURN_VALUE_IF(0 == frameSize, status, "frameSizeIs0");
- LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << processSamples
- << " frames " << processSamples * sizeof(float) / frameSize;
- for (int i = 0; i < processSamples; i++) {
+IEffect::Status EffectImpl::effectProcessImpl(float* in, float* out, int samples) {
+ for (int i = 0; i < samples; i++) {
*out++ = *in++;
}
- LOG(DEBUG) << __func__ << " done processing " << processSamples << " samples";
- return {STATUS_OK, processSamples, processSamples};
+ LOG(DEBUG) << __func__ << " done processing " << samples << " samples";
+ return {STATUS_OK, samples, samples};
}
+
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/EffectThread.cpp b/audio/aidl/default/EffectThread.cpp
index 80f120b..2b3513d 100644
--- a/audio/aidl/default/EffectThread.cpp
+++ b/audio/aidl/default/EffectThread.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <memory>
#define LOG_TAG "AHAL_EffectThread"
#include <android-base/logging.h>
#include <pthread.h>
@@ -32,13 +33,18 @@
LOG(DEBUG) << __func__ << " done";
};
-RetCode EffectThread::createThread(const std::string& name, const int priority) {
+RetCode EffectThread::createThread(std::shared_ptr<EffectContext> context, const std::string& name,
+ const int priority) {
if (mThread.joinable()) {
LOG(WARNING) << __func__ << " thread already created, no-op";
return RetCode::SUCCESS;
}
mName = name;
mPriority = priority;
+ {
+ std::lock_guard lg(mThreadMutex);
+ mThreadContext = std::move(context);
+ }
mThread = std::thread(&EffectThread::threadLoop, this);
LOG(DEBUG) << __func__ << " " << name << " priority " << mPriority << " done";
return RetCode::SUCCESS;
@@ -46,7 +52,7 @@
RetCode EffectThread::destroyThread() {
{
- std::lock_guard lg(mMutex);
+ std::lock_guard lg(mThreadMutex);
mStop = mExit = true;
}
mCv.notify_one();
@@ -54,6 +60,11 @@
if (mThread.joinable()) {
mThread.join();
}
+
+ {
+ std::lock_guard lg(mThreadMutex);
+ mThreadContext.reset();
+ }
LOG(DEBUG) << __func__ << " done";
return RetCode::SUCCESS;
}
@@ -65,7 +76,7 @@
}
{
- std::lock_guard lg(mMutex);
+ std::lock_guard lg(mThreadMutex);
if (!mStop) {
LOG(WARNING) << __func__ << " already start";
return RetCode::SUCCESS;
@@ -85,7 +96,7 @@
}
{
- std::lock_guard lg(mMutex);
+ std::lock_guard lg(mThreadMutex);
if (mStop) {
LOG(WARNING) << __func__ << " already stop";
return RetCode::SUCCESS;
@@ -97,13 +108,13 @@
}
void EffectThread::threadLoop() {
- pthread_setname_np(pthread_self(), mName.substr(0, MAX_TASK_COMM_LEN - 1).c_str());
+ pthread_setname_np(pthread_self(), mName.substr(0, kMaxTaskNameLen - 1).c_str());
setpriority(PRIO_PROCESS, 0, mPriority);
while (true) {
bool needExit = false;
{
- std::unique_lock l(mMutex);
- mCv.wait(l, [&]() REQUIRES(mMutex) {
+ std::unique_lock l(mThreadMutex);
+ mCv.wait(l, [&]() REQUIRES(mThreadMutex) {
needExit = mExit;
return mExit || !mStop;
});
@@ -112,9 +123,41 @@
LOG(WARNING) << __func__ << " EXIT!";
return;
}
- // process without lock
+
process();
}
}
+void EffectThread::process() {
+ std::shared_ptr<EffectContext> context;
+ {
+ std::lock_guard lg(mThreadMutex);
+ context = mThreadContext;
+ RETURN_VALUE_IF(!context, void(), "nullContext");
+ }
+ std::shared_ptr<EffectContext::StatusMQ> statusMQ = context->getStatusFmq();
+ std::shared_ptr<EffectContext::DataMQ> inputMQ = context->getInputDataFmq();
+ std::shared_ptr<EffectContext::DataMQ> outputMQ = context->getOutputDataFmq();
+ auto buffer = context->getWorkBuffer();
+
+ // Only this worker will read from input data MQ and write to output data MQ.
+ auto readSamples = inputMQ->availableToRead(), writeSamples = outputMQ->availableToWrite();
+ if (readSamples && writeSamples) {
+ auto processSamples = std::min(readSamples, writeSamples);
+ LOG(DEBUG) << __func__ << " available to read " << readSamples << " available to write "
+ << writeSamples << " process " << processSamples;
+
+ inputMQ->read(buffer, processSamples);
+
+ // call effectProcessImpl without lock
+ IEffect::Status status = effectProcessImpl(buffer, buffer, processSamples);
+ outputMQ->write(buffer, status.fmqProduced);
+ statusMQ->writeBlocking(&status, 1);
+ LOG(DEBUG) << __func__ << " done processing, effect consumed " << status.fmqConsumed
+ << " produced " << status.fmqProduced;
+ } else {
+ // TODO: maybe add some sleep here to avoid busy waiting
+ }
+}
+
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/EngineConfigXmlConverter.cpp b/audio/aidl/default/EngineConfigXmlConverter.cpp
new file mode 100644
index 0000000..71b4b0e
--- /dev/null
+++ b/audio/aidl/default/EngineConfigXmlConverter.cpp
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fcntl.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include <functional>
+#include <unordered_map>
+
+#include <aidl/android/media/audio/common/AudioHalEngineConfig.h>
+
+#include "core-impl/EngineConfigXmlConverter.h"
+
+using aidl::android::media::audio::common::AudioAttributes;
+using aidl::android::media::audio::common::AudioContentType;
+using aidl::android::media::audio::common::AudioFlag;
+using aidl::android::media::audio::common::AudioHalAttributesGroup;
+using aidl::android::media::audio::common::AudioHalCapCriterion;
+using aidl::android::media::audio::common::AudioHalCapCriterionType;
+using aidl::android::media::audio::common::AudioHalEngineConfig;
+using aidl::android::media::audio::common::AudioHalProductStrategy;
+using aidl::android::media::audio::common::AudioHalVolumeCurve;
+using aidl::android::media::audio::common::AudioHalVolumeGroup;
+using aidl::android::media::audio::common::AudioProductStrategyType;
+using aidl::android::media::audio::common::AudioSource;
+using aidl::android::media::audio::common::AudioStreamType;
+using aidl::android::media::audio::common::AudioUsage;
+
+namespace xsd = android::audio::policy::engine::configuration;
+
+namespace aidl::android::hardware::audio::core::internal {
+
+/**
+ * Valid curve points take the form "<index>,<attenuationMb>", where the index
+ * must be in the range [0,100]. kInvalidCurvePointIndex is used to indicate
+ * that a point was formatted incorrectly (e.g. if a vendor accidentally typed a
+ * '.' instead of a ',' in their XML)-- using such a curve point will result in
+ * failed VTS tests.
+ */
+static const int8_t kInvalidCurvePointIndex = -1;
+
+void EngineConfigXmlConverter::initProductStrategyMap() {
+#define STRATEGY_ENTRY(name) {"STRATEGY_" #name, static_cast<int>(AudioProductStrategyType::name)}
+
+ mProductStrategyMap = {STRATEGY_ENTRY(MEDIA),
+ STRATEGY_ENTRY(PHONE),
+ STRATEGY_ENTRY(SONIFICATION),
+ STRATEGY_ENTRY(SONIFICATION_RESPECTFUL),
+ STRATEGY_ENTRY(DTMF),
+ STRATEGY_ENTRY(ENFORCED_AUDIBLE),
+ STRATEGY_ENTRY(TRANSMITTED_THROUGH_SPEAKER),
+ STRATEGY_ENTRY(ACCESSIBILITY)};
+#undef STRATEGY_ENTRY
+}
+
+int EngineConfigXmlConverter::convertProductStrategyNameToAidl(
+ const std::string& xsdcProductStrategyName) {
+ const auto [it, success] = mProductStrategyMap.insert(
+ std::make_pair(xsdcProductStrategyName, mNextVendorStrategy));
+ if (success) {
+ mNextVendorStrategy++;
+ }
+ return it->second;
+}
+
+bool isDefaultAudioAttributes(const AudioAttributes& attributes) {
+ return ((attributes.contentType == AudioContentType::UNKNOWN) &&
+ (attributes.usage == AudioUsage::UNKNOWN) &&
+ (attributes.source == AudioSource::DEFAULT) && (attributes.flags == 0) &&
+ (attributes.tags.empty()));
+}
+
+AudioAttributes EngineConfigXmlConverter::convertAudioAttributesToAidl(
+ const xsd::AttributesType& xsdcAudioAttributes) {
+ if (xsdcAudioAttributes.hasAttributesRef()) {
+ if (mAttributesReferenceMap.empty()) {
+ mAttributesReferenceMap =
+ generateReferenceMap<xsd::AttributesRef, xsd::AttributesRefType>(
+ getXsdcConfig()->getAttributesRef());
+ }
+ return convertAudioAttributesToAidl(
+ *(mAttributesReferenceMap.at(xsdcAudioAttributes.getAttributesRef())
+ .getFirstAttributes()));
+ }
+ AudioAttributes aidlAudioAttributes;
+ if (xsdcAudioAttributes.hasContentType()) {
+ aidlAudioAttributes.contentType = static_cast<AudioContentType>(
+ xsdcAudioAttributes.getFirstContentType()->getValue());
+ }
+ if (xsdcAudioAttributes.hasUsage()) {
+ aidlAudioAttributes.usage =
+ static_cast<AudioUsage>(xsdcAudioAttributes.getFirstUsage()->getValue());
+ }
+ if (xsdcAudioAttributes.hasSource()) {
+ aidlAudioAttributes.source =
+ static_cast<AudioSource>(xsdcAudioAttributes.getFirstSource()->getValue());
+ }
+ if (xsdcAudioAttributes.hasFlags()) {
+ std::vector<xsd::FlagType> xsdcFlagTypeVec =
+ xsdcAudioAttributes.getFirstFlags()->getValue();
+ for (const xsd::FlagType& xsdcFlagType : xsdcFlagTypeVec) {
+ if (xsdcFlagType != xsd::FlagType::AUDIO_FLAG_NONE) {
+ aidlAudioAttributes.flags |= 1 << (static_cast<int>(xsdcFlagType) - 1);
+ }
+ }
+ }
+ if (xsdcAudioAttributes.hasBundle()) {
+ const xsd::BundleType* xsdcBundle = xsdcAudioAttributes.getFirstBundle();
+ aidlAudioAttributes.tags[0] = xsdcBundle->getKey() + "=" + xsdcBundle->getValue();
+ }
+ if (isDefaultAudioAttributes(aidlAudioAttributes)) {
+ mDefaultProductStrategyId = std::optional<int>{-1};
+ }
+ return aidlAudioAttributes;
+}
+
+AudioHalAttributesGroup EngineConfigXmlConverter::convertAttributesGroupToAidl(
+ const xsd::AttributesGroup& xsdcAttributesGroup) {
+ AudioHalAttributesGroup aidlAttributesGroup;
+ static const int kStreamTypeEnumOffset =
+ static_cast<int>(xsd::Stream::AUDIO_STREAM_VOICE_CALL) -
+ static_cast<int>(AudioStreamType::VOICE_CALL);
+ aidlAttributesGroup.streamType = static_cast<AudioStreamType>(
+ static_cast<int>(xsdcAttributesGroup.getStreamType()) - kStreamTypeEnumOffset);
+ aidlAttributesGroup.volumeGroupName = xsdcAttributesGroup.getVolumeGroup();
+ if (xsdcAttributesGroup.hasAttributes_optional()) {
+ aidlAttributesGroup.attributes =
+ convertCollectionToAidl<xsd::AttributesType, AudioAttributes>(
+ xsdcAttributesGroup.getAttributes_optional(),
+ std::bind(&EngineConfigXmlConverter::convertAudioAttributesToAidl, this,
+ std::placeholders::_1));
+ } else if (xsdcAttributesGroup.hasContentType_optional() ||
+ xsdcAttributesGroup.hasUsage_optional() ||
+ xsdcAttributesGroup.hasSource_optional() ||
+ xsdcAttributesGroup.hasFlags_optional() ||
+ xsdcAttributesGroup.hasBundle_optional()) {
+ aidlAttributesGroup.attributes.push_back(convertAudioAttributesToAidl(xsd::AttributesType(
+ xsdcAttributesGroup.getContentType_optional(),
+ xsdcAttributesGroup.getUsage_optional(), xsdcAttributesGroup.getSource_optional(),
+ xsdcAttributesGroup.getFlags_optional(), xsdcAttributesGroup.getBundle_optional(),
+ std::nullopt)));
+
+ } else {
+ // do nothing;
+ // TODO: check if this is valid or if we should treat as an error.
+ // Currently, attributes are not mandatory in schema, but an AttributesGroup
+ // without attributes does not make much sense.
+ }
+ return aidlAttributesGroup;
+}
+
+AudioHalProductStrategy EngineConfigXmlConverter::convertProductStrategyToAidl(
+ const xsd::ProductStrategies::ProductStrategy& xsdcProductStrategy) {
+ AudioHalProductStrategy aidlProductStrategy;
+
+ aidlProductStrategy.id = convertProductStrategyNameToAidl(xsdcProductStrategy.getName());
+
+ if (xsdcProductStrategy.hasAttributesGroup()) {
+ aidlProductStrategy.attributesGroups =
+ convertCollectionToAidl<xsd::AttributesGroup, AudioHalAttributesGroup>(
+ xsdcProductStrategy.getAttributesGroup(),
+ std::bind(&EngineConfigXmlConverter::convertAttributesGroupToAidl, this,
+ std::placeholders::_1));
+ }
+ if ((mDefaultProductStrategyId != std::nullopt) && (mDefaultProductStrategyId.value() == -1)) {
+ mDefaultProductStrategyId = aidlProductStrategy.id;
+ }
+ return aidlProductStrategy;
+}
+
+AudioHalVolumeCurve::CurvePoint EngineConfigXmlConverter::convertCurvePointToAidl(
+ const std::string& xsdcCurvePoint) {
+ AudioHalVolumeCurve::CurvePoint aidlCurvePoint{};
+ if (sscanf(xsdcCurvePoint.c_str(), "%" SCNd8 ",%d", &aidlCurvePoint.index,
+ &aidlCurvePoint.attenuationMb) != 2) {
+ aidlCurvePoint.index = kInvalidCurvePointIndex;
+ }
+ return aidlCurvePoint;
+}
+
+AudioHalVolumeCurve EngineConfigXmlConverter::convertVolumeCurveToAidl(
+ const xsd::Volume& xsdcVolumeCurve) {
+ AudioHalVolumeCurve aidlVolumeCurve;
+ aidlVolumeCurve.deviceCategory =
+ static_cast<AudioHalVolumeCurve::DeviceCategory>(xsdcVolumeCurve.getDeviceCategory());
+ if (xsdcVolumeCurve.hasRef()) {
+ if (mVolumesReferenceMap.empty()) {
+ mVolumesReferenceMap = generateReferenceMap<xsd::VolumesType, xsd::VolumeRef>(
+ getXsdcConfig()->getVolumes());
+ }
+ aidlVolumeCurve.curvePoints =
+ convertCollectionToAidl<std::string, AudioHalVolumeCurve::CurvePoint>(
+ mVolumesReferenceMap.at(xsdcVolumeCurve.getRef()).getPoint(),
+ std::bind(&EngineConfigXmlConverter::convertCurvePointToAidl, this,
+ std::placeholders::_1));
+ } else {
+ aidlVolumeCurve.curvePoints =
+ convertCollectionToAidl<std::string, AudioHalVolumeCurve::CurvePoint>(
+ xsdcVolumeCurve.getPoint(),
+ std::bind(&EngineConfigXmlConverter::convertCurvePointToAidl, this,
+ std::placeholders::_1));
+ }
+ return aidlVolumeCurve;
+}
+
+AudioHalVolumeGroup EngineConfigXmlConverter::convertVolumeGroupToAidl(
+ const xsd::VolumeGroupsType::VolumeGroup& xsdcVolumeGroup) {
+ AudioHalVolumeGroup aidlVolumeGroup;
+ aidlVolumeGroup.name = xsdcVolumeGroup.getName();
+ aidlVolumeGroup.minIndex = xsdcVolumeGroup.getIndexMin();
+ aidlVolumeGroup.maxIndex = xsdcVolumeGroup.getIndexMax();
+ aidlVolumeGroup.volumeCurves = convertCollectionToAidl<xsd::Volume, AudioHalVolumeCurve>(
+ xsdcVolumeGroup.getVolume(),
+ std::bind(&EngineConfigXmlConverter::convertVolumeCurveToAidl, this,
+ std::placeholders::_1));
+ return aidlVolumeGroup;
+}
+
+AudioHalCapCriterion EngineConfigXmlConverter::convertCapCriterionToAidl(
+ const xsd::CriterionType& xsdcCriterion) {
+ AudioHalCapCriterion aidlCapCriterion;
+ aidlCapCriterion.name = xsdcCriterion.getName();
+ aidlCapCriterion.criterionTypeName = xsdcCriterion.getType();
+ aidlCapCriterion.defaultLiteralValue = xsdcCriterion.get_default();
+ return aidlCapCriterion;
+}
+
+std::string EngineConfigXmlConverter::convertCriterionTypeValueToAidl(
+ const xsd::ValueType& xsdcCriterionTypeValue) {
+ return xsdcCriterionTypeValue.getLiteral();
+}
+
+AudioHalCapCriterionType EngineConfigXmlConverter::convertCapCriterionTypeToAidl(
+ const xsd::CriterionTypeType& xsdcCriterionType) {
+ AudioHalCapCriterionType aidlCapCriterionType;
+ aidlCapCriterionType.name = xsdcCriterionType.getName();
+ aidlCapCriterionType.isInclusive = !(static_cast<bool>(xsdcCriterionType.getType()));
+ aidlCapCriterionType.values =
+ convertWrappedCollectionToAidl<xsd::ValuesType, xsd::ValueType, std::string>(
+ xsdcCriterionType.getValues(), &xsd::ValuesType::getValue,
+ std::bind(&EngineConfigXmlConverter::convertCriterionTypeValueToAidl, this,
+ std::placeholders::_1));
+ return aidlCapCriterionType;
+}
+
+AudioHalEngineConfig& EngineConfigXmlConverter::getAidlEngineConfig() {
+ return mAidlEngineConfig;
+}
+
+void EngineConfigXmlConverter::init() {
+ initProductStrategyMap();
+ if (getXsdcConfig()->hasProductStrategies()) {
+ mAidlEngineConfig.productStrategies =
+ convertWrappedCollectionToAidl<xsd::ProductStrategies,
+ xsd::ProductStrategies::ProductStrategy,
+ AudioHalProductStrategy>(
+ getXsdcConfig()->getProductStrategies(),
+ &xsd::ProductStrategies::getProductStrategy,
+ std::bind(&EngineConfigXmlConverter::convertProductStrategyToAidl, this,
+ std::placeholders::_1));
+ if (mDefaultProductStrategyId) {
+ mAidlEngineConfig.defaultProductStrategyId = mDefaultProductStrategyId.value();
+ }
+ }
+ if (getXsdcConfig()->hasVolumeGroups()) {
+ mAidlEngineConfig.volumeGroups = convertWrappedCollectionToAidl<
+ xsd::VolumeGroupsType, xsd::VolumeGroupsType::VolumeGroup, AudioHalVolumeGroup>(
+ getXsdcConfig()->getVolumeGroups(), &xsd::VolumeGroupsType::getVolumeGroup,
+ std::bind(&EngineConfigXmlConverter::convertVolumeGroupToAidl, this,
+ std::placeholders::_1));
+ }
+ if (getXsdcConfig()->hasCriteria() && getXsdcConfig()->hasCriterion_types()) {
+ AudioHalEngineConfig::CapSpecificConfig capSpecificConfig;
+ capSpecificConfig.criteria =
+ convertWrappedCollectionToAidl<xsd::CriteriaType, xsd::CriterionType,
+ AudioHalCapCriterion>(
+ getXsdcConfig()->getCriteria(), &xsd::CriteriaType::getCriterion,
+ std::bind(&EngineConfigXmlConverter::convertCapCriterionToAidl, this,
+ std::placeholders::_1));
+ capSpecificConfig.criterionTypes =
+ convertWrappedCollectionToAidl<xsd::CriterionTypesType, xsd::CriterionTypeType,
+ AudioHalCapCriterionType>(
+ getXsdcConfig()->getCriterion_types(),
+ &xsd::CriterionTypesType::getCriterion_type,
+ std::bind(&EngineConfigXmlConverter::convertCapCriterionTypeToAidl, this,
+ std::placeholders::_1));
+ mAidlEngineConfig.capSpecificConfig = capSpecificConfig;
+ }
+}
+} // namespace aidl::android::hardware::audio::core::internal
\ No newline at end of file
diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp
index 971d946..47d6fa4 100644
--- a/audio/aidl/default/Module.cpp
+++ b/audio/aidl/default/Module.cpp
@@ -238,7 +238,14 @@
internal::Configuration& Module::getConfig() {
if (!mConfig) {
- mConfig.reset(new internal::Configuration(internal::getNullPrimaryConfiguration()));
+ switch (mType) {
+ case Type::DEFAULT:
+ mConfig = std::move(internal::getPrimaryConfiguration());
+ break;
+ case Type::R_SUBMIX:
+ mConfig = std::move(internal::getRSubmixConfiguration());
+ break;
+ }
}
return *mConfig;
}
diff --git a/audio/aidl/default/android.hardware.audio.service-aidl.xml b/audio/aidl/default/android.hardware.audio.service-aidl.xml
index bb4b01a..46b665f 100644
--- a/audio/aidl/default/android.hardware.audio.service-aidl.xml
+++ b/audio/aidl/default/android.hardware.audio.service-aidl.xml
@@ -7,6 +7,11 @@
<hal format="aidl">
<name>android.hardware.audio.core</name>
<version>1</version>
+ <fqname>IModule/r_submix</fqname>
+ </hal>
+ <hal format="aidl">
+ <name>android.hardware.audio.core</name>
+ <version>1</version>
<fqname>IConfig/default</fqname>
</hal>
</manifest>
diff --git a/audio/aidl/default/bassboost/BassBoostSw.cpp b/audio/aidl/default/bassboost/BassBoostSw.cpp
index c52d16f..61976c8 100644
--- a/audio/aidl/default/bassboost/BassBoostSw.cpp
+++ b/audio/aidl/default/bassboost/BassBoostSw.cpp
@@ -14,10 +14,11 @@
* limitations under the License.
*/
+#include <algorithm>
#include <cstddef>
+#include <memory>
#define LOG_TAG "AHAL_BassBoostSw"
#include <Utils.h>
-#include <algorithm>
#include <unordered_set>
#include <android-base/logging.h>
@@ -26,6 +27,7 @@
#include "BassBoostSw.h"
using aidl::android::hardware::audio::effect::BassBoostSw;
+using aidl::android::hardware::audio::effect::Descriptor;
using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::hardware::audio::effect::kBassBoostSwImplUUID;
using aidl::android::hardware::audio::effect::State;
@@ -47,23 +49,31 @@
}
}
-extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
- if (!instanceSp) {
- return EX_NONE;
+extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) {
+ if (!in_impl_uuid || *in_impl_uuid != kBassBoostSwImplUUID) {
+ LOG(ERROR) << __func__ << "uuid not supported";
+ return EX_ILLEGAL_ARGUMENT;
}
- State state;
- ndk::ScopedAStatus status = instanceSp->getState(&state);
- if (!status.isOk() || State::INIT != state) {
- LOG(ERROR) << __func__ << " instance " << instanceSp.get()
- << " in state: " << toString(state) << ", status: " << status.getDescription();
- return EX_ILLEGAL_STATE;
- }
- LOG(DEBUG) << __func__ << " instance " << instanceSp.get() << " destroyed";
+ *_aidl_return = BassBoostSw::kDescriptor;
return EX_NONE;
}
namespace aidl::android::hardware::audio::effect {
+const std::string BassBoostSw::kEffectName = "BassBoostSw";
+const bool BassBoostSw::kStrengthSupported = true;
+const BassBoost::Capability BassBoostSw::kCapability = {.strengthSupported = kStrengthSupported};
+const Descriptor BassBoostSw::kDescriptor = {
+ .common = {.id = {.type = kBassBoostTypeUUID,
+ .uuid = kBassBoostSwImplUUID,
+ .proxy = std::nullopt},
+ .flags = {.type = Flags::Type::INSERT,
+ .insert = Flags::Insert::FIRST,
+ .volume = Flags::Volume::CTRL},
+ .name = BassBoostSw::kEffectName,
+ .implementor = "The Android Open Source Project"},
+ .capability = Capability::make<Capability::bassBoost>(BassBoostSw::kCapability)};
+
ndk::ScopedAStatus BassBoostSw::getDescriptor(Descriptor* _aidl_return) {
LOG(DEBUG) << __func__ << kDescriptor.toString();
*_aidl_return = kDescriptor;
@@ -73,28 +83,74 @@
ndk::ScopedAStatus BassBoostSw::setParameterSpecific(const Parameter::Specific& specific) {
RETURN_IF(Parameter::Specific::bassBoost != specific.getTag(), EX_ILLEGAL_ARGUMENT,
"EffectNotSupported");
- std::lock_guard lg(mMutex);
RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
- mSpecificParam = specific.get<Parameter::Specific::bassBoost>();
- LOG(DEBUG) << __func__ << " success with: " << specific.toString();
- return ndk::ScopedAStatus::ok();
+ auto& bbParam = specific.get<Parameter::Specific::bassBoost>();
+ auto tag = bbParam.getTag();
+
+ switch (tag) {
+ case BassBoost::strengthPm: {
+ RETURN_IF(!kStrengthSupported, EX_ILLEGAL_ARGUMENT, "SettingStrengthNotSupported");
+
+ RETURN_IF(mContext->setBbStrengthPm(bbParam.get<BassBoost::strengthPm>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "strengthPmNotSupported");
+ return ndk::ScopedAStatus::ok();
+ }
+ default: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "BassBoostTagNotSupported");
+ }
+ }
}
ndk::ScopedAStatus BassBoostSw::getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) {
auto tag = id.getTag();
RETURN_IF(Parameter::Id::bassBoostTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
- specific->set<Parameter::Specific::bassBoost>(mSpecificParam);
+ auto bbId = id.get<Parameter::Id::bassBoostTag>();
+ auto bbIdTag = bbId.getTag();
+ switch (bbIdTag) {
+ case BassBoost::Id::commonTag:
+ return getParameterBassBoost(bbId.get<BassBoost::Id::commonTag>(), specific);
+ default:
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "BassBoostTagNotSupported");
+ }
+}
+
+ndk::ScopedAStatus BassBoostSw::getParameterBassBoost(const BassBoost::Tag& tag,
+ Parameter::Specific* specific) {
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+ BassBoost bbParam;
+ switch (tag) {
+ case BassBoost::strengthPm: {
+ bbParam.set<BassBoost::strengthPm>(mContext->getBbStrengthPm());
+ break;
+ }
+ default: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "BassBoostTagNotSupported");
+ }
+ }
+
+ specific->set<Parameter::Specific::bassBoost>(bbParam);
return ndk::ScopedAStatus::ok();
}
std::shared_ptr<EffectContext> BassBoostSw::createContext(const Parameter::Common& common) {
if (mContext) {
LOG(DEBUG) << __func__ << " context already exist";
- return mContext;
+ } else {
+ mContext = std::make_shared<BassBoostSwContext>(1 /* statusFmqDepth */, common);
}
- mContext = std::make_shared<BassBoostSwContext>(1 /* statusFmqDepth */, common);
+ return mContext;
+}
+
+std::shared_ptr<EffectContext> BassBoostSw::getContext() {
return mContext;
}
@@ -106,13 +162,13 @@
}
// Processing method running in EffectWorker thread.
-IEffect::Status BassBoostSw::effectProcessImpl(float* in, float* out, int process) {
+IEffect::Status BassBoostSw::effectProcessImpl(float* in, float* out, int samples) {
// TODO: get data buffer and process.
- LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
- for (int i = 0; i < process; i++) {
+ LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
+ for (int i = 0; i < samples; i++) {
*out++ = *in++;
}
- return {STATUS_OK, process, process};
+ return {STATUS_OK, samples, samples};
}
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/bassboost/BassBoostSw.h b/audio/aidl/default/bassboost/BassBoostSw.h
index 90a8887..411b9c9 100644
--- a/audio/aidl/default/bassboost/BassBoostSw.h
+++ b/audio/aidl/default/bassboost/BassBoostSw.h
@@ -32,11 +32,29 @@
: EffectContext(statusDepth, common) {
LOG(DEBUG) << __func__;
}
- // TODO: add specific context here
+
+ RetCode setBbStrengthPm(int strength) {
+ if (strength < BassBoost::MIN_PER_MILLE_STRENGTH ||
+ strength > BassBoost::MAX_PER_MILLE_STRENGTH) {
+ LOG(ERROR) << __func__ << " invalid strength: " << strength;
+ return RetCode::ERROR_ILLEGAL_PARAMETER;
+ }
+ // TODO : Add implementation to apply new strength
+ mStrength = strength;
+ return RetCode::SUCCESS;
+ }
+ int getBbStrengthPm() const { return mStrength; }
+
+ private:
+ int mStrength;
};
class BassBoostSw final : public EffectImpl {
public:
+ static const std::string kEffectName;
+ static const bool kStrengthSupported;
+ static const BassBoost::Capability kCapability;
+ static const Descriptor kDescriptor;
BassBoostSw() { LOG(DEBUG) << __func__; }
~BassBoostSw() {
cleanUp();
@@ -47,27 +65,17 @@
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) override;
- IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+ std::shared_ptr<EffectContext> getContext() override;
RetCode releaseContext() override;
+ std::string getEffectName() override { return kEffectName; };
+ IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+
private:
std::shared_ptr<BassBoostSwContext> mContext;
- /* capabilities */
- const BassBoost::Capability kCapability;
- /* Effect descriptor */
- const Descriptor kDescriptor = {
- .common = {.id = {.type = kBassBoostTypeUUID,
- .uuid = kBassBoostSwImplUUID,
- .proxy = std::nullopt},
- .flags = {.type = Flags::Type::INSERT,
- .insert = Flags::Insert::FIRST,
- .volume = Flags::Volume::CTRL},
- .name = "BassBoostSw",
- .implementor = "The Android Open Source Project"},
- .capability = Capability::make<Capability::bassBoost>(kCapability)};
-
- /* parameters */
- BassBoost mSpecificParam;
+ ndk::ScopedAStatus getParameterBassBoost(const BassBoost::Tag& tag,
+ Parameter::Specific* specific);
};
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/config/audioPolicy/Android.bp b/audio/aidl/default/config/audioPolicy/Android.bp
new file mode 100644
index 0000000..6d8a148
--- /dev/null
+++ b/audio/aidl/default/config/audioPolicy/Android.bp
@@ -0,0 +1,15 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+xsd_config {
+ name: "audio_policy_configuration_aidl_default",
+ srcs: ["audio_policy_configuration.xsd"],
+ package_name: "android.audio.policy.configuration",
+ nullability: true,
+}
diff --git a/audio/aidl/default/config/audioPolicy/api/current.txt b/audio/aidl/default/config/audioPolicy/api/current.txt
new file mode 100644
index 0000000..c0ffe70
--- /dev/null
+++ b/audio/aidl/default/config/audioPolicy/api/current.txt
@@ -0,0 +1,607 @@
+// Signature format: 2.0
+package android.audio.policy.configuration {
+
+ public class AttachedDevices {
+ ctor public AttachedDevices();
+ method @Nullable public java.util.List<java.lang.String> getItem();
+ }
+
+ public enum AudioChannelMask {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_1;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_10;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_11;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_12;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_13;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_14;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_15;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_16;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_17;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_18;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_19;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_2;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_20;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_21;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_22;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_23;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_24;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_3;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_4;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_5;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_6;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_7;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_8;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_9;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_2POINT0POINT2;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_2POINT1POINT2;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_3POINT0POINT2;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_3POINT1POINT2;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_5POINT1;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_6;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_FRONT_BACK;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_MONO;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_STEREO;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_VOICE_CALL_MONO;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_VOICE_DNLINK_MONO;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_VOICE_UPLINK_MONO;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_NONE;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_13POINT_360RA;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_22POINT2;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_2POINT0POINT2;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_2POINT1;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_2POINT1POINT2;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_3POINT0POINT2;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_3POINT1;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_3POINT1POINT2;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_5POINT1;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_5POINT1POINT2;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_5POINT1POINT4;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_5POINT1_BACK;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_5POINT1_SIDE;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_6POINT1;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_7POINT1;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_7POINT1POINT2;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_7POINT1POINT4;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_9POINT1POINT4;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_9POINT1POINT6;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_HAPTIC_AB;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_MONO;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_MONO_HAPTIC_A;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_MONO_HAPTIC_AB;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_PENTA;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_QUAD;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_QUAD_BACK;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_QUAD_SIDE;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_STEREO;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_STEREO_HAPTIC_A;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_STEREO_HAPTIC_AB;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_SURROUND;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_TRI;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_TRI_BACK;
+ }
+
+ public enum AudioContentType {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.AudioContentType AUDIO_CONTENT_TYPE_MOVIE;
+ enum_constant public static final android.audio.policy.configuration.AudioContentType AUDIO_CONTENT_TYPE_MUSIC;
+ enum_constant public static final android.audio.policy.configuration.AudioContentType AUDIO_CONTENT_TYPE_SONIFICATION;
+ enum_constant public static final android.audio.policy.configuration.AudioContentType AUDIO_CONTENT_TYPE_SPEECH;
+ enum_constant public static final android.audio.policy.configuration.AudioContentType AUDIO_CONTENT_TYPE_ULTRASOUND;
+ enum_constant public static final android.audio.policy.configuration.AudioContentType AUDIO_CONTENT_TYPE_UNKNOWN;
+ }
+
+ public enum AudioDevice {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_AMBIENT;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_AUX_DIGITAL;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_BACK_MIC;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_BLE_HEADSET;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_BLUETOOTH_A2DP;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_BLUETOOTH_BLE;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_BUILTIN_MIC;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_BUS;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_COMMUNICATION;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_DEFAULT;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_ECHO_REFERENCE;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_FM_TUNER;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_HDMI;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_HDMI_ARC;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_HDMI_EARC;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_IP;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_LINE;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_LOOPBACK;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_PROXY;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_REMOTE_SUBMIX;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_SPDIF;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_STUB;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_TELEPHONY_RX;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_TV_TUNER;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_USB_ACCESSORY;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_USB_DEVICE;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_USB_HEADSET;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_VOICE_CALL;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_WIRED_HEADSET;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_NONE;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_AUX_DIGITAL;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_AUX_LINE;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_BLE_BROADCAST;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_BLE_HEADSET;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_BLE_SPEAKER;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_SCO;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_BUS;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_DEFAULT;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_EARPIECE;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_ECHO_CANCELLER;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_FM;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_HDMI;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_HDMI_ARC;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_HDMI_EARC;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_HEARING_AID;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_IP;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_LINE;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_PROXY;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_SPDIF;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_SPEAKER;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_SPEAKER_SAFE;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_STUB;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_TELEPHONY_TX;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_USB_ACCESSORY;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_USB_DEVICE;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_USB_HEADSET;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_WIRED_HEADSET;
+ }
+
+ public enum AudioEncapsulationType {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.AudioEncapsulationType AUDIO_ENCAPSULATION_TYPE_IEC61937;
+ enum_constant public static final android.audio.policy.configuration.AudioEncapsulationType AUDIO_ENCAPSULATION_TYPE_NONE;
+ }
+
+ public enum AudioFormat {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_ADIF;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_ADTS;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_ADTS_ELD;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_ADTS_ERLC;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_ADTS_HE_V1;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_ADTS_HE_V2;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_ADTS_LC;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_ADTS_LD;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_ADTS_LTP;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_ADTS_MAIN;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_ADTS_SCALABLE;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_ADTS_SSR;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_ADTS_XHE;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_ELD;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_ERLC;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_HE_V1;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_HE_V2;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_LATM;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_LATM_HE_V1;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_LATM_HE_V2;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_LATM_LC;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_LC;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_LD;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_LTP;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_MAIN;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_SCALABLE;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_SSR;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_XHE;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AC3;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AC4;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_ALAC;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AMR_NB;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AMR_WB;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AMR_WB_PLUS;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_APE;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_APTX;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_APTX_ADAPTIVE;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_APTX_ADAPTIVE_QLEA;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_APTX_ADAPTIVE_R4;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_APTX_HD;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_APTX_TWSP;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_CELT;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_DEFAULT;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_DOLBY_TRUEHD;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_DRA;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_DSD;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_DTS;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_DTS_HD;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_DTS_HD_MA;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_DTS_UHD;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_DTS_UHD_P2;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_EVRC;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_EVRCB;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_EVRCNW;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_EVRCWB;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_E_AC3;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_E_AC3_JOC;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_FLAC;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_HE_AAC_V1;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_HE_AAC_V2;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_IEC60958;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_IEC61937;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_LC3;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_LDAC;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_LHDC;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_LHDC_LL;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_MAT;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_MAT_1_0;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_MAT_2_0;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_MAT_2_1;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_MP2;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_MP3;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_MPEGH_BL_L3;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_MPEGH_BL_L4;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_MPEGH_LC_L3;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_MPEGH_LC_L4;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_OPUS;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_PCM_16_BIT;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_PCM_24_BIT_PACKED;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_PCM_32_BIT;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_PCM_8_24_BIT;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_PCM_8_BIT;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_PCM_FLOAT;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_QCELP;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_SBC;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_VORBIS;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_WMA;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_WMA_PRO;
+ }
+
+ public enum AudioGainMode {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.AudioGainMode AUDIO_GAIN_MODE_CHANNELS;
+ enum_constant public static final android.audio.policy.configuration.AudioGainMode AUDIO_GAIN_MODE_JOINT;
+ enum_constant public static final android.audio.policy.configuration.AudioGainMode AUDIO_GAIN_MODE_RAMP;
+ }
+
+ public enum AudioInOutFlag {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_INPUT_FLAG_DIRECT;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_INPUT_FLAG_FAST;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_INPUT_FLAG_HW_AV_SYNC;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_INPUT_FLAG_HW_HOTWORD;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_INPUT_FLAG_MMAP_NOIRQ;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_INPUT_FLAG_RAW;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_INPUT_FLAG_SYNC;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_INPUT_FLAG_ULTRASOUND;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_INPUT_FLAG_VOIP_TX;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_DIRECT;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_DIRECT_PCM;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_FAST;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_GAPLESS_OFFLOAD;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_HW_AV_SYNC;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_INCALL_MUSIC;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_MMAP_NOIRQ;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_NON_BLOCKING;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_PRIMARY;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_RAW;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_SPATIALIZER;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_SYNC;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_TTS;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_ULTRASOUND;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_VOIP_RX;
+ }
+
+ public class AudioPolicyConfiguration {
+ ctor public AudioPolicyConfiguration();
+ method @Nullable public android.audio.policy.configuration.GlobalConfiguration getGlobalConfiguration();
+ method @Nullable public java.util.List<android.audio.policy.configuration.Modules> getModules();
+ method @Nullable public android.audio.policy.configuration.SurroundSound getSurroundSound();
+ method @Nullable public android.audio.policy.configuration.Version getVersion();
+ method @Nullable public java.util.List<android.audio.policy.configuration.Volumes> getVolumes();
+ method public void setGlobalConfiguration(@Nullable android.audio.policy.configuration.GlobalConfiguration);
+ method public void setSurroundSound(@Nullable android.audio.policy.configuration.SurroundSound);
+ method public void setVersion(@Nullable android.audio.policy.configuration.Version);
+ }
+
+ public enum AudioSource {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.AudioSource AUDIO_SOURCE_CAMCORDER;
+ enum_constant public static final android.audio.policy.configuration.AudioSource AUDIO_SOURCE_DEFAULT;
+ enum_constant public static final android.audio.policy.configuration.AudioSource AUDIO_SOURCE_ECHO_REFERENCE;
+ enum_constant public static final android.audio.policy.configuration.AudioSource AUDIO_SOURCE_FM_TUNER;
+ enum_constant public static final android.audio.policy.configuration.AudioSource AUDIO_SOURCE_HOTWORD;
+ enum_constant public static final android.audio.policy.configuration.AudioSource AUDIO_SOURCE_MIC;
+ enum_constant public static final android.audio.policy.configuration.AudioSource AUDIO_SOURCE_REMOTE_SUBMIX;
+ enum_constant public static final android.audio.policy.configuration.AudioSource AUDIO_SOURCE_ULTRASOUND;
+ enum_constant public static final android.audio.policy.configuration.AudioSource AUDIO_SOURCE_UNPROCESSED;
+ enum_constant public static final android.audio.policy.configuration.AudioSource AUDIO_SOURCE_VOICE_CALL;
+ enum_constant public static final android.audio.policy.configuration.AudioSource AUDIO_SOURCE_VOICE_COMMUNICATION;
+ enum_constant public static final android.audio.policy.configuration.AudioSource AUDIO_SOURCE_VOICE_DOWNLINK;
+ enum_constant public static final android.audio.policy.configuration.AudioSource AUDIO_SOURCE_VOICE_PERFORMANCE;
+ enum_constant public static final android.audio.policy.configuration.AudioSource AUDIO_SOURCE_VOICE_RECOGNITION;
+ enum_constant public static final android.audio.policy.configuration.AudioSource AUDIO_SOURCE_VOICE_UPLINK;
+ }
+
+ public enum AudioStreamType {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.AudioStreamType AUDIO_STREAM_ACCESSIBILITY;
+ enum_constant public static final android.audio.policy.configuration.AudioStreamType AUDIO_STREAM_ALARM;
+ enum_constant public static final android.audio.policy.configuration.AudioStreamType AUDIO_STREAM_ASSISTANT;
+ enum_constant public static final android.audio.policy.configuration.AudioStreamType AUDIO_STREAM_BLUETOOTH_SCO;
+ enum_constant public static final android.audio.policy.configuration.AudioStreamType AUDIO_STREAM_CALL_ASSISTANT;
+ enum_constant public static final android.audio.policy.configuration.AudioStreamType AUDIO_STREAM_DTMF;
+ enum_constant public static final android.audio.policy.configuration.AudioStreamType AUDIO_STREAM_ENFORCED_AUDIBLE;
+ enum_constant public static final android.audio.policy.configuration.AudioStreamType AUDIO_STREAM_MUSIC;
+ enum_constant public static final android.audio.policy.configuration.AudioStreamType AUDIO_STREAM_NOTIFICATION;
+ enum_constant public static final android.audio.policy.configuration.AudioStreamType AUDIO_STREAM_PATCH;
+ enum_constant public static final android.audio.policy.configuration.AudioStreamType AUDIO_STREAM_REROUTING;
+ enum_constant public static final android.audio.policy.configuration.AudioStreamType AUDIO_STREAM_RING;
+ enum_constant public static final android.audio.policy.configuration.AudioStreamType AUDIO_STREAM_SYSTEM;
+ enum_constant public static final android.audio.policy.configuration.AudioStreamType AUDIO_STREAM_TTS;
+ enum_constant public static final android.audio.policy.configuration.AudioStreamType AUDIO_STREAM_VOICE_CALL;
+ }
+
+ public enum AudioUsage {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_ALARM;
+ enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_ANNOUNCEMENT;
+ enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY;
+ enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
+ enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_ASSISTANCE_SONIFICATION;
+ enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_ASSISTANT;
+ enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_CALL_ASSISTANT;
+ enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_EMERGENCY;
+ enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_GAME;
+ enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_MEDIA;
+ enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_NOTIFICATION;
+ enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_NOTIFICATION_EVENT;
+ enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE;
+ enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_SAFETY;
+ enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_UNKNOWN;
+ enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_VEHICLE_STATUS;
+ enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_VIRTUAL_SOURCE;
+ enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_VOICE_COMMUNICATION;
+ enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING;
+ }
+
+ public enum DeviceCategory {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.DeviceCategory DEVICE_CATEGORY_EARPIECE;
+ enum_constant public static final android.audio.policy.configuration.DeviceCategory DEVICE_CATEGORY_EXT_MEDIA;
+ enum_constant public static final android.audio.policy.configuration.DeviceCategory DEVICE_CATEGORY_HEADSET;
+ enum_constant public static final android.audio.policy.configuration.DeviceCategory DEVICE_CATEGORY_HEARING_AID;
+ enum_constant public static final android.audio.policy.configuration.DeviceCategory DEVICE_CATEGORY_SPEAKER;
+ }
+
+ public class DevicePorts {
+ ctor public DevicePorts();
+ method @Nullable public java.util.List<android.audio.policy.configuration.DevicePorts.DevicePort> getDevicePort();
+ }
+
+ public static class DevicePorts.DevicePort {
+ ctor public DevicePorts.DevicePort();
+ method @Nullable public String getAddress();
+ method @Nullable public java.util.List<java.lang.String> getEncodedFormats();
+ method @Nullable public android.audio.policy.configuration.Gains getGains();
+ method @Nullable public java.util.List<android.audio.policy.configuration.Profile> getProfile();
+ method @Nullable public android.audio.policy.configuration.Role getRole();
+ method @Nullable public String getTagName();
+ method @Nullable public String getType();
+ method @Nullable public boolean get_default();
+ method public void setAddress(@Nullable String);
+ method public void setEncodedFormats(@Nullable java.util.List<java.lang.String>);
+ method public void setGains(@Nullable android.audio.policy.configuration.Gains);
+ method public void setRole(@Nullable android.audio.policy.configuration.Role);
+ method public void setTagName(@Nullable String);
+ method public void setType(@Nullable String);
+ method public void set_default(@Nullable boolean);
+ }
+
+ public enum EngineSuffix {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.EngineSuffix _default;
+ enum_constant public static final android.audio.policy.configuration.EngineSuffix configurable;
+ }
+
+ public class Gains {
+ ctor public Gains();
+ method @Nullable public java.util.List<android.audio.policy.configuration.Gains.Gain> getGain();
+ }
+
+ public static class Gains.Gain {
+ ctor public Gains.Gain();
+ method @Nullable public android.audio.policy.configuration.AudioChannelMask getChannel_mask();
+ method @Nullable public int getDefaultValueMB();
+ method @Nullable public int getMaxRampMs();
+ method @Nullable public int getMaxValueMB();
+ method @Nullable public int getMinRampMs();
+ method @Nullable public int getMinValueMB();
+ method @Nullable public java.util.List<android.audio.policy.configuration.AudioGainMode> getMode();
+ method @Nullable public String getName();
+ method @Nullable public int getStepValueMB();
+ method @Nullable public boolean getUseForVolume();
+ method public void setChannel_mask(@Nullable android.audio.policy.configuration.AudioChannelMask);
+ method public void setDefaultValueMB(@Nullable int);
+ method public void setMaxRampMs(@Nullable int);
+ method public void setMaxValueMB(@Nullable int);
+ method public void setMinRampMs(@Nullable int);
+ method public void setMinValueMB(@Nullable int);
+ method public void setMode(@Nullable java.util.List<android.audio.policy.configuration.AudioGainMode>);
+ method public void setName(@Nullable String);
+ method public void setStepValueMB(@Nullable int);
+ method public void setUseForVolume(@Nullable boolean);
+ }
+
+ public class GlobalConfiguration {
+ ctor public GlobalConfiguration();
+ method @Nullable public boolean getCall_screen_mode_supported();
+ method @Nullable public android.audio.policy.configuration.EngineSuffix getEngine_library();
+ method @Nullable public boolean getSpeaker_drc_enabled();
+ method public void setCall_screen_mode_supported(@Nullable boolean);
+ method public void setEngine_library(@Nullable android.audio.policy.configuration.EngineSuffix);
+ method public void setSpeaker_drc_enabled(@Nullable boolean);
+ }
+
+ public enum HalVersion {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.HalVersion _2_0;
+ enum_constant public static final android.audio.policy.configuration.HalVersion _3_0;
+ }
+
+ public class MixPorts {
+ ctor public MixPorts();
+ method @Nullable public java.util.List<android.audio.policy.configuration.MixPorts.MixPort> getMixPort();
+ }
+
+ public static class MixPorts.MixPort {
+ ctor public MixPorts.MixPort();
+ method @Nullable public java.util.List<android.audio.policy.configuration.AudioInOutFlag> getFlags();
+ method @Nullable public android.audio.policy.configuration.Gains getGains();
+ method @Nullable public long getMaxActiveCount();
+ method @Nullable public long getMaxOpenCount();
+ method @Nullable public String getName();
+ method @Nullable public java.util.List<android.audio.policy.configuration.AudioUsage> getPreferredUsage();
+ method @Nullable public java.util.List<android.audio.policy.configuration.Profile> getProfile();
+ method @Nullable public long getRecommendedMuteDurationMs();
+ method @Nullable public android.audio.policy.configuration.Role getRole();
+ method public void setFlags(@Nullable java.util.List<android.audio.policy.configuration.AudioInOutFlag>);
+ method public void setGains(@Nullable android.audio.policy.configuration.Gains);
+ method public void setMaxActiveCount(@Nullable long);
+ method public void setMaxOpenCount(@Nullable long);
+ method public void setName(@Nullable String);
+ method public void setPreferredUsage(@Nullable java.util.List<android.audio.policy.configuration.AudioUsage>);
+ method public void setRecommendedMuteDurationMs(@Nullable long);
+ method public void setRole(@Nullable android.audio.policy.configuration.Role);
+ }
+
+ public enum MixType {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.MixType mix;
+ enum_constant public static final android.audio.policy.configuration.MixType mux;
+ }
+
+ public class Modules {
+ ctor public Modules();
+ method @Nullable public java.util.List<android.audio.policy.configuration.Modules.Module> getModule();
+ }
+
+ public static class Modules.Module {
+ ctor public Modules.Module();
+ method @Nullable public android.audio.policy.configuration.AttachedDevices getAttachedDevices();
+ method @Nullable public String getDefaultOutputDevice();
+ method @Nullable public android.audio.policy.configuration.DevicePorts getDevicePorts();
+ method @Nullable public android.audio.policy.configuration.HalVersion getHalVersion();
+ method @Nullable public android.audio.policy.configuration.MixPorts getMixPorts();
+ method @Nullable public String getName();
+ method @Nullable public android.audio.policy.configuration.Routes getRoutes();
+ method public void setAttachedDevices(@Nullable android.audio.policy.configuration.AttachedDevices);
+ method public void setDefaultOutputDevice(@Nullable String);
+ method public void setDevicePorts(@Nullable android.audio.policy.configuration.DevicePorts);
+ method public void setHalVersion(@Nullable android.audio.policy.configuration.HalVersion);
+ method public void setMixPorts(@Nullable android.audio.policy.configuration.MixPorts);
+ method public void setName(@Nullable String);
+ method public void setRoutes(@Nullable android.audio.policy.configuration.Routes);
+ }
+
+ public class Profile {
+ ctor public Profile();
+ method @Nullable public java.util.List<android.audio.policy.configuration.AudioChannelMask> getChannelMasks();
+ method @Nullable public android.audio.policy.configuration.AudioEncapsulationType getEncapsulationType();
+ method @Nullable public String getFormat();
+ method @Nullable public String getName();
+ method @Nullable public java.util.List<java.math.BigInteger> getSamplingRates();
+ method public void setChannelMasks(@Nullable java.util.List<android.audio.policy.configuration.AudioChannelMask>);
+ method public void setEncapsulationType(@Nullable android.audio.policy.configuration.AudioEncapsulationType);
+ method public void setFormat(@Nullable String);
+ method public void setName(@Nullable String);
+ method public void setSamplingRates(@Nullable java.util.List<java.math.BigInteger>);
+ }
+
+ public class Reference {
+ ctor public Reference();
+ method @Nullable public String getName();
+ method @Nullable public java.util.List<java.lang.String> getPoint();
+ method public void setName(@Nullable String);
+ }
+
+ public enum Role {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.Role sink;
+ enum_constant public static final android.audio.policy.configuration.Role source;
+ }
+
+ public class Routes {
+ ctor public Routes();
+ method @Nullable public java.util.List<android.audio.policy.configuration.Routes.Route> getRoute();
+ }
+
+ public static class Routes.Route {
+ ctor public Routes.Route();
+ method @Nullable public String getSink();
+ method @Nullable public String getSources();
+ method @Nullable public android.audio.policy.configuration.MixType getType();
+ method public void setSink(@Nullable String);
+ method public void setSources(@Nullable String);
+ method public void setType(@Nullable android.audio.policy.configuration.MixType);
+ }
+
+ public class SurroundFormats {
+ ctor public SurroundFormats();
+ method @Nullable public java.util.List<android.audio.policy.configuration.SurroundFormats.Format> getFormat();
+ }
+
+ public static class SurroundFormats.Format {
+ ctor public SurroundFormats.Format();
+ method @Nullable public String getName();
+ method @Nullable public java.util.List<java.lang.String> getSubformats();
+ method public void setName(@Nullable String);
+ method public void setSubformats(@Nullable java.util.List<java.lang.String>);
+ }
+
+ public class SurroundSound {
+ ctor public SurroundSound();
+ method @Nullable public android.audio.policy.configuration.SurroundFormats getFormats();
+ method public void setFormats(@Nullable android.audio.policy.configuration.SurroundFormats);
+ }
+
+ public enum Version {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.Version _7_0;
+ enum_constant public static final android.audio.policy.configuration.Version _7_1;
+ }
+
+ public class Volume {
+ ctor public Volume();
+ method @Nullable public android.audio.policy.configuration.DeviceCategory getDeviceCategory();
+ method @Nullable public java.util.List<java.lang.String> getPoint();
+ method @Nullable public String getRef();
+ method @Nullable public android.audio.policy.configuration.AudioStreamType getStream();
+ method public void setDeviceCategory(@Nullable android.audio.policy.configuration.DeviceCategory);
+ method public void setRef(@Nullable String);
+ method public void setStream(@Nullable android.audio.policy.configuration.AudioStreamType);
+ }
+
+ public class Volumes {
+ ctor public Volumes();
+ method @Nullable public java.util.List<android.audio.policy.configuration.Reference> getReference();
+ method @Nullable public java.util.List<android.audio.policy.configuration.Volume> getVolume();
+ }
+
+ public class XmlParser {
+ ctor public XmlParser();
+ method @Nullable public static android.audio.policy.configuration.AudioPolicyConfiguration read(@NonNull java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method @Nullable public static String readText(@NonNull org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static void skip(@NonNull org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ }
+
+}
+
diff --git a/audio/aidl/default/config/audioPolicy/api/last_current.txt b/audio/aidl/default/config/audioPolicy/api/last_current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/audio/aidl/default/config/audioPolicy/api/last_current.txt
diff --git a/audio/aidl/default/config/audioPolicy/api/last_removed.txt b/audio/aidl/default/config/audioPolicy/api/last_removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/audio/aidl/default/config/audioPolicy/api/last_removed.txt
diff --git a/audio/aidl/default/config/audioPolicy/api/removed.txt b/audio/aidl/default/config/audioPolicy/api/removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/audio/aidl/default/config/audioPolicy/api/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/audio/aidl/default/config/audio_policy_configuration.xsd b/audio/aidl/default/config/audioPolicy/audio_policy_configuration.xsd
similarity index 100%
rename from audio/aidl/default/config/audio_policy_configuration.xsd
rename to audio/aidl/default/config/audioPolicy/audio_policy_configuration.xsd
diff --git a/audio/aidl/default/config/audioPolicy/engine/Android.bp b/audio/aidl/default/config/audioPolicy/engine/Android.bp
new file mode 100644
index 0000000..b2a7310
--- /dev/null
+++ b/audio/aidl/default/config/audioPolicy/engine/Android.bp
@@ -0,0 +1,15 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+xsd_config {
+ name: "audio_policy_engine_configuration_aidl_default",
+ srcs: ["audio_policy_engine_configuration.xsd"],
+ package_name: "android.audio.policy.engine.configuration",
+ nullability: true,
+}
diff --git a/audio/aidl/default/config/audioPolicy/engine/api/current.txt b/audio/aidl/default/config/audioPolicy/engine/api/current.txt
new file mode 100644
index 0000000..59574f3
--- /dev/null
+++ b/audio/aidl/default/config/audioPolicy/engine/api/current.txt
@@ -0,0 +1,302 @@
+// Signature format: 2.0
+package android.audio.policy.engine.configuration {
+
+ public class AttributesGroup {
+ ctor public AttributesGroup();
+ method @Nullable public java.util.List<android.audio.policy.engine.configuration.AttributesType> getAttributes_optional();
+ method @Nullable public android.audio.policy.engine.configuration.BundleType getBundle_optional();
+ method @Nullable public android.audio.policy.engine.configuration.ContentTypeType getContentType_optional();
+ method @Nullable public android.audio.policy.engine.configuration.FlagsType getFlags_optional();
+ method @Nullable public android.audio.policy.engine.configuration.SourceType getSource_optional();
+ method @Nullable public android.audio.policy.engine.configuration.Stream getStreamType();
+ method @Nullable public android.audio.policy.engine.configuration.UsageType getUsage_optional();
+ method @Nullable public String getVolumeGroup();
+ method public void setBundle_optional(@Nullable android.audio.policy.engine.configuration.BundleType);
+ method public void setContentType_optional(@Nullable android.audio.policy.engine.configuration.ContentTypeType);
+ method public void setFlags_optional(@Nullable android.audio.policy.engine.configuration.FlagsType);
+ method public void setSource_optional(@Nullable android.audio.policy.engine.configuration.SourceType);
+ method public void setStreamType(@Nullable android.audio.policy.engine.configuration.Stream);
+ method public void setUsage_optional(@Nullable android.audio.policy.engine.configuration.UsageType);
+ method public void setVolumeGroup(@Nullable String);
+ }
+
+ public class AttributesRef {
+ ctor public AttributesRef();
+ method @Nullable public java.util.List<android.audio.policy.engine.configuration.AttributesRefType> getReference();
+ }
+
+ public class AttributesRefType {
+ ctor public AttributesRefType();
+ method @Nullable public android.audio.policy.engine.configuration.AttributesType getAttributes();
+ method @Nullable public String getName();
+ method public void setAttributes(@Nullable android.audio.policy.engine.configuration.AttributesType);
+ method public void setName(@Nullable String);
+ }
+
+ public class AttributesType {
+ ctor public AttributesType();
+ method @Nullable public String getAttributesRef();
+ method @Nullable public android.audio.policy.engine.configuration.BundleType getBundle();
+ method @Nullable public android.audio.policy.engine.configuration.ContentTypeType getContentType();
+ method @Nullable public android.audio.policy.engine.configuration.FlagsType getFlags();
+ method @Nullable public android.audio.policy.engine.configuration.SourceType getSource();
+ method @Nullable public android.audio.policy.engine.configuration.UsageType getUsage();
+ method public void setAttributesRef(@Nullable String);
+ method public void setBundle(@Nullable android.audio.policy.engine.configuration.BundleType);
+ method public void setContentType(@Nullable android.audio.policy.engine.configuration.ContentTypeType);
+ method public void setFlags(@Nullable android.audio.policy.engine.configuration.FlagsType);
+ method public void setSource(@Nullable android.audio.policy.engine.configuration.SourceType);
+ method public void setUsage(@Nullable android.audio.policy.engine.configuration.UsageType);
+ }
+
+ public class BundleType {
+ ctor public BundleType();
+ method @Nullable public String getKey();
+ method @Nullable public String getValue();
+ method public void setKey(@Nullable String);
+ method public void setValue(@Nullable String);
+ }
+
+ public class Configuration {
+ ctor public Configuration();
+ method @Nullable public java.util.List<android.audio.policy.engine.configuration.AttributesRef> getAttributesRef();
+ method @Nullable public java.util.List<android.audio.policy.engine.configuration.CriteriaType> getCriteria();
+ method @Nullable public java.util.List<android.audio.policy.engine.configuration.CriterionTypesType> getCriterion_types();
+ method @Nullable public java.util.List<android.audio.policy.engine.configuration.ProductStrategies> getProductStrategies();
+ method @Nullable public android.audio.policy.engine.configuration.Version getVersion();
+ method @Nullable public java.util.List<android.audio.policy.engine.configuration.VolumeGroupsType> getVolumeGroups();
+ method @Nullable public java.util.List<android.audio.policy.engine.configuration.VolumesType> getVolumes();
+ method public void setVersion(@Nullable android.audio.policy.engine.configuration.Version);
+ }
+
+ public enum ContentType {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.engine.configuration.ContentType AUDIO_CONTENT_TYPE_MOVIE;
+ enum_constant public static final android.audio.policy.engine.configuration.ContentType AUDIO_CONTENT_TYPE_MUSIC;
+ enum_constant public static final android.audio.policy.engine.configuration.ContentType AUDIO_CONTENT_TYPE_SONIFICATION;
+ enum_constant public static final android.audio.policy.engine.configuration.ContentType AUDIO_CONTENT_TYPE_SPEECH;
+ enum_constant public static final android.audio.policy.engine.configuration.ContentType AUDIO_CONTENT_TYPE_UNKNOWN;
+ }
+
+ public class ContentTypeType {
+ ctor public ContentTypeType();
+ method @Nullable public android.audio.policy.engine.configuration.ContentType getValue();
+ method public void setValue(@Nullable android.audio.policy.engine.configuration.ContentType);
+ }
+
+ public class CriteriaType {
+ ctor public CriteriaType();
+ method @Nullable public java.util.List<android.audio.policy.engine.configuration.CriterionType> getCriterion();
+ }
+
+ public class CriterionType {
+ ctor public CriterionType();
+ method @Nullable public String getName();
+ method @Nullable public String getType();
+ method @Nullable public String get_default();
+ method public void setName(@Nullable String);
+ method public void setType(@Nullable String);
+ method public void set_default(@Nullable String);
+ }
+
+ public class CriterionTypeType {
+ ctor public CriterionTypeType();
+ method @Nullable public String getName();
+ method @Nullable public android.audio.policy.engine.configuration.PfwCriterionTypeEnum getType();
+ method @Nullable public android.audio.policy.engine.configuration.ValuesType getValues();
+ method public void setName(@Nullable String);
+ method public void setType(@Nullable android.audio.policy.engine.configuration.PfwCriterionTypeEnum);
+ method public void setValues(@Nullable android.audio.policy.engine.configuration.ValuesType);
+ }
+
+ public class CriterionTypesType {
+ ctor public CriterionTypesType();
+ method @Nullable public java.util.List<android.audio.policy.engine.configuration.CriterionTypeType> getCriterion_type();
+ }
+
+ public enum DeviceCategory {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.engine.configuration.DeviceCategory DEVICE_CATEGORY_EARPIECE;
+ enum_constant public static final android.audio.policy.engine.configuration.DeviceCategory DEVICE_CATEGORY_EXT_MEDIA;
+ enum_constant public static final android.audio.policy.engine.configuration.DeviceCategory DEVICE_CATEGORY_HEADSET;
+ enum_constant public static final android.audio.policy.engine.configuration.DeviceCategory DEVICE_CATEGORY_HEARING_AID;
+ enum_constant public static final android.audio.policy.engine.configuration.DeviceCategory DEVICE_CATEGORY_SPEAKER;
+ }
+
+ public enum FlagType {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.engine.configuration.FlagType AUDIO_FLAG_AUDIBILITY_ENFORCED;
+ enum_constant public static final android.audio.policy.engine.configuration.FlagType AUDIO_FLAG_BEACON;
+ enum_constant public static final android.audio.policy.engine.configuration.FlagType AUDIO_FLAG_BYPASS_INTERRUPTION_POLICY;
+ enum_constant public static final android.audio.policy.engine.configuration.FlagType AUDIO_FLAG_BYPASS_MUTE;
+ enum_constant public static final android.audio.policy.engine.configuration.FlagType AUDIO_FLAG_CAPTURE_PRIVATE;
+ enum_constant public static final android.audio.policy.engine.configuration.FlagType AUDIO_FLAG_DEEP_BUFFER;
+ enum_constant public static final android.audio.policy.engine.configuration.FlagType AUDIO_FLAG_HW_AV_SYNC;
+ enum_constant public static final android.audio.policy.engine.configuration.FlagType AUDIO_FLAG_HW_HOTWORD;
+ enum_constant public static final android.audio.policy.engine.configuration.FlagType AUDIO_FLAG_LOW_LATENCY;
+ enum_constant public static final android.audio.policy.engine.configuration.FlagType AUDIO_FLAG_MUTE_HAPTIC;
+ enum_constant public static final android.audio.policy.engine.configuration.FlagType AUDIO_FLAG_NONE;
+ enum_constant public static final android.audio.policy.engine.configuration.FlagType AUDIO_FLAG_NO_MEDIA_PROJECTION;
+ enum_constant public static final android.audio.policy.engine.configuration.FlagType AUDIO_FLAG_NO_SYSTEM_CAPTURE;
+ enum_constant public static final android.audio.policy.engine.configuration.FlagType AUDIO_FLAG_SCO;
+ enum_constant public static final android.audio.policy.engine.configuration.FlagType AUDIO_FLAG_SECURE;
+ }
+
+ public class FlagsType {
+ ctor public FlagsType();
+ method @Nullable public java.util.List<android.audio.policy.engine.configuration.FlagType> getValue();
+ method public void setValue(@Nullable java.util.List<android.audio.policy.engine.configuration.FlagType>);
+ }
+
+ public enum PfwCriterionTypeEnum {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.engine.configuration.PfwCriterionTypeEnum exclusive;
+ enum_constant public static final android.audio.policy.engine.configuration.PfwCriterionTypeEnum inclusive;
+ }
+
+ public class ProductStrategies {
+ ctor public ProductStrategies();
+ method @Nullable public java.util.List<android.audio.policy.engine.configuration.ProductStrategies.ProductStrategy> getProductStrategy();
+ }
+
+ public static class ProductStrategies.ProductStrategy {
+ ctor public ProductStrategies.ProductStrategy();
+ method @Nullable public java.util.List<android.audio.policy.engine.configuration.AttributesGroup> getAttributesGroup();
+ method @Nullable public String getName();
+ method public void setName(@Nullable String);
+ }
+
+ public enum SourceEnumType {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.engine.configuration.SourceEnumType AUDIO_SOURCE_CAMCORDER;
+ enum_constant public static final android.audio.policy.engine.configuration.SourceEnumType AUDIO_SOURCE_DEFAULT;
+ enum_constant public static final android.audio.policy.engine.configuration.SourceEnumType AUDIO_SOURCE_ECHO_REFERENCE;
+ enum_constant public static final android.audio.policy.engine.configuration.SourceEnumType AUDIO_SOURCE_FM_TUNER;
+ enum_constant public static final android.audio.policy.engine.configuration.SourceEnumType AUDIO_SOURCE_MIC;
+ enum_constant public static final android.audio.policy.engine.configuration.SourceEnumType AUDIO_SOURCE_REMOTE_SUBMIX;
+ enum_constant public static final android.audio.policy.engine.configuration.SourceEnumType AUDIO_SOURCE_UNPROCESSED;
+ enum_constant public static final android.audio.policy.engine.configuration.SourceEnumType AUDIO_SOURCE_VOICE_CALL;
+ enum_constant public static final android.audio.policy.engine.configuration.SourceEnumType AUDIO_SOURCE_VOICE_COMMUNICATION;
+ enum_constant public static final android.audio.policy.engine.configuration.SourceEnumType AUDIO_SOURCE_VOICE_DOWNLINK;
+ enum_constant public static final android.audio.policy.engine.configuration.SourceEnumType AUDIO_SOURCE_VOICE_PERFORMANCE;
+ enum_constant public static final android.audio.policy.engine.configuration.SourceEnumType AUDIO_SOURCE_VOICE_RECOGNITION;
+ enum_constant public static final android.audio.policy.engine.configuration.SourceEnumType AUDIO_SOURCE_VOICE_UPLINK;
+ }
+
+ public class SourceType {
+ ctor public SourceType();
+ method @Nullable public android.audio.policy.engine.configuration.SourceEnumType getValue();
+ method public void setValue(@Nullable android.audio.policy.engine.configuration.SourceEnumType);
+ }
+
+ public enum Stream {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.engine.configuration.Stream AUDIO_STREAM_ACCESSIBILITY;
+ enum_constant public static final android.audio.policy.engine.configuration.Stream AUDIO_STREAM_ALARM;
+ enum_constant public static final android.audio.policy.engine.configuration.Stream AUDIO_STREAM_ASSISTANT;
+ enum_constant public static final android.audio.policy.engine.configuration.Stream AUDIO_STREAM_BLUETOOTH_SCO;
+ enum_constant public static final android.audio.policy.engine.configuration.Stream AUDIO_STREAM_DEFAULT;
+ enum_constant public static final android.audio.policy.engine.configuration.Stream AUDIO_STREAM_DTMF;
+ enum_constant public static final android.audio.policy.engine.configuration.Stream AUDIO_STREAM_ENFORCED_AUDIBLE;
+ enum_constant public static final android.audio.policy.engine.configuration.Stream AUDIO_STREAM_MUSIC;
+ enum_constant public static final android.audio.policy.engine.configuration.Stream AUDIO_STREAM_NOTIFICATION;
+ enum_constant public static final android.audio.policy.engine.configuration.Stream AUDIO_STREAM_RING;
+ enum_constant public static final android.audio.policy.engine.configuration.Stream AUDIO_STREAM_SYSTEM;
+ enum_constant public static final android.audio.policy.engine.configuration.Stream AUDIO_STREAM_TTS;
+ enum_constant public static final android.audio.policy.engine.configuration.Stream AUDIO_STREAM_VOICE_CALL;
+ }
+
+ public enum UsageEnumType {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_ALARM;
+ enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY;
+ enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
+ enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_ASSISTANCE_SONIFICATION;
+ enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_ASSISTANT;
+ enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_CALL_ASSISTANT;
+ enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_GAME;
+ enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_MEDIA;
+ enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_NOTIFICATION;
+ enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED;
+ enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT;
+ enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST;
+ enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_NOTIFICATION_EVENT;
+ enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE;
+ enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_UNKNOWN;
+ enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_VIRTUAL_SOURCE;
+ enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_VOICE_COMMUNICATION;
+ enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING;
+ }
+
+ public class UsageType {
+ ctor public UsageType();
+ method @Nullable public android.audio.policy.engine.configuration.UsageEnumType getValue();
+ method public void setValue(@Nullable android.audio.policy.engine.configuration.UsageEnumType);
+ }
+
+ public class ValueType {
+ ctor public ValueType();
+ method @Nullable public String getAndroid_type();
+ method @Nullable public String getLiteral();
+ method @Nullable public long getNumerical();
+ method public void setAndroid_type(@Nullable String);
+ method public void setLiteral(@Nullable String);
+ method public void setNumerical(@Nullable long);
+ }
+
+ public class ValuesType {
+ ctor public ValuesType();
+ method @Nullable public java.util.List<android.audio.policy.engine.configuration.ValueType> getValue();
+ }
+
+ public enum Version {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.engine.configuration.Version _1_0;
+ }
+
+ public class Volume {
+ ctor public Volume();
+ method @Nullable public android.audio.policy.engine.configuration.DeviceCategory getDeviceCategory();
+ method @Nullable public java.util.List<java.lang.String> getPoint();
+ method @Nullable public String getRef();
+ method public void setDeviceCategory(@Nullable android.audio.policy.engine.configuration.DeviceCategory);
+ method public void setRef(@Nullable String);
+ }
+
+ public class VolumeGroupsType {
+ ctor public VolumeGroupsType();
+ method @Nullable public java.util.List<android.audio.policy.engine.configuration.VolumeGroupsType.VolumeGroup> getVolumeGroup();
+ }
+
+ public static class VolumeGroupsType.VolumeGroup {
+ ctor public VolumeGroupsType.VolumeGroup();
+ method @Nullable public int getIndexMax();
+ method @Nullable public int getIndexMin();
+ method @Nullable public String getName();
+ method @Nullable public java.util.List<android.audio.policy.engine.configuration.Volume> getVolume();
+ method public void setIndexMax(@Nullable int);
+ method public void setIndexMin(@Nullable int);
+ method public void setName(@Nullable String);
+ }
+
+ public class VolumeRef {
+ ctor public VolumeRef();
+ method @Nullable public String getName();
+ method @Nullable public java.util.List<java.lang.String> getPoint();
+ method public void setName(@Nullable String);
+ }
+
+ public class VolumesType {
+ ctor public VolumesType();
+ method @Nullable public java.util.List<android.audio.policy.engine.configuration.VolumeRef> getReference();
+ }
+
+ public class XmlParser {
+ ctor public XmlParser();
+ method @Nullable public static android.audio.policy.engine.configuration.Configuration read(@NonNull java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method @Nullable public static String readText(@NonNull org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static void skip(@NonNull org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ }
+
+}
+
diff --git a/audio/aidl/default/config/audioPolicy/engine/api/last_current.txt b/audio/aidl/default/config/audioPolicy/engine/api/last_current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/audio/aidl/default/config/audioPolicy/engine/api/last_current.txt
diff --git a/audio/aidl/default/config/audioPolicy/engine/api/last_removed.txt b/audio/aidl/default/config/audioPolicy/engine/api/last_removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/audio/aidl/default/config/audioPolicy/engine/api/last_removed.txt
diff --git a/audio/aidl/default/config/audioPolicy/engine/api/removed.txt b/audio/aidl/default/config/audioPolicy/engine/api/removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/audio/aidl/default/config/audioPolicy/engine/api/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/audio/aidl/default/config/audioPolicy/engine/audio_policy_engine_configuration.xsd b/audio/aidl/default/config/audioPolicy/engine/audio_policy_engine_configuration.xsd
new file mode 100644
index 0000000..b58a6c8
--- /dev/null
+++ b/audio/aidl/default/config/audioPolicy/engine/audio_policy_engine_configuration.xsd
@@ -0,0 +1,418 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+ <xs:schema version="2.0"
+ elementFormDefault="qualified"
+ attributeFormDefault="unqualified"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <!-- List the config versions supported by audio policy engine. -->
+ <xs:simpleType name="version">
+ <xs:restriction base="xs:decimal">
+ <xs:enumeration value="1.0"/>
+ </xs:restriction>
+ </xs:simpleType>
+
+ <xs:element name="configuration">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="ProductStrategies" type="ProductStrategies" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="criterion_types" type="criterionTypesType" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="criteria" type="criteriaType" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="volumeGroups" type="volumeGroupsType" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="volumes" type="volumesType" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="attributesRef" type="attributesRef" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="version" type="version" use="required"/>
+ </xs:complexType>
+
+ <xs:key name="volumeCurveNameKey">
+ <xs:selector xpath="volumes/reference"/>
+ <xs:field xpath="@name"/>
+ </xs:key>
+ <xs:keyref name="volumeCurveRef" refer="volumeCurveNameKey">
+ <xs:selector xpath="volumeGroups/volumeGroup"/>
+ <xs:field xpath="@ref"/>
+ </xs:keyref>
+
+ <xs:key name="attributesRefNameKey">
+ <xs:selector xpath="attributesRef/reference"/>
+ <xs:field xpath="@name"/>
+ </xs:key>
+ <xs:keyref name="volumeGroupAttributesRef" refer="attributesRefNameKey">
+ <xs:selector xpath="volumeGroups/volumeGroup/volume"/>
+ <xs:field xpath="@attributesRef"/>
+ </xs:keyref>
+ <xs:keyref name="ProductStrategyAttributesRef" refer="attributesRefNameKey">
+ <xs:selector xpath="ProductStrategies/ProductStrategy/Attributes"/>
+ <xs:field xpath="@attributesRef"/>
+ </xs:keyref>
+
+ <xs:unique name="productStrategyNameUniqueness">
+ <xs:selector xpath="ProductStrategies/ProductStrategy"/>
+ <xs:field xpath="@name"/>
+ </xs:unique>
+
+ <!-- ensure validity of volume group referred in product strategy-->
+ <xs:key name="volumeGroupKey">
+ <xs:selector xpath="volumeGroups/volumeGroup/name"/>
+ <xs:field xpath="."/>
+ </xs:key>
+ <xs:keyref name="volumeGroupRef" refer="volumeGroupKey">
+ <xs:selector xpath="ProductStrategies/ProductStrategy/AttributesGroup"/>
+ <xs:field xpath="@volumeGroup"/>
+ </xs:keyref>
+
+ <xs:unique name="volumeTargetUniqueness">
+ <xs:selector xpath="volumeGroups/volumeGroup"/>
+ <xs:field xpath="@name"/>
+ <xs:field xpath="@deviceCategory"/>
+ </xs:unique>
+
+ <!-- ensure validity of criterion type referred in criterion-->
+ <xs:key name="criterionTypeKey">
+ <xs:selector xpath="criterion_types/criterion_type"/>
+ <xs:field xpath="@name"/>
+ </xs:key>
+ <xs:keyref name="criterionTypeKeyRef" refer="criterionTypeKey">
+ <xs:selector xpath="criteria/criterion"/>
+ <xs:field xpath="@type"/>
+ </xs:keyref>
+
+ </xs:element>
+
+ <xs:complexType name="ProductStrategies">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ </xs:documentation>
+ </xs:annotation>
+ <xs:sequence>
+ <xs:element name="ProductStrategy" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="AttributesGroup" type="AttributesGroup" minOccurs="1" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:string" use="required"/>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:complexType name="AttributesGroup">
+ <xs:sequence>
+ <xs:choice minOccurs="0">
+ <xs:element name="Attributes" type="AttributesType" minOccurs="1" maxOccurs="unbounded"/>
+ <xs:sequence>
+ <xs:element name="ContentType" type="ContentTypeType" minOccurs="0" maxOccurs="1"/>
+ <xs:element name="Usage" type="UsageType" minOccurs="1" maxOccurs="1"/>
+ <xs:element name="Source" type="SourceType" minOccurs="0" maxOccurs="1"/>
+ <xs:element name="Flags" type="FlagsType" minOccurs="0" maxOccurs="1"/>
+ <xs:element name="Bundle" type="BundleType" minOccurs="0" maxOccurs="1"/>
+ </xs:sequence>
+ </xs:choice>
+ </xs:sequence>
+ <xs:attribute name="streamType" type="stream" use="optional"/>
+ <xs:attribute name="volumeGroup" type="xs:string" use="optional"/>
+ </xs:complexType>
+
+ <xs:complexType name="volumeGroupsType">
+ <xs:sequence>
+ <xs:element name="volumeGroup" minOccurs="0" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="name" type="xs:token"/>
+ <xs:element name="indexMin" type="xs:int" minOccurs="0" maxOccurs="1"/>
+ <xs:element name="indexMax" type="xs:int" minOccurs="0" maxOccurs="1"/>
+ <xs:element name="volume" type="volume" minOccurs="1" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:unique name="volumeAttributesUniqueness">
+ <xs:selector xpath="volume"/>
+ <xs:field xpath="deviceCategory"/>
+ </xs:unique>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:complexType name="volumesType">
+ <xs:sequence>
+ <xs:element name="reference" type="volumeRef" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:complexType name="attributesRef">
+ <xs:sequence>
+ <xs:element name="reference" type="attributesRefType" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:complexType name="criteriaType">
+ <xs:sequence>
+ <xs:element name="criterion" type="criterionType" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="criterionType">
+ <xs:attribute name="name" type="xs:string" use="required"/>
+ <xs:attribute name="type" type="xs:string" use="required"/>
+ <xs:attribute name="default" type="xs:string" use="optional"/>
+ </xs:complexType>
+
+ <xs:complexType name="criterionTypesType">
+ <xs:sequence>
+ <xs:element name="criterion_type" type="criterionTypeType" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="criterionTypeType">
+ <xs:sequence>
+ <xs:element name="values" type="valuesType" minOccurs="0" maxOccurs="1"/>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:token" use="required"/>
+ <xs:attribute name="type" type="pfwCriterionTypeEnum" use="required"/>
+ </xs:complexType>
+
+ <xs:complexType name="valuesType">
+ <xs:sequence>
+ <xs:element name="value" type="valueType" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="valueType">
+ <xs:attribute name="literal" type="xs:string" use="required"/>
+ <xs:attribute name="numerical" type="xs:long" use="required"/>
+ <xs:attribute name="android_type" type="longDecimalOrHexType" use="optional"/>
+ </xs:complexType>
+
+ <xs:simpleType name="longDecimalOrHexType">
+ <xs:union memberTypes="xs:long longHexType" />
+ </xs:simpleType>
+
+ <xs:simpleType name="longHexType">
+ <xs:restriction base="xs:string">
+ <xs:pattern value="0x[0-9A-Fa-f]{1,16}"/>
+ </xs:restriction>
+ </xs:simpleType>
+
+ <xs:complexType name="attributesRefType">
+ <xs:sequence>
+ <xs:element name="Attributes" type="AttributesType" minOccurs="1" maxOccurs="1"/>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:token" use="required"/>
+ </xs:complexType>
+
+ <xs:complexType name="AttributesType">
+ <xs:sequence>
+ <xs:element name="ContentType" type="ContentTypeType" minOccurs="0" maxOccurs="1"/>
+ <xs:element name="Usage" type="UsageType" minOccurs="0" maxOccurs="1"/>
+ <xs:element name="Source" type="SourceType" minOccurs="0" maxOccurs="1"/>
+ <xs:element name="Flags" type="FlagsType" minOccurs="0" maxOccurs="1"/>
+ <xs:element name="Bundle" type="BundleType" minOccurs="0" maxOccurs="1"/>
+ </xs:sequence>
+ <xs:attribute name="attributesRef" type="xs:token" use="optional"/>
+ <!-- with xsd 1.1, it is impossible to make choice on either attributes or element...-->
+ </xs:complexType>
+
+ <xs:complexType name="ContentTypeType">
+ <xs:attribute name="value" type="contentType" use="required"/>
+ </xs:complexType>
+ <xs:complexType name="UsageType">
+ <xs:attribute name="value" type="usageEnumType" use="required"/>
+ </xs:complexType>
+ <xs:complexType name="SourceType">
+ <xs:attribute name="value" type="sourceEnumType" use="required"/>
+ </xs:complexType>
+ <xs:complexType name="FlagsType">
+ <xs:attribute name="value" type="flagsEnumType" use="required"/>
+ </xs:complexType>
+ <xs:complexType name="BundleType">
+ <xs:attribute name="key" type="xs:string" use="required"/>
+ <xs:attribute name="value" type="xs:string" use="required"/>
+ </xs:complexType>
+
+ <xs:complexType name="volume">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ Volume section defines a volume curve for a given use case and device category.
+ It contains a list of points of this curve expressing the attenuation in Millibels
+ for a given volume index from 0 to 100.
+ <volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
+ <point>0,-9600</point>
+ <point>100,0</point>
+ </volume>
+
+ It may also reference a reference/@name to avoid duplicating curves.
+ <volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+ <reference name="DEFAULT_MEDIA_VOLUME_CURVE">
+ <point>0,-9600</point>
+ <point>100,0</point>
+ </reference>
+ </xs:documentation>
+ </xs:annotation>
+ <xs:sequence>
+ <xs:element name="point" type="volumePoint" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="deviceCategory" type="deviceCategory"/>
+ <xs:attribute name="ref" type="xs:token" use="optional"/>
+ </xs:complexType>
+
+ <xs:complexType name="volumeRef">
+ <xs:sequence>
+ <xs:element name="point" type="volumePoint" minOccurs="2" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:token" use="required"/>
+ </xs:complexType>
+
+ <xs:simpleType name="volumePoint">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ Comma separated pair of number.
+ The fist one is the framework level (between 0 and 100).
+ The second one is the volume to send to the HAL.
+ The framework will interpolate volumes not specified.
+ Their MUST be at least 2 points specified.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:restriction base="xs:string">
+ <xs:pattern value="([0-9]{1,2}|100),-?[0-9]+"/>
+ </xs:restriction>
+ </xs:simpleType>
+
+
+ <xs:simpleType name="streamsCsv">
+ <xs:list>
+ <xs:simpleType>
+ <xs:restriction base="stream">
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:list>
+ </xs:simpleType>
+
+ <!-- Enum values of audio_stream_type_t in audio-base.h
+ TODO: avoid manual sync. -->
+ <xs:simpleType name="stream">
+ <xs:restriction base="xs:NMTOKEN">
+ <!--xs:pattern value="\c+(,\c+)*"/-->
+ <xs:enumeration value="AUDIO_STREAM_DEFAULT"/>
+ <xs:enumeration value="AUDIO_STREAM_VOICE_CALL"/>
+ <xs:enumeration value="AUDIO_STREAM_SYSTEM"/>
+ <xs:enumeration value="AUDIO_STREAM_RING"/>
+ <xs:enumeration value="AUDIO_STREAM_MUSIC"/>
+ <xs:enumeration value="AUDIO_STREAM_ALARM"/>
+ <xs:enumeration value="AUDIO_STREAM_NOTIFICATION"/>
+ <xs:enumeration value="AUDIO_STREAM_BLUETOOTH_SCO"/>
+ <xs:enumeration value="AUDIO_STREAM_ENFORCED_AUDIBLE"/>
+ <xs:enumeration value="AUDIO_STREAM_DTMF"/>
+ <xs:enumeration value="AUDIO_STREAM_TTS"/>
+ <xs:enumeration value="AUDIO_STREAM_ACCESSIBILITY"/>
+ <xs:enumeration value="AUDIO_STREAM_ASSISTANT"/>
+ </xs:restriction>
+ </xs:simpleType>
+
+ <xs:simpleType name="deviceCategory">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="DEVICE_CATEGORY_HEADSET"/>
+ <xs:enumeration value="DEVICE_CATEGORY_SPEAKER"/>
+ <xs:enumeration value="DEVICE_CATEGORY_EARPIECE"/>
+ <xs:enumeration value="DEVICE_CATEGORY_EXT_MEDIA"/>
+ <xs:enumeration value="DEVICE_CATEGORY_HEARING_AID"/>
+ </xs:restriction>
+ </xs:simpleType>
+
+ <xs:simpleType name="contentType">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="AUDIO_CONTENT_TYPE_UNKNOWN"/>
+ <xs:enumeration value="AUDIO_CONTENT_TYPE_SPEECH"/>
+ <xs:enumeration value="AUDIO_CONTENT_TYPE_MUSIC"/>
+ <xs:enumeration value="AUDIO_CONTENT_TYPE_MOVIE"/>
+ <xs:enumeration value="AUDIO_CONTENT_TYPE_SONIFICATION"/>
+ </xs:restriction>
+ </xs:simpleType>
+
+ <xs:simpleType name="usageEnumType">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="AUDIO_USAGE_UNKNOWN"/>
+ <xs:enumeration value="AUDIO_USAGE_MEDIA"/>
+ <xs:enumeration value="AUDIO_USAGE_VOICE_COMMUNICATION"/>
+ <xs:enumeration value="AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING"/>
+ <xs:enumeration value="AUDIO_USAGE_ALARM"/>
+ <xs:enumeration value="AUDIO_USAGE_NOTIFICATION"/>
+ <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE"/>
+ <!-- Note: the following 3 values were deprecated in Android T (13) SDK -->
+ <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST"/>
+ <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT"/>
+ <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED"/>
+ <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_EVENT"/>
+ <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY"/>
+ <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE"/>
+ <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_SONIFICATION"/>
+ <xs:enumeration value="AUDIO_USAGE_GAME"/>
+ <xs:enumeration value="AUDIO_USAGE_VIRTUAL_SOURCE"/>
+ <xs:enumeration value="AUDIO_USAGE_ASSISTANT"/>
+ <xs:enumeration value="AUDIO_USAGE_CALL_ASSISTANT"/>
+ </xs:restriction>
+ </xs:simpleType>
+
+ <xs:simpleType name="flagsEnumType">
+ <xs:list>
+ <xs:simpleType>
+ <xs:restriction base="flagType">
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:list>
+ </xs:simpleType>
+
+ <xs:simpleType name="flagType">
+ <xs:restriction base="xs:NMTOKEN">
+ <xs:enumeration value="AUDIO_FLAG_NONE"/>
+ <xs:enumeration value="AUDIO_FLAG_AUDIBILITY_ENFORCED"/>
+ <xs:enumeration value="AUDIO_FLAG_SECURE"/>
+ <xs:enumeration value="AUDIO_FLAG_SCO"/>
+ <xs:enumeration value="AUDIO_FLAG_BEACON"/>
+ <xs:enumeration value="AUDIO_FLAG_HW_AV_SYNC"/>
+ <xs:enumeration value="AUDIO_FLAG_HW_HOTWORD"/>
+ <xs:enumeration value="AUDIO_FLAG_BYPASS_INTERRUPTION_POLICY"/>
+ <xs:enumeration value="AUDIO_FLAG_BYPASS_MUTE"/>
+ <xs:enumeration value="AUDIO_FLAG_LOW_LATENCY"/>
+ <xs:enumeration value="AUDIO_FLAG_DEEP_BUFFER"/>
+ <xs:enumeration value="AUDIO_FLAG_NO_MEDIA_PROJECTION"/>
+ <xs:enumeration value="AUDIO_FLAG_MUTE_HAPTIC"/>
+ <xs:enumeration value="AUDIO_FLAG_NO_SYSTEM_CAPTURE"/>
+ <xs:enumeration value="AUDIO_FLAG_CAPTURE_PRIVATE"/>
+ </xs:restriction>
+ </xs:simpleType>
+
+ <xs:simpleType name="sourceEnumType">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="AUDIO_SOURCE_DEFAULT"/>
+ <xs:enumeration value="AUDIO_SOURCE_MIC"/>
+ <xs:enumeration value="AUDIO_SOURCE_VOICE_UPLINK"/>
+ <xs:enumeration value="AUDIO_SOURCE_VOICE_DOWNLINK"/>
+ <xs:enumeration value="AUDIO_SOURCE_VOICE_CALL"/>
+ <xs:enumeration value="AUDIO_SOURCE_CAMCORDER"/>
+ <xs:enumeration value="AUDIO_SOURCE_VOICE_RECOGNITION"/>
+ <xs:enumeration value="AUDIO_SOURCE_VOICE_COMMUNICATION"/>
+ <xs:enumeration value="AUDIO_SOURCE_REMOTE_SUBMIX"/>
+ <xs:enumeration value="AUDIO_SOURCE_UNPROCESSED"/>
+ <xs:enumeration value="AUDIO_SOURCE_VOICE_PERFORMANCE"/>
+ <xs:enumeration value="AUDIO_SOURCE_ECHO_REFERENCE"/>
+ <xs:enumeration value="AUDIO_SOURCE_FM_TUNER"/>
+ </xs:restriction>
+ </xs:simpleType>
+
+ <xs:simpleType name="pfwCriterionTypeEnum">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="inclusive"/>
+ <xs:enumeration value="exclusive"/>
+ </xs:restriction>
+ </xs:simpleType>
+</xs:schema>
diff --git a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp
index 3920a58..39345a9 100644
--- a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp
+++ b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp
@@ -25,6 +25,7 @@
#include "DynamicsProcessingSw.h"
+using aidl::android::hardware::audio::effect::Descriptor;
using aidl::android::hardware::audio::effect::DynamicsProcessingSw;
using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::hardware::audio::effect::kDynamicsProcessingSwImplUUID;
@@ -47,23 +48,31 @@
}
}
-extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
- if (!instanceSp) {
- return EX_NONE;
+extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) {
+ if (!in_impl_uuid || *in_impl_uuid != kDynamicsProcessingSwImplUUID) {
+ LOG(ERROR) << __func__ << "uuid not supported";
+ return EX_ILLEGAL_ARGUMENT;
}
- State state;
- ndk::ScopedAStatus status = instanceSp->getState(&state);
- if (!status.isOk() || State::INIT != state) {
- LOG(ERROR) << __func__ << " instance " << instanceSp.get()
- << " in state: " << toString(state) << ", status: " << status.getDescription();
- return EX_ILLEGAL_STATE;
- }
- LOG(DEBUG) << __func__ << " instance " << instanceSp.get() << " destroyed";
+ *_aidl_return = DynamicsProcessingSw::kDescriptor;
return EX_NONE;
}
namespace aidl::android::hardware::audio::effect {
+const std::string DynamicsProcessingSw::kEffectName = "DynamicsProcessingSw";
+const DynamicsProcessing::Capability DynamicsProcessingSw::kCapability;
+const Descriptor DynamicsProcessingSw::kDescriptor = {
+ .common = {.id = {.type = kDynamicsProcessingTypeUUID,
+ .uuid = kDynamicsProcessingSwImplUUID,
+ .proxy = std::nullopt},
+ .flags = {.type = Flags::Type::INSERT,
+ .insert = Flags::Insert::FIRST,
+ .volume = Flags::Volume::CTRL},
+ .name = DynamicsProcessingSw::kEffectName,
+ .implementor = "The Android Open Source Project"},
+ .capability = Capability::make<Capability::dynamicsProcessing>(
+ DynamicsProcessingSw::kCapability)};
+
ndk::ScopedAStatus DynamicsProcessingSw::getDescriptor(Descriptor* _aidl_return) {
LOG(DEBUG) << __func__ << kDescriptor.toString();
*_aidl_return = kDescriptor;
@@ -73,8 +82,6 @@
ndk::ScopedAStatus DynamicsProcessingSw::setParameterSpecific(const Parameter::Specific& specific) {
RETURN_IF(Parameter::Specific::dynamicsProcessing != specific.getTag(), EX_ILLEGAL_ARGUMENT,
"EffectNotSupported");
- std::lock_guard lg(mMutex);
- RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
mSpecificParam = specific.get<Parameter::Specific::dynamicsProcessing>();
LOG(DEBUG) << __func__ << " success with: " << specific.toString();
@@ -93,9 +100,13 @@
const Parameter::Common& common) {
if (mContext) {
LOG(DEBUG) << __func__ << " context already exist";
- return mContext;
+ } else {
+ mContext = std::make_shared<DynamicsProcessingSwContext>(1 /* statusFmqDepth */, common);
}
- mContext = std::make_shared<DynamicsProcessingSwContext>(1 /* statusFmqDepth */, common);
+ return mContext;
+}
+
+std::shared_ptr<EffectContext> DynamicsProcessingSw::getContext() {
return mContext;
}
@@ -107,13 +118,13 @@
}
// Processing method running in EffectWorker thread.
-IEffect::Status DynamicsProcessingSw::effectProcessImpl(float* in, float* out, int process) {
+IEffect::Status DynamicsProcessingSw::effectProcessImpl(float* in, float* out, int samples) {
// TODO: get data buffer and process.
- LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
- for (int i = 0; i < process; i++) {
+ LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
+ for (int i = 0; i < samples; i++) {
*out++ = *in++;
}
- return {STATUS_OK, process, process};
+ return {STATUS_OK, samples, samples};
}
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h
index 2bc2762..2ae46c5 100644
--- a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h
+++ b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h
@@ -37,6 +37,9 @@
class DynamicsProcessingSw final : public EffectImpl {
public:
+ static const std::string kEffectName;
+ static const DynamicsProcessing::Capability kCapability;
+ static const Descriptor kDescriptor;
DynamicsProcessingSw() { LOG(DEBUG) << __func__; }
~DynamicsProcessingSw() {
cleanUp();
@@ -47,26 +50,16 @@
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) override;
- IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+ std::shared_ptr<EffectContext> getContext() override;
RetCode releaseContext() override;
+ IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+ std::string getEffectName() override { return kEffectName; };
+
private:
std::shared_ptr<DynamicsProcessingSwContext> mContext;
- /* capabilities */
- const DynamicsProcessing::Capability kCapability;
- /* Effect descriptor */
- const Descriptor kDescriptor = {
- .common = {.id = {.type = kDynamicsProcessingTypeUUID,
- .uuid = kDynamicsProcessingSwImplUUID,
- .proxy = std::nullopt},
- .flags = {.type = Flags::Type::INSERT,
- .insert = Flags::Insert::FIRST,
- .volume = Flags::Volume::CTRL},
- .name = "DynamicsProcessingSw",
- .implementor = "The Android Open Source Project"},
- .capability = Capability::make<Capability::dynamicsProcessing>(kCapability)};
-
/* parameters */
DynamicsProcessing mSpecificParam;
};
diff --git a/audio/aidl/default/envReverb/EnvReverbSw.cpp b/audio/aidl/default/envReverb/EnvReverbSw.cpp
index ad447ab..a107064 100644
--- a/audio/aidl/default/envReverb/EnvReverbSw.cpp
+++ b/audio/aidl/default/envReverb/EnvReverbSw.cpp
@@ -25,6 +25,7 @@
#include "EnvReverbSw.h"
+using aidl::android::hardware::audio::effect::Descriptor;
using aidl::android::hardware::audio::effect::EnvReverbSw;
using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::hardware::audio::effect::kEnvReverbSwImplUUID;
@@ -47,23 +48,30 @@
}
}
-extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
- if (!instanceSp) {
- return EX_NONE;
+extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) {
+ if (!in_impl_uuid || *in_impl_uuid != kEnvReverbSwImplUUID) {
+ LOG(ERROR) << __func__ << "uuid not supported";
+ return EX_ILLEGAL_ARGUMENT;
}
- State state;
- ndk::ScopedAStatus status = instanceSp->getState(&state);
- if (!status.isOk() || State::INIT != state) {
- LOG(ERROR) << __func__ << " instance " << instanceSp.get()
- << " in state: " << toString(state) << ", status: " << status.getDescription();
- return EX_ILLEGAL_STATE;
- }
- LOG(DEBUG) << __func__ << " instance " << instanceSp.get() << " destroyed";
+ *_aidl_return = EnvReverbSw::kDescriptor;
return EX_NONE;
}
namespace aidl::android::hardware::audio::effect {
+const std::string EnvReverbSw::kEffectName = "EnvReverbSw";
+const EnvironmentalReverb::Capability EnvReverbSw::kCapability;
+const Descriptor EnvReverbSw::kDescriptor = {
+ .common = {.id = {.type = kEnvReverbTypeUUID,
+ .uuid = kEnvReverbSwImplUUID,
+ .proxy = std::nullopt},
+ .flags = {.type = Flags::Type::INSERT,
+ .insert = Flags::Insert::FIRST,
+ .volume = Flags::Volume::CTRL},
+ .name = EnvReverbSw::kEffectName,
+ .implementor = "The Android Open Source Project"},
+ .capability = Capability::make<Capability::environmentalReverb>(EnvReverbSw::kCapability)};
+
ndk::ScopedAStatus EnvReverbSw::getDescriptor(Descriptor* _aidl_return) {
LOG(DEBUG) << __func__ << kDescriptor.toString();
*_aidl_return = kDescriptor;
@@ -71,12 +79,10 @@
}
ndk::ScopedAStatus EnvReverbSw::setParameterSpecific(const Parameter::Specific& specific) {
- RETURN_IF(Parameter::Specific::reverb != specific.getTag(), EX_ILLEGAL_ARGUMENT,
+ RETURN_IF(Parameter::Specific::environmentalReverb != specific.getTag(), EX_ILLEGAL_ARGUMENT,
"EffectNotSupported");
- std::lock_guard lg(mMutex);
- RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
- mSpecificParam = specific.get<Parameter::Specific::reverb>();
+ mSpecificParam = specific.get<Parameter::Specific::environmentalReverb>();
LOG(DEBUG) << __func__ << " success with: " << specific.toString();
return ndk::ScopedAStatus::ok();
}
@@ -84,17 +90,22 @@
ndk::ScopedAStatus EnvReverbSw::getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) {
auto tag = id.getTag();
- RETURN_IF(Parameter::Id::reverbTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
- specific->set<Parameter::Specific::reverb>(mSpecificParam);
+ RETURN_IF(Parameter::Id::environmentalReverbTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
+ specific->set<Parameter::Specific::environmentalReverb>(mSpecificParam);
return ndk::ScopedAStatus::ok();
}
std::shared_ptr<EffectContext> EnvReverbSw::createContext(const Parameter::Common& common) {
if (mContext) {
LOG(DEBUG) << __func__ << " context already exist";
- return mContext;
+ } else {
+ mContext = std::make_shared<EnvReverbSwContext>(1 /* statusFmqDepth */, common);
}
- mContext = std::make_shared<EnvReverbSwContext>(1 /* statusFmqDepth */, common);
+
+ return mContext;
+}
+
+std::shared_ptr<EffectContext> EnvReverbSw::getContext() {
return mContext;
}
@@ -106,13 +117,13 @@
}
// Processing method running in EffectWorker thread.
-IEffect::Status EnvReverbSw::effectProcessImpl(float* in, float* out, int process) {
+IEffect::Status EnvReverbSw::effectProcessImpl(float* in, float* out, int samples) {
// TODO: get data buffer and process.
- LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
- for (int i = 0; i < process; i++) {
+ LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
+ for (int i = 0; i < samples; i++) {
*out++ = *in++;
}
- return {STATUS_OK, process, process};
+ return {STATUS_OK, samples, samples};
}
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/envReverb/EnvReverbSw.h b/audio/aidl/default/envReverb/EnvReverbSw.h
index 5a9ab27..b8761a6 100644
--- a/audio/aidl/default/envReverb/EnvReverbSw.h
+++ b/audio/aidl/default/envReverb/EnvReverbSw.h
@@ -37,6 +37,9 @@
class EnvReverbSw final : public EffectImpl {
public:
+ static const std::string kEffectName;
+ static const EnvironmentalReverb::Capability kCapability;
+ static const Descriptor kDescriptor;
EnvReverbSw() { LOG(DEBUG) << __func__; }
~EnvReverbSw() {
cleanUp();
@@ -47,27 +50,17 @@
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) override;
- IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+ std::shared_ptr<EffectContext> getContext() override;
RetCode releaseContext() override;
+ IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+ std::string getEffectName() override { return kEffectName; }
+
private:
std::shared_ptr<EnvReverbSwContext> mContext;
- /* capabilities */
- const Reverb::Capability kCapability;
- /* Effect descriptor */
- const Descriptor kDescriptor = {
- .common = {.id = {.type = kEnvReverbTypeUUID,
- .uuid = kEnvReverbSwImplUUID,
- .proxy = std::nullopt},
- .flags = {.type = Flags::Type::INSERT,
- .insert = Flags::Insert::FIRST,
- .volume = Flags::Volume::CTRL},
- .name = "EnvReverbSw",
- .implementor = "The Android Open Source Project"},
- .capability = Capability::make<Capability::reverb>(kCapability)};
-
/* parameters */
- Reverb mSpecificParam;
+ EnvironmentalReverb mSpecificParam;
};
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/equalizer/EqualizerSw.cpp b/audio/aidl/default/equalizer/EqualizerSw.cpp
index d61ef97..984b943 100644
--- a/audio/aidl/default/equalizer/EqualizerSw.cpp
+++ b/audio/aidl/default/equalizer/EqualizerSw.cpp
@@ -25,6 +25,7 @@
#include "EqualizerSw.h"
+using aidl::android::hardware::audio::effect::Descriptor;
using aidl::android::hardware::audio::effect::EqualizerSw;
using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::hardware::audio::effect::kEqualizerSwImplUUID;
@@ -47,20 +48,41 @@
}
}
-extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
- State state;
- ndk::ScopedAStatus status = instanceSp->getState(&state);
- if (!status.isOk() || State::INIT != state) {
- LOG(ERROR) << __func__ << " instance " << instanceSp.get()
- << " in state: " << toString(state) << ", status: " << status.getDescription();
- return EX_ILLEGAL_STATE;
+extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) {
+ if (!in_impl_uuid || *in_impl_uuid != kEqualizerSwImplUUID) {
+ LOG(ERROR) << __func__ << "uuid not supported";
+ return EX_ILLEGAL_ARGUMENT;
}
- LOG(DEBUG) << __func__ << " instance " << instanceSp.get() << " destroyed";
+ *_aidl_return = EqualizerSw::kDesc;
return EX_NONE;
}
namespace aidl::android::hardware::audio::effect {
+const std::string EqualizerSw::kEffectName = "EqualizerSw";
+const std::vector<Equalizer::BandFrequency> EqualizerSw::kBandFrequency = {{0, 30000, 120000},
+ {1, 120001, 460000},
+ {2, 460001, 1800000},
+ {3, 1800001, 7000000},
+ {4, 7000001, 20000000}};
+const std::vector<Equalizer::Preset> EqualizerSw::kPresets = {
+ {0, "Normal"}, {1, "Classical"}, {2, "Dance"}, {3, "Flat"}, {4, "Folk"},
+ {5, "Heavy Metal"}, {6, "Hip Hop"}, {7, "Jazz"}, {8, "Pop"}, {9, "Rock"}};
+
+const Equalizer::Capability EqualizerSw::kEqCap = {.bandFrequencies = kBandFrequency,
+ .presets = kPresets};
+
+const Descriptor EqualizerSw::kDesc = {
+ .common = {.id = {.type = kEqualizerTypeUUID,
+ .uuid = kEqualizerSwImplUUID,
+ .proxy = kEqualizerProxyUUID},
+ .flags = {.type = Flags::Type::INSERT,
+ .insert = Flags::Insert::FIRST,
+ .volume = Flags::Volume::CTRL},
+ .name = EqualizerSw::kEffectName,
+ .implementor = "The Android Open Source Project"},
+ .capability = Capability::make<Capability::equalizer>(EqualizerSw::kEqCap)};
+
ndk::ScopedAStatus EqualizerSw::getDescriptor(Descriptor* _aidl_return) {
LOG(DEBUG) << __func__ << kDesc.toString();
*_aidl_return = kDesc;
@@ -70,7 +92,6 @@
ndk::ScopedAStatus EqualizerSw::setParameterSpecific(const Parameter::Specific& specific) {
RETURN_IF(Parameter::Specific::equalizer != specific.getTag(), EX_ILLEGAL_ARGUMENT,
"EffectNotSupported");
- std::lock_guard lg(mMutex);
RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
auto& eqParam = specific.get<Parameter::Specific::equalizer>();
@@ -117,7 +138,6 @@
ndk::ScopedAStatus EqualizerSw::getParameterEqualizer(const Equalizer::Tag& tag,
Parameter::Specific* specific) {
- std::lock_guard lg(mMutex);
RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
Equalizer eqParam;
@@ -144,9 +164,14 @@
std::shared_ptr<EffectContext> EqualizerSw::createContext(const Parameter::Common& common) {
if (mContext) {
LOG(DEBUG) << __func__ << " context already exist";
- return mContext;
+ } else {
+ mContext = std::make_shared<EqualizerSwContext>(1 /* statusFmqDepth */, common);
}
- mContext = std::make_shared<EqualizerSwContext>(1 /* statusFmqDepth */, common);
+
+ return mContext;
+}
+
+std::shared_ptr<EffectContext> EqualizerSw::getContext() {
return mContext;
}
@@ -158,13 +183,13 @@
}
// Processing method running in EffectWorker thread.
-IEffect::Status EqualizerSw::effectProcessImpl(float* in, float* out, int process) {
+IEffect::Status EqualizerSw::effectProcessImpl(float* in, float* out, int samples) {
// TODO: get data buffer and process.
- LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
- for (int i = 0; i < process; i++) {
+ LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
+ for (int i = 0; i < samples; i++) {
*out++ = *in++;
}
- return {STATUS_OK, process, process};
+ return {STATUS_OK, samples, samples};
}
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/equalizer/EqualizerSw.h b/audio/aidl/default/equalizer/EqualizerSw.h
index aa4587a..81bcd7a 100644
--- a/audio/aidl/default/equalizer/EqualizerSw.h
+++ b/audio/aidl/default/equalizer/EqualizerSw.h
@@ -80,6 +80,12 @@
class EqualizerSw final : public EffectImpl {
public:
+ static const std::string kEffectName;
+ static const std::vector<Equalizer::BandFrequency> kBandFrequency;
+ static const std::vector<Equalizer::Preset> kPresets;
+ static const Equalizer::Capability kEqCap;
+ static const Descriptor kDesc;
+
EqualizerSw() { LOG(DEBUG) << __func__; }
~EqualizerSw() {
cleanUp();
@@ -90,36 +96,18 @@
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) override;
- IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+ std::shared_ptr<EffectContext> getContext() override;
RetCode releaseContext() override;
+ IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+ std::string getEffectName() override { return kEffectName; }
+
private:
- std::shared_ptr<EqualizerSwContext> mContext;
- /* capabilities */
- const std::vector<Equalizer::BandFrequency> mBandFrequency = {{0, 30000, 120000},
- {1, 120001, 460000},
- {2, 460001, 1800000},
- {3, 1800001, 7000000},
- {4, 7000001, 20000000}};
- // presets supported by the device
- const std::vector<Equalizer::Preset> mPresets = {
- {0, "Normal"}, {1, "Classical"}, {2, "Dance"}, {3, "Flat"}, {4, "Folk"},
- {5, "Heavy Metal"}, {6, "Hip Hop"}, {7, "Jazz"}, {8, "Pop"}, {9, "Rock"}};
-
- const Equalizer::Capability kEqCap = {.bandFrequencies = mBandFrequency, .presets = mPresets};
- // Effect descriptor.
- const Descriptor kDesc = {.common = {.id = {.type = kEqualizerTypeUUID,
- .uuid = kEqualizerSwImplUUID,
- .proxy = kEqualizerProxyUUID},
- .flags = {.type = Flags::Type::INSERT,
- .insert = Flags::Insert::FIRST,
- .volume = Flags::Volume::CTRL},
- .name = "EqualizerSw",
- .implementor = "The Android Open Source Project"},
- .capability = Capability::make<Capability::equalizer>(kEqCap)};
-
ndk::ScopedAStatus getParameterEqualizer(const Equalizer::Tag& tag,
Parameter::Specific* specific);
+ std::shared_ptr<EqualizerSwContext> mContext;
};
+
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp
index fd5ea34..8004631 100644
--- a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp
+++ b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp
@@ -25,6 +25,7 @@
#include "HapticGeneratorSw.h"
+using aidl::android::hardware::audio::effect::Descriptor;
using aidl::android::hardware::audio::effect::HapticGeneratorSw;
using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::hardware::audio::effect::kHapticGeneratorSwImplUUID;
@@ -47,23 +48,33 @@
}
}
-extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
- if (!instanceSp) {
- return EX_NONE;
+extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) {
+ if (!in_impl_uuid || *in_impl_uuid != kHapticGeneratorSwImplUUID) {
+ LOG(ERROR) << __func__ << "uuid not supported";
+ return EX_ILLEGAL_ARGUMENT;
}
- State state;
- ndk::ScopedAStatus status = instanceSp->getState(&state);
- if (!status.isOk() || State::INIT != state) {
- LOG(ERROR) << __func__ << " instance " << instanceSp.get()
- << " in state: " << toString(state) << ", status: " << status.getDescription();
- return EX_ILLEGAL_STATE;
- }
- LOG(DEBUG) << __func__ << " instance " << instanceSp.get() << " destroyed";
+ *_aidl_return = HapticGeneratorSw::kDescriptor;
return EX_NONE;
}
namespace aidl::android::hardware::audio::effect {
+const std::string HapticGeneratorSw::kEffectName = "HapticGeneratorSw";
+/* capabilities */
+const HapticGenerator::Capability HapticGeneratorSw::kCapability;
+/* Effect descriptor */
+const Descriptor HapticGeneratorSw::kDescriptor = {
+ .common = {.id = {.type = kHapticGeneratorTypeUUID,
+ .uuid = kHapticGeneratorSwImplUUID,
+ .proxy = std::nullopt},
+ .flags = {.type = Flags::Type::INSERT,
+ .insert = Flags::Insert::FIRST,
+ .volume = Flags::Volume::CTRL},
+ .name = HapticGeneratorSw::kEffectName,
+ .implementor = "The Android Open Source Project"},
+ .capability =
+ Capability::make<Capability::hapticGenerator>(HapticGeneratorSw::kCapability)};
+
ndk::ScopedAStatus HapticGeneratorSw::getDescriptor(Descriptor* _aidl_return) {
LOG(DEBUG) << __func__ << kDescriptor.toString();
*_aidl_return = kDescriptor;
@@ -73,9 +84,6 @@
ndk::ScopedAStatus HapticGeneratorSw::setParameterSpecific(const Parameter::Specific& specific) {
RETURN_IF(Parameter::Specific::hapticGenerator != specific.getTag(), EX_ILLEGAL_ARGUMENT,
"EffectNotSupported");
- std::lock_guard lg(mMutex);
- RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
-
mSpecificParam = specific.get<Parameter::Specific::hapticGenerator>();
LOG(DEBUG) << __func__ << " success with: " << specific.toString();
return ndk::ScopedAStatus::ok();
@@ -92,9 +100,14 @@
std::shared_ptr<EffectContext> HapticGeneratorSw::createContext(const Parameter::Common& common) {
if (mContext) {
LOG(DEBUG) << __func__ << " context already exist";
- return mContext;
+ } else {
+ mContext = std::make_shared<HapticGeneratorSwContext>(1 /* statusFmqDepth */, common);
}
- mContext = std::make_shared<HapticGeneratorSwContext>(1 /* statusFmqDepth */, common);
+
+ return mContext;
+}
+
+std::shared_ptr<EffectContext> HapticGeneratorSw::getContext() {
return mContext;
}
@@ -106,13 +119,13 @@
}
// Processing method running in EffectWorker thread.
-IEffect::Status HapticGeneratorSw::effectProcessImpl(float* in, float* out, int process) {
+IEffect::Status HapticGeneratorSw::effectProcessImpl(float* in, float* out, int samples) {
// TODO: get data buffer and process.
- LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
- for (int i = 0; i < process; i++) {
+ LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
+ for (int i = 0; i < samples; i++) {
*out++ = *in++;
}
- return {STATUS_OK, process, process};
+ return {STATUS_OK, samples, samples};
}
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h
index 518aa87..bf01bfb 100644
--- a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h
+++ b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h
@@ -37,6 +37,9 @@
class HapticGeneratorSw final : public EffectImpl {
public:
+ static const std::string kEffectName;
+ static const HapticGenerator::Capability kCapability;
+ static const Descriptor kDescriptor;
HapticGeneratorSw() { LOG(DEBUG) << __func__; }
~HapticGeneratorSw() {
cleanUp();
@@ -47,26 +50,16 @@
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) override;
- IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+ std::shared_ptr<EffectContext> getContext() override;
RetCode releaseContext() override;
+ IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+ std::string getEffectName() override { return kEffectName; }
+
private:
std::shared_ptr<HapticGeneratorSwContext> mContext;
- /* capabilities */
- const HapticGenerator::Capability kCapability;
- /* Effect descriptor */
- const Descriptor kDescriptor = {
- .common = {.id = {.type = kHapticGeneratorTypeUUID,
- .uuid = kHapticGeneratorSwImplUUID,
- .proxy = std::nullopt},
- .flags = {.type = Flags::Type::INSERT,
- .insert = Flags::Insert::FIRST,
- .volume = Flags::Volume::CTRL},
- .name = "HapticGeneratorSw",
- .implementor = "The Android Open Source Project"},
- .capability = Capability::make<Capability::hapticGenerator>(kCapability)};
-
/* parameters */
HapticGenerator mSpecificParam;
};
diff --git a/audio/aidl/default/include/core-impl/AudioPolicyConfigXmlConverter.h b/audio/aidl/default/include/core-impl/AudioPolicyConfigXmlConverter.h
new file mode 100644
index 0000000..47918f0
--- /dev/null
+++ b/audio/aidl/default/include/core-impl/AudioPolicyConfigXmlConverter.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <string>
+
+#include <aidl/android/media/audio/common/AudioHalEngineConfig.h>
+#include <android_audio_policy_configuration.h>
+#include <android_audio_policy_configuration_enums.h>
+
+#include "core-impl/XmlConverter.h"
+
+namespace aidl::android::hardware::audio::core::internal {
+
+class AudioPolicyConfigXmlConverter {
+ public:
+ explicit AudioPolicyConfigXmlConverter(const std::string& configFilePath)
+ : mConverter(configFilePath, &::android::audio::policy::configuration::read) {}
+
+ std::string getError() const { return mConverter.getError(); }
+ ::android::status_t getStatus() const { return mConverter.getStatus(); }
+
+ const ::aidl::android::media::audio::common::AudioHalEngineConfig& getAidlEngineConfig();
+
+ private:
+ const std::optional<::android::audio::policy::configuration::AudioPolicyConfiguration>&
+ getXsdcConfig() const {
+ return mConverter.getXsdcConfig();
+ }
+ void addVolumeGroupstoEngineConfig();
+ void mapStreamToVolumeCurve(
+ const ::android::audio::policy::configuration::Volume& xsdcVolumeCurve);
+ void mapStreamsToVolumeCurves();
+ void parseVolumes();
+ ::aidl::android::media::audio::common::AudioHalVolumeCurve::CurvePoint convertCurvePointToAidl(
+ const std::string& xsdcCurvePoint);
+
+ ::aidl::android::media::audio::common::AudioHalVolumeCurve convertVolumeCurveToAidl(
+ const ::android::audio::policy::configuration::Volume& xsdcVolumeCurve);
+
+ ::aidl::android::media::audio::common::AudioHalEngineConfig mAidlEngineConfig;
+ XmlConverter<::android::audio::policy::configuration::AudioPolicyConfiguration> mConverter;
+ std::unordered_map<std::string, ::android::audio::policy::configuration::Reference>
+ mVolumesReferenceMap;
+ std::unordered_map<::android::audio::policy::configuration::AudioStreamType,
+ std::vector<::aidl::android::media::audio::common::AudioHalVolumeCurve>>
+ mStreamToVolumeCurvesMap;
+};
+
+} // namespace aidl::android::hardware::audio::core::internal
diff --git a/audio/aidl/default/include/core-impl/Config.h b/audio/aidl/default/include/core-impl/Config.h
index 4555efd..96a6cb9 100644
--- a/audio/aidl/default/include/core-impl/Config.h
+++ b/audio/aidl/default/include/core-impl/Config.h
@@ -17,11 +17,22 @@
#pragma once
#include <aidl/android/hardware/audio/core/BnConfig.h>
+#include <system/audio_config.h>
+
+#include "AudioPolicyConfigXmlConverter.h"
+#include "EngineConfigXmlConverter.h"
namespace aidl::android::hardware::audio::core {
+static const std::string kEngineConfigFileName = "audio_policy_engine_configuration.xml";
class Config : public BnConfig {
ndk::ScopedAStatus getSurroundSoundConfig(SurroundSoundConfig* _aidl_return) override;
+ ndk::ScopedAStatus getEngineConfig(
+ aidl::android::media::audio::common::AudioHalEngineConfig* _aidl_return) override;
+ internal::AudioPolicyConfigXmlConverter mAudioPolicyConverter{
+ ::android::audio_get_audio_policy_config_file()};
+ internal::EngineConfigXmlConverter mEngConfigConverter{
+ ::android::audio_find_readable_configuration_file(kEngineConfigFileName.c_str())};
};
} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/Configuration.h b/audio/aidl/default/include/core-impl/Configuration.h
index 95adcd7..3b4c494 100644
--- a/audio/aidl/default/include/core-impl/Configuration.h
+++ b/audio/aidl/default/include/core-impl/Configuration.h
@@ -17,6 +17,7 @@
#pragma once
#include <map>
+#include <memory>
#include <vector>
#include <aidl/android/hardware/audio/core/AudioPatch.h>
@@ -41,6 +42,7 @@
int32_t nextPatchId = 1;
};
-Configuration& getNullPrimaryConfiguration();
+std::unique_ptr<Configuration> getPrimaryConfiguration();
+std::unique_ptr<Configuration> getRSubmixConfiguration();
} // namespace aidl::android::hardware::audio::core::internal
diff --git a/audio/aidl/default/include/core-impl/EngineConfigXmlConverter.h b/audio/aidl/default/include/core-impl/EngineConfigXmlConverter.h
new file mode 100644
index 0000000..b34441d
--- /dev/null
+++ b/audio/aidl/default/include/core-impl/EngineConfigXmlConverter.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <string>
+#include <unordered_map>
+
+#include <utils/Errors.h>
+
+#include <android_audio_policy_engine_configuration.h>
+#include <android_audio_policy_engine_configuration_enums.h>
+
+#include "core-impl/XmlConverter.h"
+
+namespace aidl::android::hardware::audio::core::internal {
+
+class EngineConfigXmlConverter {
+ public:
+ explicit EngineConfigXmlConverter(const std::string& configFilePath)
+ : mConverter(configFilePath, &::android::audio::policy::engine::configuration::read) {
+ if (mConverter.getXsdcConfig()) {
+ init();
+ }
+ }
+
+ std::string getError() const { return mConverter.getError(); }
+ ::android::status_t getStatus() const { return mConverter.getStatus(); }
+
+ ::aidl::android::media::audio::common::AudioHalEngineConfig& getAidlEngineConfig();
+
+ private:
+ const std::optional<::android::audio::policy::engine::configuration::Configuration>&
+ getXsdcConfig() {
+ return mConverter.getXsdcConfig();
+ }
+ void init();
+ void initProductStrategyMap();
+ ::aidl::android::media::audio::common::AudioAttributes convertAudioAttributesToAidl(
+ const ::android::audio::policy::engine::configuration::AttributesType&
+ xsdcAudioAttributes);
+ ::aidl::android::media::audio::common::AudioHalAttributesGroup convertAttributesGroupToAidl(
+ const ::android::audio::policy::engine::configuration::AttributesGroup&
+ xsdcAttributesGroup);
+ ::aidl::android::media::audio::common::AudioHalCapCriterion convertCapCriterionToAidl(
+ const ::android::audio::policy::engine::configuration::CriterionType& xsdcCriterion);
+ ::aidl::android::media::audio::common::AudioHalCapCriterionType convertCapCriterionTypeToAidl(
+ const ::android::audio::policy::engine::configuration::CriterionTypeType&
+ xsdcCriterionType);
+ std::string convertCriterionTypeValueToAidl(
+ const ::android::audio::policy::engine::configuration::ValueType&
+ xsdcCriterionTypeValue);
+ ::aidl::android::media::audio::common::AudioHalVolumeCurve::CurvePoint convertCurvePointToAidl(
+ const std::string& xsdcCurvePoint);
+ ::aidl::android::media::audio::common::AudioHalProductStrategy convertProductStrategyToAidl(
+ const ::android::audio::policy::engine::configuration::ProductStrategies::
+ ProductStrategy& xsdcProductStrategy);
+ int convertProductStrategyNameToAidl(const std::string& xsdcProductStrategyName);
+ ::aidl::android::media::audio::common::AudioHalVolumeCurve convertVolumeCurveToAidl(
+ const ::android::audio::policy::engine::configuration::Volume& xsdcVolumeCurve);
+ ::aidl::android::media::audio::common::AudioHalVolumeGroup convertVolumeGroupToAidl(
+ const ::android::audio::policy::engine::configuration::VolumeGroupsType::VolumeGroup&
+ xsdcVolumeGroup);
+
+ ::aidl::android::media::audio::common::AudioHalEngineConfig mAidlEngineConfig;
+ XmlConverter<::android::audio::policy::engine::configuration::Configuration> mConverter;
+ std::unordered_map<std::string,
+ ::android::audio::policy::engine::configuration::AttributesRefType>
+ mAttributesReferenceMap;
+ std::unordered_map<std::string, ::android::audio::policy::engine::configuration::VolumeRef>
+ mVolumesReferenceMap;
+ std::unordered_map<std::string, int> mProductStrategyMap;
+ int mNextVendorStrategy = ::aidl::android::media::audio::common::AudioHalProductStrategy::
+ VENDOR_STRATEGY_ID_START;
+ std::optional<int> mDefaultProductStrategyId;
+};
+
+} // namespace aidl::android::hardware::audio::core::internal
diff --git a/audio/aidl/default/include/core-impl/Module.h b/audio/aidl/default/include/core-impl/Module.h
index 3509327..52fb54c 100644
--- a/audio/aidl/default/include/core-impl/Module.h
+++ b/audio/aidl/default/include/core-impl/Module.h
@@ -31,6 +31,9 @@
public:
// This value is used for all AudioPatches and reported by all streams.
static constexpr int32_t kLatencyMs = 10;
+ enum Type : int { DEFAULT, R_SUBMIX };
+
+ explicit Module(Type type) : mType(type) {}
private:
ndk::ScopedAStatus setModuleDebug(
@@ -105,6 +108,7 @@
// The maximum stream buffer size is 1 GiB = 2 ** 30 bytes;
static constexpr int32_t kMaximumStreamBufferSizeBytes = 1 << 30;
+ const Type mType;
std::unique_ptr<internal::Configuration> mConfig;
ModuleDebug mDebug;
// Since it is required to return the same instance of the ITelephony, even
diff --git a/audio/aidl/default/include/core-impl/XmlConverter.h b/audio/aidl/default/include/core-impl/XmlConverter.h
new file mode 100644
index 0000000..ec23edb
--- /dev/null
+++ b/audio/aidl/default/include/core-impl/XmlConverter.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <optional>
+#include <string>
+#include <unordered_map>
+
+#include <system/audio_config.h>
+#include <utils/Errors.h>
+
+namespace aidl::android::hardware::audio::core::internal {
+
+template <typename T>
+class XmlConverter {
+ public:
+ XmlConverter(const std::string& configFilePath,
+ std::function<std::optional<T>(const char*)> readXmlConfig)
+ : XmlConverter(configFilePath,
+ ::android::audio_is_readable_configuration_file(configFilePath.c_str()),
+ readXmlConfig) {}
+
+ const ::android::status_t& getStatus() const { return mStatus; }
+
+ const std::string& getError() const { return mErrorMessage; }
+
+ const std::optional<T>& getXsdcConfig() const { return mXsdcConfig; }
+
+ private:
+ XmlConverter(const std::string& configFilePath, const bool& isReadableConfigFile,
+ const std::function<std::optional<T>(const char*)>& readXmlConfig)
+ : mXsdcConfig{isReadableConfigFile ? readXmlConfig(configFilePath.c_str()) : std::nullopt},
+ mStatus(mXsdcConfig ? ::android::OK : ::android::NO_INIT),
+ mErrorMessage(generateError(configFilePath, isReadableConfigFile, mStatus)) {}
+
+ static std::string generateError(const std::string& configFilePath,
+ const bool& isReadableConfigFile,
+ const ::android::status_t& status) {
+ std::string errorMessage;
+ if (status != ::android::OK) {
+ if (!isReadableConfigFile) {
+ errorMessage = "Could not read requested config file:" + configFilePath;
+ } else {
+ errorMessage = "Invalid config file: " + configFilePath;
+ }
+ }
+ return errorMessage;
+ }
+
+ const std::optional<T> mXsdcConfig;
+ const ::android::status_t mStatus;
+ const std::string mErrorMessage;
+};
+
+/**
+ * Converts a vector of an xsd wrapper type to a flat vector of the
+ * corresponding AIDL type.
+ *
+ * Wrapper types are used in order to have well-formed xIncludes. In the
+ * example below, Modules is the wrapper type for Module.
+ * <Modules>
+ * <Module> ... </Module>
+ * <Module> ... </Module>
+ * </Modules>
+ */
+template <typename W, typename X, typename A>
+static std::vector<A> convertWrappedCollectionToAidl(
+ const std::vector<W>& xsdcWrapperTypeVec,
+ std::function<const std::vector<X>&(const W&)> getInnerTypeVec,
+ std::function<A(const X&)> convertToAidl) {
+ std::vector<A> resultAidlTypeVec;
+ if (!xsdcWrapperTypeVec.empty()) {
+ /*
+ * xsdcWrapperTypeVec likely only contains one element; that is, it's
+ * likely that all the inner types that we need to convert are inside of
+ * xsdcWrapperTypeVec[0].
+ */
+ resultAidlTypeVec.reserve(getInnerTypeVec(xsdcWrapperTypeVec[0]).size());
+ for (const W& xsdcWrapperType : xsdcWrapperTypeVec) {
+ std::transform(getInnerTypeVec(xsdcWrapperType).begin(),
+ getInnerTypeVec(xsdcWrapperType).end(),
+ std::back_inserter(resultAidlTypeVec), convertToAidl);
+ }
+ }
+ return resultAidlTypeVec;
+}
+
+template <typename X, typename A>
+static std::vector<A> convertCollectionToAidl(const std::vector<X>& xsdcTypeVec,
+ std::function<A(const X&)> convertToAidl) {
+ std::vector<A> resultAidlTypeVec;
+ resultAidlTypeVec.reserve(xsdcTypeVec.size());
+ std::transform(xsdcTypeVec.begin(), xsdcTypeVec.end(), std::back_inserter(resultAidlTypeVec),
+ convertToAidl);
+ return resultAidlTypeVec;
+}
+
+/**
+ * Generates a map of xsd references, keyed by reference name, given a
+ * vector of wrapper types for the reference.
+ *
+ * Wrapper types are used in order to have well-formed xIncludes. In the
+ * example below, Wrapper is the wrapper type for Reference.
+ * <Wrapper>
+ * <Reference> ... </Reference>
+ * <Reference> ... </Reference>
+ * </Wrapper>
+ */
+template <typename W, typename R>
+static std::unordered_map<std::string, R> generateReferenceMap(
+ const std::vector<W>& xsdcWrapperTypeVec) {
+ std::unordered_map<std::string, R> resultMap;
+ if (!xsdcWrapperTypeVec.empty()) {
+ /*
+ * xsdcWrapperTypeVec likely only contains one element; that is, it's
+ * likely that all the inner types that we need to convert are inside of
+ * xsdcWrapperTypeVec[0].
+ */
+ resultMap.reserve(xsdcWrapperTypeVec[0].getReference().size());
+ for (const W& xsdcWrapperType : xsdcWrapperTypeVec) {
+ for (const R& xsdcReference : xsdcWrapperType.getReference()) {
+ resultMap.insert({xsdcReference.getName(), xsdcReference});
+ }
+ }
+ }
+ return resultMap;
+}
+} // namespace aidl::android::hardware::audio::core::internal
diff --git a/audio/aidl/default/include/effect-impl/EffectContext.h b/audio/aidl/default/include/effect-impl/EffectContext.h
index f608e12..95645d5 100644
--- a/audio/aidl/default/include/effect-impl/EffectContext.h
+++ b/audio/aidl/default/include/effect-impl/EffectContext.h
@@ -16,16 +16,13 @@
#pragma once
#include <Utils.h>
-#include <android-base/logging.h>
-#include <utils/Log.h>
-#include <cstddef>
-#include <cstdint>
#include <memory>
-#include <utility>
#include <vector>
-#include <aidl/android/hardware/audio/effect/BnEffect.h>
+#include <android-base/logging.h>
#include <fmq/AidlMessageQueue.h>
+
+#include <aidl/android/hardware/audio/effect/BnEffect.h>
#include "EffectTypes.h"
namespace aidl::android::hardware::audio::effect {
@@ -74,13 +71,10 @@
std::shared_ptr<DataMQ> getOutputDataFmq() { return mOutputMQ; }
float* getWorkBuffer() { return static_cast<float*>(mWorkBuffer.data()); }
- // TODO: update with actual available size
- size_t availableToRead() { return mWorkBuffer.capacity(); }
- size_t availableToWrite() { return mWorkBuffer.capacity(); }
// reset buffer status by abandon all data and status in FMQ
void resetBuffer() {
- auto buffer = getWorkBuffer();
+ auto buffer = static_cast<float*>(mWorkBuffer.data());
std::vector<IEffect::Status> status(mStatusMQ->availableToRead());
mInputMQ->read(buffer, mInputMQ->availableToRead());
mOutputMQ->read(buffer, mOutputMQ->availableToRead());
@@ -89,9 +83,9 @@
void dupeFmq(IEffect::OpenEffectReturn* effectRet) {
if (effectRet) {
- effectRet->statusMQ = getStatusFmq()->dupeDesc();
- effectRet->inputDataMQ = getInputDataFmq()->dupeDesc();
- effectRet->outputDataMQ = getOutputDataFmq()->dupeDesc();
+ effectRet->statusMQ = mStatusMQ->dupeDesc();
+ effectRet->inputDataMQ = mInputMQ->dupeDesc();
+ effectRet->outputDataMQ = mOutputMQ->dupeDesc();
}
}
size_t getInputFrameSize() { return mInputFrameSize; }
@@ -138,7 +132,8 @@
protected:
// common parameters
int mSessionId = INVALID_AUDIO_SESSION_ID;
- size_t mInputFrameSize, mOutputFrameSize;
+ size_t mInputFrameSize;
+ size_t mOutputFrameSize;
Parameter::Common mCommon;
aidl::android::media::audio::common::AudioDeviceDescription mOutputDevice;
aidl::android::media::audio::common::AudioMode mMode;
diff --git a/audio/aidl/default/include/effect-impl/EffectImpl.h b/audio/aidl/default/include/effect-impl/EffectImpl.h
index d9825da..e7d081f 100644
--- a/audio/aidl/default/include/effect-impl/EffectImpl.h
+++ b/audio/aidl/default/include/effect-impl/EffectImpl.h
@@ -15,45 +15,38 @@
*/
#pragma once
-#include <aidl/android/hardware/audio/effect/BnEffect.h>
-#include <fmq/AidlMessageQueue.h>
#include <cstdlib>
#include <memory>
-#include <mutex>
+#include <aidl/android/hardware/audio/effect/BnEffect.h>
+#include <fmq/AidlMessageQueue.h>
+
+#include "EffectContext.h"
+#include "EffectThread.h"
#include "EffectTypes.h"
#include "effect-impl/EffectContext.h"
+#include "effect-impl/EffectThread.h"
#include "effect-impl/EffectTypes.h"
-#include "effect-impl/EffectWorker.h"
+
+extern "C" binder_exception_t destroyEffect(
+ const std::shared_ptr<aidl::android::hardware::audio::effect::IEffect>& instanceSp);
namespace aidl::android::hardware::audio::effect {
-class EffectImpl : public BnEffect, public EffectWorker {
+class EffectImpl : public BnEffect, public EffectThread {
public:
EffectImpl() = default;
virtual ~EffectImpl() = default;
- /**
- * Each effect implementation CAN override these methods if necessary
- * If you would like implement IEffect::open completely, override EffectImpl::open(), if you
- * want to keep most of EffectImpl logic but have a little customize, try override openImpl().
- * openImpl() will be called at the beginning of EffectImpl::open() without lock protection.
- *
- * Same for closeImpl().
- */
virtual ndk::ScopedAStatus open(const Parameter::Common& common,
const std::optional<Parameter::Specific>& specific,
OpenEffectReturn* ret) override;
virtual ndk::ScopedAStatus close() override;
virtual ndk::ScopedAStatus command(CommandId id) override;
- virtual ndk::ScopedAStatus commandStart() { return ndk::ScopedAStatus::ok(); }
- virtual ndk::ScopedAStatus commandStop() { return ndk::ScopedAStatus::ok(); }
- virtual ndk::ScopedAStatus commandReset() { return ndk::ScopedAStatus::ok(); }
virtual ndk::ScopedAStatus getState(State* state) override;
virtual ndk::ScopedAStatus setParameter(const Parameter& param) override;
virtual ndk::ScopedAStatus getParameter(const Parameter::Id& id, Parameter* param) override;
- virtual IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
virtual ndk::ScopedAStatus setParameterCommon(const Parameter& param);
virtual ndk::ScopedAStatus getParameterCommon(const Parameter::Tag& tag, Parameter* param);
@@ -63,21 +56,32 @@
virtual ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) = 0;
virtual ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) = 0;
+
+ virtual std::string getEffectName() = 0;
+ virtual IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+
+ /**
+ * Effect context methods must be implemented by each effect.
+ * Each effect can derive from EffectContext and define its own context, but must upcast to
+ * EffectContext for EffectImpl to use.
+ */
virtual std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) = 0;
+ virtual std::shared_ptr<EffectContext> getContext() = 0;
virtual RetCode releaseContext() = 0;
protected:
- /*
- * Lock is required if effectProcessImpl (which is running in an independent thread) needs to
- * access state and parameters.
- */
- std::mutex mMutex;
- State mState GUARDED_BY(mMutex) = State::INIT;
+ State mState = State::INIT;
IEffect::Status status(binder_status_t status, size_t consumed, size_t produced);
void cleanUp();
- private:
- std::shared_ptr<EffectContext> mContext GUARDED_BY(mMutex);
+ /**
+ * Optional CommandId handling methods for effects to override.
+ * For CommandId::START, EffectImpl call commandImpl before starting the EffectThread
+ * processing.
+ * For CommandId::STOP and CommandId::RESET, EffectImpl call commandImpl after stop the
+ * EffectThread processing.
+ */
+ virtual ndk::ScopedAStatus commandImpl(CommandId id);
};
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/effect-impl/EffectThread.h b/audio/aidl/default/include/effect-impl/EffectThread.h
index 09a0000..4b6cecd 100644
--- a/audio/aidl/default/include/effect-impl/EffectThread.h
+++ b/audio/aidl/default/include/effect-impl/EffectThread.h
@@ -22,6 +22,7 @@
#include <android-base/thread_annotations.h>
#include <system/thread_defs.h>
+#include "effect-impl/EffectContext.h"
#include "effect-impl/EffectTypes.h"
namespace aidl::android::hardware::audio::effect {
@@ -33,7 +34,7 @@
virtual ~EffectThread();
// called by effect implementation.
- RetCode createThread(const std::string& name,
+ RetCode createThread(std::shared_ptr<EffectContext> context, const std::string& name,
const int priority = ANDROID_PRIORITY_URGENT_AUDIO);
RetCode destroyThread();
RetCode startThread();
@@ -42,15 +43,43 @@
// Will call process() in a loop if the thread is running.
void threadLoop();
- // User of EffectThread must implement the effect processing logic in this method.
- virtual void process() = 0;
- const int MAX_TASK_COMM_LEN = 15;
+ /**
+ * @brief effectProcessImpl is running in worker thread which created in EffectThread.
+ *
+ * Effect implementation should think about concurrency in the implementation if necessary.
+ * Parameter setting usually implemented in context (derived from EffectContext), and some
+ * parameter maybe used in the processing, then effect implementation should consider using a
+ * mutex to protect these parameter.
+ *
+ * EffectThread will make sure effectProcessImpl only be called after startThread() successful
+ * and before stopThread() successful.
+ *
+ * @param in address of input float buffer.
+ * @param out address of output float buffer.
+ * @param samples number of samples to process.
+ * @return IEffect::Status
+ */
+ virtual IEffect::Status effectProcessImpl(float* in, float* out, int samples) = 0;
+
+ /**
+ * The default EffectThread::process() implementation doesn't need to lock. It will only
+ * access the FMQ and mWorkBuffer in EffectContext, since they will only be changed in
+ * EffectImpl IEffect::open() (in this case EffectThread just created and not running yet) and
+ * IEffect::command(CommandId::RESET) (in this case EffectThread already stopped).
+ *
+ * process() call effectProcessImpl for effect processing, and because effectProcessImpl is
+ * implemented by effects, process() must not hold lock before call into effectProcessImpl to
+ * avoid deadlock.
+ */
+ virtual void process();
private:
- std::mutex mMutex;
+ const int kMaxTaskNameLen = 15;
+ std::mutex mThreadMutex;
std::condition_variable mCv;
- bool mExit GUARDED_BY(mMutex) = false;
- bool mStop GUARDED_BY(mMutex) = true;
+ bool mExit GUARDED_BY(mThreadMutex) = false;
+ bool mStop GUARDED_BY(mThreadMutex) = true;
+ std::shared_ptr<EffectContext> mThreadContext GUARDED_BY(mThreadMutex);
std::thread mThread;
int mPriority;
std::string mName;
diff --git a/audio/aidl/default/include/effect-impl/EffectTypes.h b/audio/aidl/default/include/effect-impl/EffectTypes.h
index fc6a01d..58c8672 100644
--- a/audio/aidl/default/include/effect-impl/EffectTypes.h
+++ b/audio/aidl/default/include/effect-impl/EffectTypes.h
@@ -26,10 +26,14 @@
std::shared_ptr<aidl::android::hardware::audio::effect::IEffect>*);
typedef binder_exception_t (*EffectDestroyFunctor)(
const std::shared_ptr<aidl::android::hardware::audio::effect::IEffect>&);
+typedef binder_exception_t (*EffectQueryFunctor)(
+ const ::aidl::android::media::audio::common::AudioUuid*,
+ aidl::android::hardware::audio::effect::Descriptor*);
struct effect_dl_interface_s {
EffectCreateFunctor createEffectFunc;
EffectDestroyFunctor destroyEffectFunc;
+ EffectQueryFunctor queryEffectFunc;
};
namespace aidl::android::hardware::audio::effect {
@@ -102,6 +106,15 @@
} \
} while (0)
+#define RETURN_IF_BINDER_EXCEPTION(functor) \
+ { \
+ binder_exception_t exception = functor; \
+ if (EX_NONE != exception) { \
+ LOG(ERROR) << #functor << ": failed with error " << exception; \
+ return ndk::ScopedAStatus::fromExceptionCode(exception); \
+ } \
+ }
+
static inline bool stringToUuid(const char* str,
::aidl::android::media::audio::common::AudioUuid* uuid) {
RETURN_VALUE_IF(!uuid || !str, false, "nullPtr");
diff --git a/audio/aidl/default/include/effect-impl/EffectWorker.h b/audio/aidl/default/include/effect-impl/EffectWorker.h
index 6a78eab..b456817 100644
--- a/audio/aidl/default/include/effect-impl/EffectWorker.h
+++ b/audio/aidl/default/include/effect-impl/EffectWorker.h
@@ -63,7 +63,7 @@
// must implement by each effect implementation
// TODO: consider if this interface need adjustment to handle in-place processing
- virtual IEffect::Status effectProcessImpl(float* in, float* out, int processSamples) = 0;
+ virtual IEffect::Status effectProcessImpl(float* in, float* out, int samples) = 0;
private:
// make sure the context only set once.
diff --git a/audio/aidl/default/include/effectFactory-impl/EffectFactory.h b/audio/aidl/default/include/effectFactory-impl/EffectFactory.h
index 7edace0..5903276 100644
--- a/audio/aidl/default/include/effectFactory-impl/EffectFactory.h
+++ b/audio/aidl/default/include/effectFactory-impl/EffectFactory.h
@@ -20,6 +20,7 @@
#include <map>
#include <optional>
#include <set>
+#include <tuple>
#include <vector>
#include <aidl/android/hardware/audio/effect/BnFactory.h>
@@ -37,14 +38,14 @@
* @param in_type Type UUID.
* @param in_instance Instance UUID.
* @param in_proxy Proxy UUID.
- * @param out_descriptor List of identities .
+ * @param out_descriptor List of Descriptors.
* @return ndk::ScopedAStatus
*/
ndk::ScopedAStatus queryEffects(
const std::optional<::aidl::android::media::audio::common::AudioUuid>& in_type,
const std::optional<::aidl::android::media::audio::common::AudioUuid>& in_instance,
const std::optional<::aidl::android::media::audio::common::AudioUuid>& in_proxy,
- std::vector<Descriptor::Identity>* out_descriptor) override;
+ std::vector<Descriptor>* out_descriptor) override;
/**
* @brief Query list of defined processing, with the optional filter by AudioStreamType
@@ -82,12 +83,19 @@
const EffectConfig mConfig;
~Factory();
// Set of effect descriptors supported by the devices.
+ std::set<Descriptor> mDescSet;
std::set<Descriptor::Identity> mIdentitySet;
- std::map<aidl::android::media::audio::common::AudioUuid /* implementationUUID */,
- std::pair<std::unique_ptr<void, std::function<void(void*)>> /* dlHandle */,
- std::unique_ptr<struct effect_dl_interface_s>>>
- mEffectLibMap;
+ static constexpr int kMapEntryHandleIndex = 0;
+ static constexpr int kMapEntryInterfaceIndex = 1;
+ static constexpr int kMapEntryLibNameIndex = 2;
+ typedef std::tuple<std::unique_ptr<void, std::function<void(void*)>> /* dlHandle */,
+ std::unique_ptr<struct effect_dl_interface_s> /* interfaces */,
+ std::string /* library name */>
+ DlEntry;
+
+ std::map<aidl::android::media::audio::common::AudioUuid /* implUUID */, DlEntry> mEffectLibMap;
+
std::map<std::weak_ptr<IEffect>, aidl::android::media::audio::common::AudioUuid,
std::owner_less<>>
mEffectUuidMap;
@@ -101,6 +109,8 @@
const ::aidl::android::media::audio::common::AudioUuid& typeUuid,
const std::optional<::aidl::android::media::audio::common::AudioUuid> proxyUuid);
void loadEffectLibs();
+ /* Get effect_dl_interface_s from library handle */
+ void getDlSyms(DlEntry& entry);
};
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.cpp b/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.cpp
index 9d2b978..da02076 100644
--- a/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.cpp
+++ b/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.cpp
@@ -25,6 +25,7 @@
#include "LoudnessEnhancerSw.h"
+using aidl::android::hardware::audio::effect::Descriptor;
using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::hardware::audio::effect::kLoudnessEnhancerSwImplUUID;
using aidl::android::hardware::audio::effect::LoudnessEnhancerSw;
@@ -47,23 +48,28 @@
}
}
-extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
- if (!instanceSp) {
- return EX_NONE;
+extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) {
+ if (!in_impl_uuid || *in_impl_uuid != kLoudnessEnhancerSwImplUUID) {
+ LOG(ERROR) << __func__ << "uuid not supported";
+ return EX_ILLEGAL_ARGUMENT;
}
- State state;
- ndk::ScopedAStatus status = instanceSp->getState(&state);
- if (!status.isOk() || State::INIT != state) {
- LOG(ERROR) << __func__ << " instance " << instanceSp.get()
- << " in state: " << toString(state) << ", status: " << status.getDescription();
- return EX_ILLEGAL_STATE;
- }
- LOG(DEBUG) << __func__ << " instance " << instanceSp.get() << " destroyed";
+ *_aidl_return = LoudnessEnhancerSw::kDescriptor;
return EX_NONE;
}
namespace aidl::android::hardware::audio::effect {
+const std::string LoudnessEnhancerSw::kEffectName = "LoudnessEnhancerSw";
+const Descriptor LoudnessEnhancerSw::kDescriptor = {
+ .common = {.id = {.type = kLoudnessEnhancerTypeUUID,
+ .uuid = kLoudnessEnhancerSwImplUUID,
+ .proxy = std::nullopt},
+ .flags = {.type = Flags::Type::INSERT,
+ .insert = Flags::Insert::FIRST,
+ .volume = Flags::Volume::CTRL},
+ .name = LoudnessEnhancerSw::kEffectName,
+ .implementor = "The Android Open Source Project"}};
+
ndk::ScopedAStatus LoudnessEnhancerSw::getDescriptor(Descriptor* _aidl_return) {
LOG(DEBUG) << __func__ << kDescriptor.toString();
*_aidl_return = kDescriptor;
@@ -73,7 +79,6 @@
ndk::ScopedAStatus LoudnessEnhancerSw::setParameterSpecific(const Parameter::Specific& specific) {
RETURN_IF(Parameter::Specific::loudnessEnhancer != specific.getTag(), EX_ILLEGAL_ARGUMENT,
"EffectNotSupported");
- std::lock_guard lg(mMutex);
RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
auto& leParam = specific.get<Parameter::Specific::loudnessEnhancer>();
@@ -113,7 +118,6 @@
ndk::ScopedAStatus LoudnessEnhancerSw::getParameterLoudnessEnhancer(
const LoudnessEnhancer::Tag& tag, Parameter::Specific* specific) {
- std::lock_guard lg(mMutex);
RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
LoudnessEnhancer leParam;
@@ -136,9 +140,14 @@
std::shared_ptr<EffectContext> LoudnessEnhancerSw::createContext(const Parameter::Common& common) {
if (mContext) {
LOG(DEBUG) << __func__ << " context already exist";
- return mContext;
+ } else {
+ mContext = std::make_shared<LoudnessEnhancerSwContext>(1 /* statusFmqDepth */, common);
}
- mContext = std::make_shared<LoudnessEnhancerSwContext>(1 /* statusFmqDepth */, common);
+
+ return mContext;
+}
+
+std::shared_ptr<EffectContext> LoudnessEnhancerSw::getContext() {
return mContext;
}
@@ -150,13 +159,13 @@
}
// Processing method running in EffectWorker thread.
-IEffect::Status LoudnessEnhancerSw::effectProcessImpl(float* in, float* out, int process) {
+IEffect::Status LoudnessEnhancerSw::effectProcessImpl(float* in, float* out, int samples) {
// TODO: get data buffer and process.
- LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
- for (int i = 0; i < process; i++) {
+ LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
+ for (int i = 0; i < samples; i++) {
*out++ = *in++;
}
- return {STATUS_OK, process, process};
+ return {STATUS_OK, samples, samples};
}
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.h b/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.h
index 856bf0b..5da70c7 100644
--- a/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.h
+++ b/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.h
@@ -46,6 +46,9 @@
class LoudnessEnhancerSw final : public EffectImpl {
public:
+ static const std::string kEffectName;
+ static const LoudnessEnhancer::Capability kCapability;
+ static const Descriptor kDescriptor;
LoudnessEnhancerSw() { LOG(DEBUG) << __func__; }
~LoudnessEnhancerSw() {
cleanUp();
@@ -56,26 +59,16 @@
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) override;
- IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+ std::shared_ptr<EffectContext> getContext() override;
RetCode releaseContext() override;
+ IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+ std::string getEffectName() override { return kEffectName; }
+
private:
std::shared_ptr<LoudnessEnhancerSwContext> mContext;
- /* capabilities */
- const LoudnessEnhancer::Capability kCapability;
- /* Effect descriptor */
- const Descriptor kDescriptor = {
- .common = {.id = {.type = kLoudnessEnhancerTypeUUID,
- .uuid = kLoudnessEnhancerSwImplUUID,
- .proxy = std::nullopt},
- .flags = {.type = Flags::Type::INSERT,
- .insert = Flags::Insert::FIRST,
- .volume = Flags::Volume::CTRL},
- .name = "LoudnessEnhancerSw",
- .implementor = "The Android Open Source Project"},
- .capability = Capability::make<Capability::loudnessEnhancer>(kCapability)};
-
ndk::ScopedAStatus getParameterLoudnessEnhancer(const LoudnessEnhancer::Tag& tag,
Parameter::Specific* specific);
};
diff --git a/audio/aidl/default/main.cpp b/audio/aidl/default/main.cpp
index 7786cc6..b11af4e 100644
--- a/audio/aidl/default/main.cpp
+++ b/audio/aidl/default/main.cpp
@@ -17,14 +17,14 @@
#include <cstdlib>
#include <ctime>
-#include "core-impl/Config.h"
-#include "core-impl/Module.h"
-
#include <android-base/logging.h>
#include <android/binder_ibinder_platform.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
+#include "core-impl/Config.h"
+#include "core-impl/Module.h"
+
using aidl::android::hardware::audio::core::Config;
using aidl::android::hardware::audio::core::Module;
@@ -43,14 +43,21 @@
AServiceManager_addService(config->asBinder().get(), configName.c_str());
CHECK_EQ(STATUS_OK, status);
- // Make the default module
- auto moduleDefault = ndk::SharedRefBase::make<Module>();
+ // Make modules
+ auto moduleDefault = ndk::SharedRefBase::make<Module>(Module::Type::DEFAULT);
+ const std::string moduleDefaultName = std::string() + Module::descriptor + "/default";
AIBinder_setMinSchedulerPolicy(moduleDefault->asBinder().get(), SCHED_NORMAL,
ANDROID_PRIORITY_AUDIO);
- const std::string moduleDefaultName = std::string() + Module::descriptor + "/default";
status = AServiceManager_addService(moduleDefault->asBinder().get(), moduleDefaultName.c_str());
CHECK_EQ(STATUS_OK, status);
+ auto moduleRSubmix = ndk::SharedRefBase::make<Module>(Module::Type::R_SUBMIX);
+ const std::string moduleRSubmixName = std::string() + Module::descriptor + "/r_submix";
+ AIBinder_setMinSchedulerPolicy(moduleRSubmix->asBinder().get(), SCHED_NORMAL,
+ ANDROID_PRIORITY_AUDIO);
+ status = AServiceManager_addService(moduleRSubmix->asBinder().get(), moduleRSubmixName.c_str());
+ CHECK_EQ(STATUS_OK, status);
+
ABinderProcess_joinThreadPool();
return EXIT_FAILURE; // should not reach
}
diff --git a/audio/aidl/default/presetReverb/PresetReverbSw.cpp b/audio/aidl/default/presetReverb/PresetReverbSw.cpp
index 069d0ff..1b9d614 100644
--- a/audio/aidl/default/presetReverb/PresetReverbSw.cpp
+++ b/audio/aidl/default/presetReverb/PresetReverbSw.cpp
@@ -25,6 +25,7 @@
#include "PresetReverbSw.h"
+using aidl::android::hardware::audio::effect::Descriptor;
using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::hardware::audio::effect::kPresetReverbSwImplUUID;
using aidl::android::hardware::audio::effect::PresetReverbSw;
@@ -47,23 +48,30 @@
}
}
-extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
- if (!instanceSp) {
- return EX_NONE;
+extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) {
+ if (!in_impl_uuid || *in_impl_uuid != kPresetReverbSwImplUUID) {
+ LOG(ERROR) << __func__ << "uuid not supported";
+ return EX_ILLEGAL_ARGUMENT;
}
- State state;
- ndk::ScopedAStatus status = instanceSp->getState(&state);
- if (!status.isOk() || State::INIT != state) {
- LOG(ERROR) << __func__ << " instance " << instanceSp.get()
- << " in state: " << toString(state) << ", status: " << status.getDescription();
- return EX_ILLEGAL_STATE;
- }
- LOG(DEBUG) << __func__ << " instance " << instanceSp.get() << " destroyed";
+ *_aidl_return = PresetReverbSw::kDescriptor;
return EX_NONE;
}
namespace aidl::android::hardware::audio::effect {
+const std::string PresetReverbSw::kEffectName = "PresetReverbSw";
+const PresetReverb::Capability PresetReverbSw::kCapability;
+const Descriptor PresetReverbSw::kDescriptor = {
+ .common = {.id = {.type = kPresetReverbTypeUUID,
+ .uuid = kPresetReverbSwImplUUID,
+ .proxy = std::nullopt},
+ .flags = {.type = Flags::Type::INSERT,
+ .insert = Flags::Insert::FIRST,
+ .volume = Flags::Volume::CTRL},
+ .name = PresetReverbSw::kEffectName,
+ .implementor = "The Android Open Source Project"},
+ .capability = Capability::make<Capability::presetReverb>(PresetReverbSw::kCapability)};
+
ndk::ScopedAStatus PresetReverbSw::getDescriptor(Descriptor* _aidl_return) {
LOG(DEBUG) << __func__ << kDescriptor.toString();
*_aidl_return = kDescriptor;
@@ -71,12 +79,10 @@
}
ndk::ScopedAStatus PresetReverbSw::setParameterSpecific(const Parameter::Specific& specific) {
- RETURN_IF(Parameter::Specific::reverb != specific.getTag(), EX_ILLEGAL_ARGUMENT,
+ RETURN_IF(Parameter::Specific::presetReverb != specific.getTag(), EX_ILLEGAL_ARGUMENT,
"EffectNotSupported");
- std::lock_guard lg(mMutex);
- RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
- mSpecificParam = specific.get<Parameter::Specific::reverb>();
+ mSpecificParam = specific.get<Parameter::Specific::presetReverb>();
LOG(DEBUG) << __func__ << " success with: " << specific.toString();
return ndk::ScopedAStatus::ok();
}
@@ -84,17 +90,22 @@
ndk::ScopedAStatus PresetReverbSw::getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) {
auto tag = id.getTag();
- RETURN_IF(Parameter::Id::reverbTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
- specific->set<Parameter::Specific::reverb>(mSpecificParam);
+ RETURN_IF(Parameter::Id::presetReverbTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
+ specific->set<Parameter::Specific::presetReverb>(mSpecificParam);
return ndk::ScopedAStatus::ok();
}
std::shared_ptr<EffectContext> PresetReverbSw::createContext(const Parameter::Common& common) {
if (mContext) {
LOG(DEBUG) << __func__ << " context already exist";
- return mContext;
+ } else {
+ mContext = std::make_shared<PresetReverbSwContext>(1 /* statusFmqDepth */, common);
}
- mContext = std::make_shared<PresetReverbSwContext>(1 /* statusFmqDepth */, common);
+
+ return mContext;
+}
+
+std::shared_ptr<EffectContext> PresetReverbSw::getContext() {
return mContext;
}
@@ -106,13 +117,13 @@
}
// Processing method running in EffectWorker thread.
-IEffect::Status PresetReverbSw::effectProcessImpl(float* in, float* out, int process) {
+IEffect::Status PresetReverbSw::effectProcessImpl(float* in, float* out, int samples) {
// TODO: get data buffer and process.
- LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
- for (int i = 0; i < process; i++) {
+ LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
+ for (int i = 0; i < samples; i++) {
*out++ = *in++;
}
- return {STATUS_OK, process, process};
+ return {STATUS_OK, samples, samples};
}
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/presetReverb/PresetReverbSw.h b/audio/aidl/default/presetReverb/PresetReverbSw.h
index 75a5a94..43ed36e 100644
--- a/audio/aidl/default/presetReverb/PresetReverbSw.h
+++ b/audio/aidl/default/presetReverb/PresetReverbSw.h
@@ -37,6 +37,9 @@
class PresetReverbSw final : public EffectImpl {
public:
+ static const std::string kEffectName;
+ static const PresetReverb::Capability kCapability;
+ static const Descriptor kDescriptor;
PresetReverbSw() { LOG(DEBUG) << __func__; }
~PresetReverbSw() {
cleanUp();
@@ -47,27 +50,17 @@
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) override;
- IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+ std::shared_ptr<EffectContext> getContext() override;
RetCode releaseContext() override;
+ IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+ std::string getEffectName() override { return kEffectName; }
+
private:
std::shared_ptr<PresetReverbSwContext> mContext;
- /* capabilities */
- const Reverb::Capability kCapability;
- /* Effect descriptor */
- const Descriptor kDescriptor = {
- .common = {.id = {.type = kPresetReverbTypeUUID,
- .uuid = kPresetReverbSwImplUUID,
- .proxy = std::nullopt},
- .flags = {.type = Flags::Type::INSERT,
- .insert = Flags::Insert::FIRST,
- .volume = Flags::Volume::CTRL},
- .name = "PresetReverbSw",
- .implementor = "The Android Open Source Project"},
- .capability = Capability::make<Capability::reverb>(kCapability)};
-
/* parameters */
- Reverb mSpecificParam;
+ PresetReverb mSpecificParam;
};
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/virtualizer/VirtualizerSw.cpp b/audio/aidl/default/virtualizer/VirtualizerSw.cpp
index 9688fc8..faa630e 100644
--- a/audio/aidl/default/virtualizer/VirtualizerSw.cpp
+++ b/audio/aidl/default/virtualizer/VirtualizerSw.cpp
@@ -25,6 +25,7 @@
#include "VirtualizerSw.h"
+using aidl::android::hardware::audio::effect::Descriptor;
using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::hardware::audio::effect::kVirtualizerSwImplUUID;
using aidl::android::hardware::audio::effect::State;
@@ -47,23 +48,30 @@
}
}
-extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
- if (!instanceSp) {
- return EX_NONE;
+extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) {
+ if (!in_impl_uuid || *in_impl_uuid != kVirtualizerSwImplUUID) {
+ LOG(ERROR) << __func__ << "uuid not supported";
+ return EX_ILLEGAL_ARGUMENT;
}
- State state;
- ndk::ScopedAStatus status = instanceSp->getState(&state);
- if (!status.isOk() || State::INIT != state) {
- LOG(ERROR) << __func__ << " instance " << instanceSp.get()
- << " in state: " << toString(state) << ", status: " << status.getDescription();
- return EX_ILLEGAL_STATE;
- }
- LOG(DEBUG) << __func__ << " instance " << instanceSp.get() << " destroyed";
+ *_aidl_return = VirtualizerSw::kDescriptor;
return EX_NONE;
}
namespace aidl::android::hardware::audio::effect {
+const std::string VirtualizerSw::kEffectName = "VirtualizerSw";
+const Virtualizer::Capability VirtualizerSw::kCapability;
+const Descriptor VirtualizerSw::kDescriptor = {
+ .common = {.id = {.type = kVirtualizerTypeUUID,
+ .uuid = kVirtualizerSwImplUUID,
+ .proxy = std::nullopt},
+ .flags = {.type = Flags::Type::INSERT,
+ .insert = Flags::Insert::FIRST,
+ .volume = Flags::Volume::CTRL},
+ .name = VirtualizerSw::kEffectName,
+ .implementor = "The Android Open Source Project"},
+ .capability = Capability::make<Capability::virtualizer>(VirtualizerSw::kCapability)};
+
ndk::ScopedAStatus VirtualizerSw::getDescriptor(Descriptor* _aidl_return) {
LOG(DEBUG) << __func__ << kDescriptor.toString();
*_aidl_return = kDescriptor;
@@ -73,8 +81,6 @@
ndk::ScopedAStatus VirtualizerSw::setParameterSpecific(const Parameter::Specific& specific) {
RETURN_IF(Parameter::Specific::virtualizer != specific.getTag(), EX_ILLEGAL_ARGUMENT,
"EffectNotSupported");
- std::lock_guard lg(mMutex);
- RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
mSpecificParam = specific.get<Parameter::Specific::virtualizer>();
LOG(DEBUG) << __func__ << " success with: " << specific.toString();
@@ -92,9 +98,14 @@
std::shared_ptr<EffectContext> VirtualizerSw::createContext(const Parameter::Common& common) {
if (mContext) {
LOG(DEBUG) << __func__ << " context already exist";
- return mContext;
+ } else {
+ mContext = std::make_shared<VirtualizerSwContext>(1 /* statusFmqDepth */, common);
}
- mContext = std::make_shared<VirtualizerSwContext>(1 /* statusFmqDepth */, common);
+
+ return mContext;
+}
+
+std::shared_ptr<EffectContext> VirtualizerSw::getContext() {
return mContext;
}
@@ -106,13 +117,13 @@
}
// Processing method running in EffectWorker thread.
-IEffect::Status VirtualizerSw::effectProcessImpl(float* in, float* out, int process) {
+IEffect::Status VirtualizerSw::effectProcessImpl(float* in, float* out, int samples) {
// TODO: get data buffer and process.
- LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
- for (int i = 0; i < process; i++) {
+ LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
+ for (int i = 0; i < samples; i++) {
*out++ = *in++;
}
- return {STATUS_OK, process, process};
+ return {STATUS_OK, samples, samples};
}
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/virtualizer/VirtualizerSw.h b/audio/aidl/default/virtualizer/VirtualizerSw.h
index e4de8b3..4a05678 100644
--- a/audio/aidl/default/virtualizer/VirtualizerSw.h
+++ b/audio/aidl/default/virtualizer/VirtualizerSw.h
@@ -37,6 +37,9 @@
class VirtualizerSw final : public EffectImpl {
public:
+ static const std::string kEffectName;
+ static const Virtualizer::Capability kCapability;
+ static const Descriptor kDescriptor;
VirtualizerSw() { LOG(DEBUG) << __func__; }
~VirtualizerSw() {
cleanUp();
@@ -47,26 +50,16 @@
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) override;
- IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+ std::shared_ptr<EffectContext> getContext() override;
RetCode releaseContext() override;
+ IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+ std::string getEffectName() override { return kEffectName; }
+
private:
std::shared_ptr<VirtualizerSwContext> mContext;
- /* capabilities */
- const Virtualizer::Capability kCapability;
- /* Effect descriptor */
- const Descriptor kDescriptor = {
- .common = {.id = {.type = kVirtualizerTypeUUID,
- .uuid = kVirtualizerSwImplUUID,
- .proxy = std::nullopt},
- .flags = {.type = Flags::Type::INSERT,
- .insert = Flags::Insert::FIRST,
- .volume = Flags::Volume::CTRL},
- .name = "VirtualizerSw",
- .implementor = "The Android Open Source Project"},
- .capability = Capability::make<Capability::virtualizer>(kCapability)};
-
/* parameters */
Virtualizer mSpecificParam;
};
diff --git a/audio/aidl/default/visualizer/VisualizerSw.cpp b/audio/aidl/default/visualizer/VisualizerSw.cpp
index 24a7bef..b898c00 100644
--- a/audio/aidl/default/visualizer/VisualizerSw.cpp
+++ b/audio/aidl/default/visualizer/VisualizerSw.cpp
@@ -25,6 +25,7 @@
#include "VisualizerSw.h"
+using aidl::android::hardware::audio::effect::Descriptor;
using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::hardware::audio::effect::kVisualizerSwImplUUID;
using aidl::android::hardware::audio::effect::State;
@@ -47,23 +48,30 @@
}
}
-extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
- if (!instanceSp) {
- return EX_NONE;
+extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) {
+ if (!in_impl_uuid || *in_impl_uuid != kVisualizerSwImplUUID) {
+ LOG(ERROR) << __func__ << "uuid not supported";
+ return EX_ILLEGAL_ARGUMENT;
}
- State state;
- ndk::ScopedAStatus status = instanceSp->getState(&state);
- if (!status.isOk() || State::INIT != state) {
- LOG(ERROR) << __func__ << " instance " << instanceSp.get()
- << " in state: " << toString(state) << ", status: " << status.getDescription();
- return EX_ILLEGAL_STATE;
- }
- LOG(DEBUG) << __func__ << " instance " << instanceSp.get() << " destroyed";
+ *_aidl_return = VisualizerSw::kDescriptor;
return EX_NONE;
}
namespace aidl::android::hardware::audio::effect {
+const std::string VisualizerSw::kEffectName = "VisualizerSw";
+const Visualizer::Capability VisualizerSw::kCapability;
+const Descriptor VisualizerSw::kDescriptor = {
+ .common = {.id = {.type = kVisualizerTypeUUID,
+ .uuid = kVisualizerSwImplUUID,
+ .proxy = std::nullopt},
+ .flags = {.type = Flags::Type::INSERT,
+ .insert = Flags::Insert::FIRST,
+ .volume = Flags::Volume::CTRL},
+ .name = VisualizerSw::kEffectName,
+ .implementor = "The Android Open Source Project"},
+ .capability = Capability::make<Capability::visualizer>(VisualizerSw::kCapability)};
+
ndk::ScopedAStatus VisualizerSw::getDescriptor(Descriptor* _aidl_return) {
LOG(DEBUG) << __func__ << kDescriptor.toString();
*_aidl_return = kDescriptor;
@@ -73,8 +81,6 @@
ndk::ScopedAStatus VisualizerSw::setParameterSpecific(const Parameter::Specific& specific) {
RETURN_IF(Parameter::Specific::visualizer != specific.getTag(), EX_ILLEGAL_ARGUMENT,
"EffectNotSupported");
- std::lock_guard lg(mMutex);
- RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
mSpecificParam = specific.get<Parameter::Specific::visualizer>();
LOG(DEBUG) << __func__ << " success with: " << specific.toString();
@@ -92,9 +98,14 @@
std::shared_ptr<EffectContext> VisualizerSw::createContext(const Parameter::Common& common) {
if (mContext) {
LOG(DEBUG) << __func__ << " context already exist";
- return mContext;
+ } else {
+ mContext = std::make_shared<VisualizerSwContext>(1 /* statusFmqDepth */, common);
}
- mContext = std::make_shared<VisualizerSwContext>(1 /* statusFmqDepth */, common);
+
+ return mContext;
+}
+
+std::shared_ptr<EffectContext> VisualizerSw::getContext() {
return mContext;
}
@@ -106,13 +117,13 @@
}
// Processing method running in EffectWorker thread.
-IEffect::Status VisualizerSw::effectProcessImpl(float* in, float* out, int process) {
+IEffect::Status VisualizerSw::effectProcessImpl(float* in, float* out, int samples) {
// TODO: get data buffer and process.
- LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
- for (int i = 0; i < process; i++) {
+ LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
+ for (int i = 0; i < samples; i++) {
*out++ = *in++;
}
- return {STATUS_OK, process, process};
+ return {STATUS_OK, samples, samples};
}
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/visualizer/VisualizerSw.h b/audio/aidl/default/visualizer/VisualizerSw.h
index bccd6e9..24b92dd 100644
--- a/audio/aidl/default/visualizer/VisualizerSw.h
+++ b/audio/aidl/default/visualizer/VisualizerSw.h
@@ -37,6 +37,9 @@
class VisualizerSw final : public EffectImpl {
public:
+ static const std::string kEffectName;
+ static const Visualizer::Capability kCapability;
+ static const Descriptor kDescriptor;
VisualizerSw() { LOG(DEBUG) << __func__; }
~VisualizerSw() {
cleanUp();
@@ -47,26 +50,16 @@
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) override;
- IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+ std::shared_ptr<EffectContext> getContext() override;
RetCode releaseContext() override;
+ IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+ std::string getEffectName() override { return kEffectName; }
+
private:
std::shared_ptr<VisualizerSwContext> mContext;
- /* capabilities */
- const Visualizer::Capability kCapability;
- /* Effect descriptor */
- const Descriptor kDescriptor = {
- .common = {.id = {.type = kVisualizerTypeUUID,
- .uuid = kVisualizerSwImplUUID,
- .proxy = std::nullopt},
- .flags = {.type = Flags::Type::INSERT,
- .insert = Flags::Insert::FIRST,
- .volume = Flags::Volume::CTRL},
- .name = "VisualizerSw",
- .implementor = "The Android Open Source Project"},
- .capability = Capability::make<Capability::visualizer>(kCapability)};
-
/* parameters */
Visualizer mSpecificParam;
};
diff --git a/audio/aidl/default/volume/VolumeSw.cpp b/audio/aidl/default/volume/VolumeSw.cpp
index b8af921..6fce16e 100644
--- a/audio/aidl/default/volume/VolumeSw.cpp
+++ b/audio/aidl/default/volume/VolumeSw.cpp
@@ -25,6 +25,7 @@
#include "VolumeSw.h"
+using aidl::android::hardware::audio::effect::Descriptor;
using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::hardware::audio::effect::kVolumeSwImplUUID;
using aidl::android::hardware::audio::effect::State;
@@ -47,23 +48,30 @@
}
}
-extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
- if (!instanceSp) {
- return EX_NONE;
+extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) {
+ if (!in_impl_uuid || *in_impl_uuid != kVolumeSwImplUUID) {
+ LOG(ERROR) << __func__ << "uuid not supported";
+ return EX_ILLEGAL_ARGUMENT;
}
- State state;
- ndk::ScopedAStatus status = instanceSp->getState(&state);
- if (!status.isOk() || State::INIT != state) {
- LOG(ERROR) << __func__ << " instance " << instanceSp.get()
- << " in state: " << toString(state) << ", status: " << status.getDescription();
- return EX_ILLEGAL_STATE;
- }
- LOG(DEBUG) << __func__ << " instance " << instanceSp.get() << " destroyed";
+ *_aidl_return = VolumeSw::kDescriptor;
return EX_NONE;
}
namespace aidl::android::hardware::audio::effect {
+const std::string VolumeSw::kEffectName = "VolumeSw";
+const Volume::Capability VolumeSw::kCapability;
+const Descriptor VolumeSw::kDescriptor = {
+ .common = {.id = {.type = kVolumeTypeUUID,
+ .uuid = kVolumeSwImplUUID,
+ .proxy = std::nullopt},
+ .flags = {.type = Flags::Type::INSERT,
+ .insert = Flags::Insert::FIRST,
+ .volume = Flags::Volume::CTRL},
+ .name = VolumeSw::kEffectName,
+ .implementor = "The Android Open Source Project"},
+ .capability = Capability::make<Capability::volume>(VolumeSw::kCapability)};
+
ndk::ScopedAStatus VolumeSw::getDescriptor(Descriptor* _aidl_return) {
LOG(DEBUG) << __func__ << kDescriptor.toString();
*_aidl_return = kDescriptor;
@@ -73,8 +81,6 @@
ndk::ScopedAStatus VolumeSw::setParameterSpecific(const Parameter::Specific& specific) {
RETURN_IF(Parameter::Specific::volume != specific.getTag(), EX_ILLEGAL_ARGUMENT,
"EffectNotSupported");
- std::lock_guard lg(mMutex);
- RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
mSpecificParam = specific.get<Parameter::Specific::volume>();
LOG(DEBUG) << __func__ << " success with: " << specific.toString();
@@ -92,9 +98,14 @@
std::shared_ptr<EffectContext> VolumeSw::createContext(const Parameter::Common& common) {
if (mContext) {
LOG(DEBUG) << __func__ << " context already exist";
- return mContext;
+ } else {
+ mContext = std::make_shared<VolumeSwContext>(1 /* statusFmqDepth */, common);
}
- mContext = std::make_shared<VolumeSwContext>(1 /* statusFmqDepth */, common);
+
+ return mContext;
+}
+
+std::shared_ptr<EffectContext> VolumeSw::getContext() {
return mContext;
}
@@ -106,13 +117,13 @@
}
// Processing method running in EffectWorker thread.
-IEffect::Status VolumeSw::effectProcessImpl(float* in, float* out, int process) {
+IEffect::Status VolumeSw::effectProcessImpl(float* in, float* out, int samples) {
// TODO: get data buffer and process.
- LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
- for (int i = 0; i < process; i++) {
+ LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
+ for (int i = 0; i < samples; i++) {
*out++ = *in++;
}
- return {STATUS_OK, process, process};
+ return {STATUS_OK, samples, samples};
}
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/volume/VolumeSw.h b/audio/aidl/default/volume/VolumeSw.h
index 86e01c1..3bd29b9 100644
--- a/audio/aidl/default/volume/VolumeSw.h
+++ b/audio/aidl/default/volume/VolumeSw.h
@@ -37,6 +37,9 @@
class VolumeSw final : public EffectImpl {
public:
+ static const std::string kEffectName;
+ static const Volume::Capability kCapability;
+ static const Descriptor kDescriptor;
VolumeSw() { LOG(DEBUG) << __func__; }
~VolumeSw() {
cleanUp();
@@ -47,26 +50,16 @@
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) override;
- IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+ std::shared_ptr<EffectContext> getContext() override;
RetCode releaseContext() override;
+ IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+ std::string getEffectName() override { return kEffectName; }
+
private:
std::shared_ptr<VolumeSwContext> mContext;
- /* capabilities */
- const Volume::Capability kCapability;
- /* Effect descriptor */
- const Descriptor kDescriptor = {
- .common = {.id = {.type = kVolumeTypeUUID,
- .uuid = kVolumeSwImplUUID,
- .proxy = std::nullopt},
- .flags = {.type = Flags::Type::INSERT,
- .insert = Flags::Insert::FIRST,
- .volume = Flags::Volume::CTRL},
- .name = "VolumeSw",
- .implementor = "The Android Open Source Project"},
- .capability = Capability::make<Capability::volume>(kCapability)};
-
/* parameters */
Volume mSpecificParam;
};
diff --git a/audio/aidl/vts/Android.bp b/audio/aidl/vts/Android.bp
index 03e9fca..068742d 100644
--- a/audio/aidl/vts/Android.bp
+++ b/audio/aidl/vts/Android.bp
@@ -49,7 +49,8 @@
],
srcs: [
"ModuleConfig.cpp",
- "VtsHalAudioCoreTargetTest.cpp",
+ "VtsHalAudioCoreConfigTargetTest.cpp",
+ "VtsHalAudioCoreModuleTargetTest.cpp",
],
}
@@ -66,6 +67,12 @@
}
cc_test {
+ name: "VtsHalBassBoostTargetTest",
+ defaults: ["VtsHalAudioTargetTestDefaults"],
+ srcs: ["VtsHalBassBoostTargetTest.cpp"],
+}
+
+cc_test {
name: "VtsHalEqualizerTargetTest",
defaults: ["VtsHalAudioTargetTestDefaults"],
srcs: ["VtsHalEqualizerTargetTest.cpp"],
diff --git a/audio/aidl/vts/EffectFactoryHelper.h b/audio/aidl/vts/EffectFactoryHelper.h
index dc766dd..b649d9e 100644
--- a/audio/aidl/vts/EffectFactoryHelper.h
+++ b/audio/aidl/vts/EffectFactoryHelper.h
@@ -58,9 +58,11 @@
for (const auto& name : names) {
auto factory = IFactory::fromBinder(util.connectToService(name));
if (factory) {
- if (std::vector<Descriptor::Identity> ids;
- factory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids).isOk()) {
- for (const auto& id : ids) {
+ if (std::vector<Descriptor> descs;
+ factory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &descs)
+ .isOk()) {
+ for (const auto& desc : descs) {
+ const auto& id = desc.common.id;
if (type.has_value() && id.type != type.value()) {
continue;
}
diff --git a/audio/aidl/vts/VtsHalAudioCoreConfigTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreConfigTargetTest.cpp
new file mode 100644
index 0000000..bf73648
--- /dev/null
+++ b/audio/aidl/vts/VtsHalAudioCoreConfigTargetTest.cpp
@@ -0,0 +1,333 @@
+#include <set>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#define LOG_TAG "VtsHalAudioCore.Config"
+
+#include <Utils.h>
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/audio/core/IConfig.h>
+
+#include "AudioHalBinderServiceUtil.h"
+#include "TestUtils.h"
+
+using namespace android;
+using aidl::android::hardware::audio::core::IConfig;
+using aidl::android::media::audio::common::AudioAttributes;
+using aidl::android::media::audio::common::AudioFlag;
+using aidl::android::media::audio::common::AudioHalAttributesGroup;
+using aidl::android::media::audio::common::AudioHalCapCriterion;
+using aidl::android::media::audio::common::AudioHalCapCriterionType;
+using aidl::android::media::audio::common::AudioHalEngineConfig;
+using aidl::android::media::audio::common::AudioHalProductStrategy;
+using aidl::android::media::audio::common::AudioHalVolumeCurve;
+using aidl::android::media::audio::common::AudioHalVolumeGroup;
+using aidl::android::media::audio::common::AudioProductStrategyType;
+using aidl::android::media::audio::common::AudioSource;
+using aidl::android::media::audio::common::AudioStreamType;
+using aidl::android::media::audio::common::AudioUsage;
+
+class AudioCoreConfig : public testing::TestWithParam<std::string> {
+ public:
+ void SetUp() override { ASSERT_NO_FATAL_FAILURE(ConnectToService()); }
+ void ConnectToService() {
+ mConfig = IConfig::fromBinder(mBinderUtil.connectToService(GetParam()));
+ ASSERT_NE(mConfig, nullptr);
+ }
+
+ void RestartService() {
+ ASSERT_NE(mConfig, nullptr);
+ mEngineConfig.reset();
+ mConfig = IConfig::fromBinder(mBinderUtil.restartService());
+ ASSERT_NE(mConfig, nullptr);
+ }
+
+ void SetUpEngineConfig() {
+ if (mEngineConfig == nullptr) {
+ auto tempConfig = std::make_unique<AudioHalEngineConfig>();
+ ASSERT_IS_OK(mConfig->getEngineConfig(tempConfig.get()));
+ mEngineConfig = std::move(tempConfig);
+ }
+ }
+
+ static bool IsProductStrategyTypeReservedForSystemUse(const AudioProductStrategyType& pst) {
+ switch (pst) {
+ case AudioProductStrategyType::SYS_RESERVED_NONE:
+ case AudioProductStrategyType::SYS_RESERVED_REROUTING:
+ case AudioProductStrategyType::SYS_RESERVED_CALL_ASSISTANT:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ static bool IsStreamTypeReservedForSystemUse(const AudioStreamType& streamType) {
+ switch (streamType) {
+ case AudioStreamType::SYS_RESERVED_DEFAULT:
+ case AudioStreamType::SYS_RESERVED_REROUTING:
+ case AudioStreamType::SYS_RESERVED_PATCH:
+ case AudioStreamType::CALL_ASSISTANT:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ static bool IsAudioUsageValid(const AudioUsage& usage) {
+ switch (usage) {
+ case AudioUsage::INVALID:
+ case AudioUsage::SYS_RESERVED_NOTIFICATION_COMMUNICATION_REQUEST:
+ case AudioUsage::SYS_RESERVED_NOTIFICATION_COMMUNICATION_INSTANT:
+ case AudioUsage::SYS_RESERVED_NOTIFICATION_COMMUNICATION_DELAYED:
+ return false;
+ default:
+ return true;
+ }
+ }
+
+ static bool IsAudioSourceValid(const AudioSource& source) {
+ return (source != AudioSource::SYS_RESERVED_INVALID);
+ }
+
+ static const std::unordered_set<int>& GetSupportedAudioProductStrategyTypes() {
+ static const std::unordered_set<int> supportedAudioProductStrategyTypes = []() {
+ std::unordered_set<int> supportedStrategyTypes;
+ for (const auto& audioProductStrategyType :
+ ndk::enum_range<AudioProductStrategyType>()) {
+ if (!IsProductStrategyTypeReservedForSystemUse(audioProductStrategyType)) {
+ supportedStrategyTypes.insert(static_cast<int>(audioProductStrategyType));
+ }
+ }
+ return supportedStrategyTypes;
+ }();
+ return supportedAudioProductStrategyTypes;
+ }
+
+ static int GetSupportedAudioFlagsMask() {
+ static const int supportedAudioFlagsMask = []() {
+ int mask = 0;
+ for (const auto& audioFlag : ndk::enum_range<AudioFlag>()) {
+ mask |= static_cast<int>(audioFlag);
+ }
+ return mask;
+ }();
+ return supportedAudioFlagsMask;
+ }
+
+ /**
+ * Verify streamType is not INVALID if using default engine.
+ * Verify that streamType is a valid AudioStreamType if the associated
+ * volumeGroup minIndex/maxIndex is INDEX_DEFERRED_TO_AUDIO_SERVICE.
+ */
+ void ValidateAudioStreamType(const AudioStreamType& streamType,
+ const AudioHalVolumeGroup& associatedVolumeGroup) {
+ EXPECT_FALSE(IsStreamTypeReservedForSystemUse(streamType));
+ if (!mEngineConfig->capSpecificConfig ||
+ associatedVolumeGroup.minIndex ==
+ AudioHalVolumeGroup::INDEX_DEFERRED_TO_AUDIO_SERVICE) {
+ EXPECT_NE(streamType, AudioStreamType::INVALID);
+ }
+ }
+
+ /**
+ * Verify contained enum types are valid.
+ */
+ void ValidateAudioAttributes(const AudioAttributes& attributes) {
+ // No need to check contentType; there are no INVALID or SYS_RESERVED values
+ EXPECT_TRUE(IsAudioUsageValid(attributes.usage));
+ EXPECT_TRUE(IsAudioSourceValid(attributes.source));
+ EXPECT_EQ(attributes.flags & ~GetSupportedAudioFlagsMask(), 0);
+ }
+
+ /**
+ * Verify volumeGroupName corresponds to an AudioHalVolumeGroup.
+ * Validate contained types.
+ */
+ void ValidateAudioHalAttributesGroup(
+ const AudioHalAttributesGroup& attributesGroup,
+ std::unordered_map<std::string, const AudioHalVolumeGroup&>& volumeGroupMap,
+ std::unordered_set<std::string>& volumeGroupsUsedInStrategies) {
+ bool isVolumeGroupNameValid = volumeGroupMap.count(attributesGroup.volumeGroupName);
+ EXPECT_TRUE(isVolumeGroupNameValid);
+ EXPECT_NO_FATAL_FAILURE(ValidateAudioStreamType(
+ attributesGroup.streamType, volumeGroupMap.at(attributesGroup.volumeGroupName)));
+ if (isVolumeGroupNameValid) {
+ volumeGroupsUsedInStrategies.insert(attributesGroup.volumeGroupName);
+ }
+ for (const AudioAttributes& attr : attributesGroup.attributes) {
+ EXPECT_NO_FATAL_FAILURE(ValidateAudioAttributes(attr));
+ }
+ }
+
+ /**
+ * Default engine: verify productStrategy.id is valid AudioProductStrategyType.
+ * CAP engine: verify productStrategy.id is either valid AudioProductStrategyType
+ * or is >= VENDOR_STRATEGY_ID_START.
+ * Validate contained types.
+ */
+ void ValidateAudioHalProductStrategy(
+ const AudioHalProductStrategy& strategy,
+ std::unordered_map<std::string, const AudioHalVolumeGroup&>& volumeGroupMap,
+ std::unordered_set<std::string>& volumeGroupsUsedInStrategies) {
+ if (!mEngineConfig->capSpecificConfig ||
+ (strategy.id < AudioHalProductStrategy::VENDOR_STRATEGY_ID_START)) {
+ EXPECT_NE(GetSupportedAudioProductStrategyTypes().find(strategy.id),
+ GetSupportedAudioProductStrategyTypes().end());
+ }
+ for (const AudioHalAttributesGroup& attributesGroup : strategy.attributesGroups) {
+ EXPECT_NO_FATAL_FAILURE(ValidateAudioHalAttributesGroup(attributesGroup, volumeGroupMap,
+ volumeGroupsUsedInStrategies));
+ }
+ }
+
+ /**
+ * Verify curve point index is in [CurvePoint::MIN_INDEX, CurvePoint::MAX_INDEX].
+ */
+ void ValidateAudioHalVolumeCurve(const AudioHalVolumeCurve& volumeCurve) {
+ for (const AudioHalVolumeCurve::CurvePoint& curvePoint : volumeCurve.curvePoints) {
+ EXPECT_TRUE(curvePoint.index >= AudioHalVolumeCurve::CurvePoint::MIN_INDEX);
+ EXPECT_TRUE(curvePoint.index <= AudioHalVolumeCurve::CurvePoint::MAX_INDEX);
+ }
+ }
+
+ /**
+ * Verify minIndex, maxIndex are non-negative.
+ * Verify minIndex <= maxIndex.
+ * Verify no two volume curves use the same device category.
+ * Validate contained types.
+ */
+ void ValidateAudioHalVolumeGroup(const AudioHalVolumeGroup& volumeGroup) {
+ /**
+ * Legacy volume curves in audio_policy_configuration.xsd don't use
+ * minIndex or maxIndex. Use of audio_policy_configuration.xml still
+ * allows, and in some cases, relies on, AudioService to provide the min
+ * and max indices for a volumeGroup. From the VTS perspective, there is
+ * no way to differentiate between use of audio_policy_configuration.xml
+ * or audio_policy_engine_configuration.xml, as either one can be used
+ * for the default audio policy engine.
+ */
+ if (volumeGroup.minIndex != AudioHalVolumeGroup::INDEX_DEFERRED_TO_AUDIO_SERVICE ||
+ volumeGroup.maxIndex != AudioHalVolumeGroup::INDEX_DEFERRED_TO_AUDIO_SERVICE) {
+ EXPECT_TRUE(volumeGroup.minIndex >= 0);
+ EXPECT_TRUE(volumeGroup.maxIndex >= 0);
+ }
+ EXPECT_TRUE(volumeGroup.minIndex <= volumeGroup.maxIndex);
+ std::unordered_set<AudioHalVolumeCurve::DeviceCategory> deviceCategorySet;
+ for (const AudioHalVolumeCurve& volumeCurve : volumeGroup.volumeCurves) {
+ EXPECT_TRUE(deviceCategorySet.insert(volumeCurve.deviceCategory).second);
+ EXPECT_NO_FATAL_FAILURE(ValidateAudioHalVolumeCurve(volumeCurve));
+ }
+ }
+
+ /**
+ * Verify defaultLiteralValue is empty for inclusive criterion.
+ */
+ void ValidateAudioHalCapCriterion(const AudioHalCapCriterion& criterion,
+ const AudioHalCapCriterionType& criterionType) {
+ if (criterionType.isInclusive) {
+ EXPECT_TRUE(criterion.defaultLiteralValue.empty());
+ }
+ }
+
+ /**
+ * Verify values only contain alphanumeric characters.
+ */
+ void ValidateAudioHalCapCriterionType(const AudioHalCapCriterionType& criterionType) {
+ auto isNotAlnum = [](const char& c) { return !isalnum(c); };
+ for (const std::string& value : criterionType.values) {
+ EXPECT_EQ(find_if(value.begin(), value.end(), isNotAlnum), value.end());
+ }
+ }
+
+ /**
+ * Verify each criterionType has a unique name.
+ * Verify each criterion has a unique name.
+ * Verify each criterion maps to a criterionType.
+ * Verify each criterionType is used in a criterion.
+ * Validate contained types.
+ */
+ void ValidateCapSpecificConfig(const AudioHalEngineConfig::CapSpecificConfig& capCfg) {
+ EXPECT_FALSE(capCfg.criteria.empty());
+ EXPECT_FALSE(capCfg.criterionTypes.empty());
+ std::unordered_map<std::string, AudioHalCapCriterionType> criterionTypeMap;
+ for (const AudioHalCapCriterionType& criterionType : capCfg.criterionTypes) {
+ EXPECT_NO_FATAL_FAILURE(ValidateAudioHalCapCriterionType(criterionType));
+ EXPECT_TRUE(criterionTypeMap.insert({criterionType.name, criterionType}).second);
+ }
+ std::unordered_set<std::string> criterionNameSet;
+ for (const AudioHalCapCriterion& criterion : capCfg.criteria) {
+ EXPECT_TRUE(criterionNameSet.insert(criterion.name).second);
+ EXPECT_EQ(criterionTypeMap.count(criterion.criterionTypeName), 1UL);
+ EXPECT_NO_FATAL_FAILURE(ValidateAudioHalCapCriterion(
+ criterion, criterionTypeMap.at(criterion.criterionTypeName)));
+ }
+ EXPECT_EQ(criterionTypeMap.size(), criterionNameSet.size());
+ }
+
+ /**
+ * Verify VolumeGroups are non-empty.
+ * Verify defaultProductStrategyId matches one of the provided productStrategies.
+ * Otherwise, must be left uninitialized.
+ * Verify each volumeGroup has a unique name.
+ * Verify each productStrategy has a unique id.
+ * Verify each volumeGroup is used in a product strategy.
+ * CAP engine: verify productStrategies are non-empty.
+ * Validate contained types.
+ */
+ void ValidateAudioHalEngineConfig() {
+ EXPECT_NE(mEngineConfig->volumeGroups.size(), 0UL);
+ std::unordered_map<std::string, const AudioHalVolumeGroup&> volumeGroupMap;
+ for (const AudioHalVolumeGroup& volumeGroup : mEngineConfig->volumeGroups) {
+ EXPECT_TRUE(volumeGroupMap.insert({volumeGroup.name, volumeGroup}).second);
+ EXPECT_NO_FATAL_FAILURE(ValidateAudioHalVolumeGroup(volumeGroup));
+ }
+ if (!mEngineConfig->productStrategies.empty()) {
+ std::unordered_set<int> productStrategyIdSet;
+ std::unordered_set<std::string> volumeGroupsUsedInStrategies;
+ for (const AudioHalProductStrategy& strategy : mEngineConfig->productStrategies) {
+ EXPECT_TRUE(productStrategyIdSet.insert(strategy.id).second);
+ EXPECT_NO_FATAL_FAILURE(ValidateAudioHalProductStrategy(
+ strategy, volumeGroupMap, volumeGroupsUsedInStrategies));
+ }
+ EXPECT_TRUE(productStrategyIdSet.count(mEngineConfig->defaultProductStrategyId))
+ << "defaultProductStrategyId doesn't match any of the provided "
+ "productStrategies";
+ EXPECT_EQ(volumeGroupMap.size(), volumeGroupsUsedInStrategies.size());
+ } else {
+ EXPECT_EQ(mEngineConfig->defaultProductStrategyId,
+ static_cast<int>(AudioProductStrategyType::SYS_RESERVED_NONE))
+ << "defaultProductStrategyId defined, but no productStrategies were provided";
+ }
+ if (mEngineConfig->capSpecificConfig) {
+ EXPECT_NO_FATAL_FAILURE(
+ ValidateCapSpecificConfig(mEngineConfig->capSpecificConfig.value()));
+ EXPECT_FALSE(mEngineConfig->productStrategies.empty());
+ }
+ }
+
+ private:
+ std::shared_ptr<IConfig> mConfig;
+ std::unique_ptr<AudioHalEngineConfig> mEngineConfig;
+ AudioHalBinderServiceUtil mBinderUtil;
+};
+
+TEST_P(AudioCoreConfig, Published) {
+ // SetUp must complete with no failures.
+}
+
+TEST_P(AudioCoreConfig, CanBeRestarted) {
+ ASSERT_NO_FATAL_FAILURE(RestartService());
+}
+
+TEST_P(AudioCoreConfig, GetEngineConfigIsValid) {
+ ASSERT_NO_FATAL_FAILURE(SetUpEngineConfig());
+ EXPECT_NO_FATAL_FAILURE(ValidateAudioHalEngineConfig());
+}
+
+INSTANTIATE_TEST_SUITE_P(AudioCoreConfigTest, AudioCoreConfig,
+ testing::ValuesIn(android::getAidlHalInstanceNames(IConfig::descriptor)),
+ android::PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioCoreConfig);
diff --git a/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
similarity index 98%
rename from audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp
rename to audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
index c0c04f4..99771e6 100644
--- a/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
@@ -27,7 +27,7 @@
#include <variant>
#include <vector>
-#define LOG_TAG "VtsHalAudioCore"
+#define LOG_TAG "VtsHalAudioCore.Module"
#include <android-base/logging.h>
#include <StreamWorker.h>
@@ -79,6 +79,7 @@
using aidl::android::media::audio::common::AudioUsage;
using aidl::android::media::audio::common::Void;
using android::hardware::audio::common::isBitPositionFlagSet;
+using android::hardware::audio::common::isTelephonyDeviceType;
using android::hardware::audio::common::StreamLogic;
using android::hardware::audio::common::StreamWorker;
using ndk::enum_range;
@@ -490,16 +491,16 @@
private:
StreamDescriptor::State getState() const { return mSteps[mCurrentStep].second; }
bool isBurstBifurcation() {
- return getTrigger() == TransitionTrigger{kBurstCommand}&& getState() ==
- StreamDescriptor::State::TRANSFERRING;
+ return getTrigger() == TransitionTrigger{kBurstCommand} &&
+ getState() == StreamDescriptor::State::TRANSFERRING;
}
bool isPauseBifurcation() {
- return getTrigger() == TransitionTrigger{kPauseCommand}&& getState() ==
- StreamDescriptor::State::TRANSFER_PAUSED;
+ return getTrigger() == TransitionTrigger{kPauseCommand} &&
+ getState() == StreamDescriptor::State::TRANSFER_PAUSED;
}
bool isStartBifurcation() {
- return getTrigger() == TransitionTrigger{kStartCommand}&& getState() ==
- StreamDescriptor::State::TRANSFERRING;
+ return getTrigger() == TransitionTrigger{kStartCommand} &&
+ getState() == StreamDescriptor::State::TRANSFERRING;
}
const std::vector<StateTransition> mSteps;
size_t mCurrentStep = 0;
@@ -1902,9 +1903,13 @@
using AudioStreamIn = AudioStream<IStreamIn>;
using AudioStreamOut = AudioStream<IStreamOut>;
-#define TEST_IN_AND_OUT_STREAM(method_name) \
- TEST_P(AudioStreamIn, method_name) { ASSERT_NO_FATAL_FAILURE(method_name()); } \
- TEST_P(AudioStreamOut, method_name) { ASSERT_NO_FATAL_FAILURE(method_name()); }
+#define TEST_IN_AND_OUT_STREAM(method_name) \
+ TEST_P(AudioStreamIn, method_name) { \
+ ASSERT_NO_FATAL_FAILURE(method_name()); \
+ } \
+ TEST_P(AudioStreamOut, method_name) { \
+ ASSERT_NO_FATAL_FAILURE(method_name()); \
+ }
TEST_IN_AND_OUT_STREAM(CloseTwice);
TEST_IN_AND_OUT_STREAM(OpenAllConfigs);
@@ -2216,9 +2221,9 @@
}
}
- bool ValidateObservablePosition(const AudioPortConfig& /*portConfig*/) {
- // May return false based on the portConfig, e.g. for telephony ports.
- return true;
+ bool ValidateObservablePosition(const AudioPortConfig& devicePortConfig) {
+ return !isTelephonyDeviceType(
+ devicePortConfig.ext.get<AudioPortExt::Tag::device>().device.type.type);
}
// Set up a patch first, then open a stream.
@@ -2243,7 +2248,7 @@
worker.join();
EXPECT_FALSE(worker.hasError()) << worker.getError();
EXPECT_EQ("", driver.getUnexpectedStateTransition());
- if (ValidateObservablePosition(portConfig)) {
+ if (ValidateObservablePosition(devicePortConfig)) {
EXPECT_TRUE(driver.hasObservablePositionIncrease());
EXPECT_FALSE(driver.hasRetrogradeObservablePosition());
}
@@ -2271,7 +2276,7 @@
worker.join();
EXPECT_FALSE(worker.hasError()) << worker.getError();
EXPECT_EQ("", driver.getUnexpectedStateTransition());
- if (ValidateObservablePosition(portConfig)) {
+ if (ValidateObservablePosition(devicePortConfig)) {
EXPECT_TRUE(driver.hasObservablePositionIncrease());
EXPECT_FALSE(driver.hasRetrogradeObservablePosition());
}
@@ -2280,9 +2285,13 @@
using AudioStreamIoIn = AudioStreamIo<IStreamIn>;
using AudioStreamIoOut = AudioStreamIo<IStreamOut>;
-#define TEST_IN_AND_OUT_STREAM_IO(method_name) \
- TEST_P(AudioStreamIoIn, method_name) { ASSERT_NO_FATAL_FAILURE(method_name()); } \
- TEST_P(AudioStreamIoOut, method_name) { ASSERT_NO_FATAL_FAILURE(method_name()); }
+#define TEST_IN_AND_OUT_STREAM_IO(method_name) \
+ TEST_P(AudioStreamIoIn, method_name) { \
+ ASSERT_NO_FATAL_FAILURE(method_name()); \
+ } \
+ TEST_P(AudioStreamIoOut, method_name) { \
+ ASSERT_NO_FATAL_FAILURE(method_name()); \
+ }
TEST_IN_AND_OUT_STREAM_IO(Run);
@@ -2435,9 +2444,13 @@
// Not all tests require both directions, so parametrization would require
// more abstractions.
-#define TEST_PATCH_BOTH_DIRECTIONS(method_name) \
- TEST_P(AudioModulePatch, method_name##Input) { ASSERT_NO_FATAL_FAILURE(method_name(true)); } \
- TEST_P(AudioModulePatch, method_name##Output) { ASSERT_NO_FATAL_FAILURE(method_name(false)); }
+#define TEST_PATCH_BOTH_DIRECTIONS(method_name) \
+ TEST_P(AudioModulePatch, method_name##Input) { \
+ ASSERT_NO_FATAL_FAILURE(method_name(true)); \
+ } \
+ TEST_P(AudioModulePatch, method_name##Output) { \
+ ASSERT_NO_FATAL_FAILURE(method_name(false)); \
+ }
TEST_PATCH_BOTH_DIRECTIONS(ResetPortConfigUsedByPatch);
TEST_PATCH_BOTH_DIRECTIONS(SetInvalidPatch);
diff --git a/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp b/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp
index 8ae963e..21f5eb5 100644
--- a/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp
@@ -65,8 +65,10 @@
std::unique_ptr<EffectFactoryHelper> mFactoryHelper;
std::shared_ptr<IFactory> mEffectFactory;
std::vector<std::shared_ptr<IEffect>> mEffects;
- const Descriptor::Identity kNullDesc = {.uuid = kEffectNullUuid};
- const Descriptor::Identity kZeroDesc = {.uuid = kEffectZeroUuid};
+ const Descriptor::Identity kNullId = {.uuid = kEffectNullUuid};
+ const Descriptor::Identity kZeroId = {.uuid = kEffectZeroUuid};
+ const Descriptor kNullDesc = {.common.id = kNullId};
+ const Descriptor kZeroDesc = {.common.id = kZeroId};
template <typename Functor>
void ForEachId(const std::vector<Descriptor::Identity> ids, Functor functor) {
@@ -82,15 +84,15 @@
}
}
- std::vector<std::shared_ptr<IEffect>> createWithIds(
- const std::vector<Descriptor::Identity> ids,
- const binder_status_t expectStatus = EX_NONE) {
+ std::vector<std::shared_ptr<IEffect>> createWithDescs(
+ const std::vector<Descriptor> descs, const binder_status_t expectStatus = EX_NONE) {
std::vector<std::shared_ptr<IEffect>> effects;
- for (const auto& id : ids) {
+ for (const auto& desc : descs) {
+ const auto& uuid = desc.common.id.uuid;
std::shared_ptr<IEffect> effect;
- EXPECT_STATUS(expectStatus, mEffectFactory->createEffect(id.uuid, &effect));
+ EXPECT_STATUS(expectStatus, mEffectFactory->createEffect(uuid, &effect));
if (expectStatus == EX_NONE) {
- EXPECT_NE(effect, nullptr) << " null effect with uuid: " << id.uuid.toString();
+ EXPECT_NE(effect, nullptr) << " null effect with uuid: " << uuid.toString();
effects.push_back(std::move(effect));
}
}
@@ -102,9 +104,9 @@
EXPECT_STATUS(expectStatus, mEffectFactory->destroyEffect(effect));
}
}
- void creatAndDestroyIds(const std::vector<Descriptor::Identity> ids) {
- for (const auto& id : ids) {
- auto effects = createWithIds({id});
+ void creatAndDestroyDescs(const std::vector<Descriptor> descs) {
+ for (const auto& desc : descs) {
+ auto effects = createWithDescs({desc});
ASSERT_NO_FATAL_FAILURE(destroyEffects(effects));
}
}
@@ -128,7 +130,7 @@
* https://developer.android.com/reference/android/media/audiofx/AudioEffect
*/
TEST_P(EffectFactoryTest, ExpectAllAospEffectTypes) {
- std::vector<Descriptor::Identity> ids;
+ std::vector<Descriptor> descs;
std::set<AudioUuid> typeUuidSet(
{aidl::android::hardware::audio::effect::kBassBoostTypeUUID,
aidl::android::hardware::audio::effect::kEqualizerTypeUUID,
@@ -138,10 +140,10 @@
aidl::android::hardware::audio::effect::kHapticGeneratorTypeUUID,
aidl::android::hardware::audio::effect::kVirtualizerTypeUUID});
- EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids));
- EXPECT_TRUE(ids.size() >= typeUuidSet.size());
- for (const auto& id : ids) {
- typeUuidSet.erase(id.type);
+ EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &descs));
+ EXPECT_TRUE(descs.size() >= typeUuidSet.size());
+ for (const auto& desc : descs) {
+ typeUuidSet.erase(desc.common.id.type);
}
std::string msg = " missing type UUID:\n";
for (const auto& uuid : typeUuidSet) {
@@ -152,46 +154,46 @@
}
TEST_P(EffectFactoryTest, QueryNullTypeUuid) {
- std::vector<Descriptor::Identity> ids;
- EXPECT_IS_OK(mEffectFactory->queryEffects(kEffectNullUuid, std::nullopt, std::nullopt, &ids));
- EXPECT_EQ(ids.size(), 0UL);
+ std::vector<Descriptor> descs;
+ EXPECT_IS_OK(mEffectFactory->queryEffects(kEffectNullUuid, std::nullopt, std::nullopt, &descs));
+ EXPECT_EQ(descs.size(), 0UL);
}
TEST_P(EffectFactoryTest, QueriedNullImplUuid) {
- std::vector<Descriptor::Identity> ids;
- EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, kEffectNullUuid, std::nullopt, &ids));
- EXPECT_EQ(ids.size(), 0UL);
+ std::vector<Descriptor> descs;
+ EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, kEffectNullUuid, std::nullopt, &descs));
+ EXPECT_EQ(descs.size(), 0UL);
}
TEST_P(EffectFactoryTest, QueriedNullProxyUuid) {
- std::vector<Descriptor::Identity> ids;
- EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, kEffectNullUuid, &ids));
- EXPECT_EQ(ids.size(), 0UL);
+ std::vector<Descriptor> descs;
+ EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, kEffectNullUuid, &descs));
+ EXPECT_EQ(descs.size(), 0UL);
}
// create all effects, and then destroy them all together
TEST_P(EffectFactoryTest, CreateAndDestroyEffects) {
- std::vector<Descriptor::Identity> ids;
- EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids));
- EXPECT_NE(ids.size(), 0UL);
+ std::vector<Descriptor> descs;
+ EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &descs));
+ EXPECT_NE(descs.size(), 0UL);
std::vector<std::shared_ptr<IEffect>> effects;
- effects = createWithIds(ids);
- EXPECT_EQ(ids.size(), effects.size());
+ effects = createWithDescs(descs);
+ EXPECT_EQ(descs.size(), effects.size());
destroyEffects(effects);
}
TEST_P(EffectFactoryTest, CreateMultipleInstanceOfSameEffect) {
- std::vector<Descriptor::Identity> ids;
- EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids));
- EXPECT_NE(ids.size(), 0UL);
+ std::vector<Descriptor> descs;
+ EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &descs));
+ EXPECT_NE(descs.size(), 0UL);
- std::vector<std::shared_ptr<IEffect>> effects = createWithIds(ids);
- EXPECT_EQ(ids.size(), effects.size());
- std::vector<std::shared_ptr<IEffect>> effects2 = createWithIds(ids);
- EXPECT_EQ(ids.size(), effects2.size());
- std::vector<std::shared_ptr<IEffect>> effects3 = createWithIds(ids);
- EXPECT_EQ(ids.size(), effects3.size());
+ std::vector<std::shared_ptr<IEffect>> effects = createWithDescs(descs);
+ EXPECT_EQ(descs.size(), effects.size());
+ std::vector<std::shared_ptr<IEffect>> effects2 = createWithDescs(descs);
+ EXPECT_EQ(descs.size(), effects2.size());
+ std::vector<std::shared_ptr<IEffect>> effects3 = createWithDescs(descs);
+ EXPECT_EQ(descs.size(), effects3.size());
destroyEffects(effects);
destroyEffects(effects2);
@@ -200,28 +202,28 @@
// create and destroy each effect one by one
TEST_P(EffectFactoryTest, CreateAndDestroyEffectsOneByOne) {
- std::vector<Descriptor::Identity> ids;
- EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids));
- EXPECT_NE(ids.size(), 0UL);
+ std::vector<Descriptor> descs;
+ EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &descs));
+ EXPECT_NE(descs.size(), 0UL);
- creatAndDestroyIds(ids);
+ creatAndDestroyDescs(descs);
}
// for each effect: repeat 3 times create and destroy
TEST_P(EffectFactoryTest, CreateAndDestroyRepeat) {
- std::vector<Descriptor::Identity> ids;
- EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids));
- EXPECT_NE(ids.size(), 0UL);
+ std::vector<Descriptor> descs;
+ EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &descs));
+ EXPECT_NE(descs.size(), 0UL);
- creatAndDestroyIds(ids);
- creatAndDestroyIds(ids);
- creatAndDestroyIds(ids);
+ creatAndDestroyDescs(descs);
+ creatAndDestroyDescs(descs);
+ creatAndDestroyDescs(descs);
}
// Expect EX_ILLEGAL_ARGUMENT when create with invalid UUID.
TEST_P(EffectFactoryTest, CreateWithInvalidUuid) {
- std::vector<Descriptor::Identity> ids = {kNullDesc, kZeroDesc};
- auto effects = createWithIds(ids, EX_ILLEGAL_ARGUMENT);
+ std::vector<Descriptor> descs = {kNullDesc, kZeroDesc};
+ auto effects = createWithDescs(descs, EX_ILLEGAL_ARGUMENT);
EXPECT_EQ(effects.size(), 0UL);
}
@@ -233,23 +235,23 @@
// Same descriptor ID should work after service restart.
TEST_P(EffectFactoryTest, CreateDestroyWithRestart) {
- std::vector<Descriptor::Identity> ids;
- EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids));
- EXPECT_NE(ids.size(), 0UL);
- creatAndDestroyIds(ids);
+ std::vector<Descriptor> descs;
+ EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &descs));
+ EXPECT_NE(descs.size(), 0UL);
+ creatAndDestroyDescs(descs);
mFactoryHelper->RestartFactoryService();
connectAndGetFactory();
- creatAndDestroyIds(ids);
+ creatAndDestroyDescs(descs);
}
// Effect handle invalid after restart.
TEST_P(EffectFactoryTest, EffectInvalidAfterRestart) {
- std::vector<Descriptor::Identity> ids;
- EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids));
- EXPECT_NE(ids.size(), 0UL);
- std::vector<std::shared_ptr<IEffect>> effects = createWithIds(ids);
+ std::vector<Descriptor> descs;
+ EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &descs));
+ EXPECT_NE(descs.size(), 0UL);
+ std::vector<std::shared_ptr<IEffect>> effects = createWithDescs(descs);
ASSERT_NO_FATAL_FAILURE(mFactoryHelper->RestartFactoryService());
diff --git a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
index 8212149..4f14bf0 100644
--- a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
@@ -752,16 +752,9 @@
::testing::Combine(testing::ValuesIn(
EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor))),
[](const testing::TestParamInfo<AudioEffectTest::ParamType>& info) {
- auto msSinceEpoch = std::chrono::duration_cast<std::chrono::nanoseconds>(
- std::chrono::system_clock::now().time_since_epoch())
- .count();
auto instance = std::get<PARAM_INSTANCE_NAME>(info.param);
- std::ostringstream address;
- address << msSinceEpoch << "_factory_" << instance.first.get();
- std::string name = address.str() + "_UUID_timeLow_" +
- ::android::internal::ToString(instance.second.uuid.timeLow) +
- "_timeMid_" +
- ::android::internal::ToString(instance.second.uuid.timeMid);
+ std::string name = "TYPE_" + instance.second.type.toString() + "_UUID_" +
+ instance.second.uuid.toString();
std::replace_if(
name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
return name;
diff --git a/audio/aidl/vts/VtsHalBassBoostTargetTest.cpp b/audio/aidl/vts/VtsHalBassBoostTargetTest.cpp
new file mode 100644
index 0000000..7adf63c
--- /dev/null
+++ b/audio/aidl/vts/VtsHalBassBoostTargetTest.cpp
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "VtsHalBassBoostTest"
+
+#include <Utils.h>
+#include <aidl/Vintf.h>
+#include <limits.h>
+
+#include "EffectHelper.h"
+
+using namespace android;
+
+using aidl::android::hardware::audio::effect::BassBoost;
+using aidl::android::hardware::audio::effect::Capability;
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::kBassBoostTypeUUID;
+using aidl::android::hardware::audio::effect::Parameter;
+
+/**
+ * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
+ * VtsAudioEffectTargetTest.
+ */
+enum ParamName { PARAM_INSTANCE_NAME, PARAM_STRENGTH };
+using BassBoostParamTestParam =
+ std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor::Identity>, int>;
+
+/*
+ * Testing parameter range, assuming the parameter supported by effect is in this range.
+ * Parameter should be within the valid range defined in the documentation,
+ * for any supported value test expects EX_NONE from IEffect.setParameter(),
+ * otherwise expect EX_ILLEGAL_ARGUMENT.
+ */
+
+const std::vector<int> kStrengthValues = {
+ std::numeric_limits<int>::min(),
+ BassBoost::MIN_PER_MILLE_STRENGTH - 1,
+ BassBoost::MIN_PER_MILLE_STRENGTH,
+ (BassBoost::MIN_PER_MILLE_STRENGTH + BassBoost::MAX_PER_MILLE_STRENGTH) >> 1,
+ BassBoost::MAX_PER_MILLE_STRENGTH,
+ BassBoost::MAX_PER_MILLE_STRENGTH + 2,
+ std::numeric_limits<int>::max()};
+
+class BassBoostParamTest : public ::testing::TestWithParam<BassBoostParamTestParam>,
+ public EffectHelper {
+ public:
+ BassBoostParamTest() : mParamStrength(std::get<PARAM_STRENGTH>(GetParam())) {
+ std::tie(mFactory, mIdentity) = std::get<PARAM_INSTANCE_NAME>(GetParam());
+ }
+
+ void SetUp() override {
+ ASSERT_NE(nullptr, mFactory);
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mIdentity));
+
+ Parameter::Specific specific = getDefaultParamSpecific();
+ Parameter::Common common = EffectHelper::createParamCommon(
+ 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
+ kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
+ IEffect::OpenEffectReturn ret;
+ ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &ret, EX_NONE));
+ ASSERT_NE(nullptr, mEffect);
+ }
+
+ void TearDown() override {
+ ASSERT_NO_FATAL_FAILURE(close(mEffect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+ }
+
+ Parameter::Specific getDefaultParamSpecific() {
+ BassBoost bb = BassBoost::make<BassBoost::strengthPm>(BassBoost::MIN_PER_MILLE_STRENGTH);
+ Parameter::Specific specific =
+ Parameter::Specific::make<Parameter::Specific::bassBoost>(bb);
+ return specific;
+ }
+
+ static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+ std::shared_ptr<IFactory> mFactory;
+ std::shared_ptr<IEffect> mEffect;
+ Descriptor::Identity mIdentity;
+ int mParamStrength = BassBoost::MIN_PER_MILLE_STRENGTH;
+
+ void SetAndGetBassBoostParameters() {
+ for (auto& it : mTags) {
+ auto& tag = it.first;
+ auto& bb = it.second;
+
+ // validate parameter
+ Descriptor desc;
+ ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
+ const bool valid = isTagInRange(it.first, it.second, desc);
+ const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
+
+ // set parameter
+ Parameter expectParam;
+ Parameter::Specific specific;
+ specific.set<Parameter::Specific::bassBoost>(bb);
+ expectParam.set<Parameter::specific>(specific);
+ EXPECT_STATUS(expected, mEffect->setParameter(expectParam)) << expectParam.toString();
+
+ // only get if parameter in range and set success
+ if (expected == EX_NONE) {
+ Parameter getParam;
+ Parameter::Id id;
+ BassBoost::Id bbId;
+ bbId.set<BassBoost::Id::commonTag>(tag);
+ id.set<Parameter::Id::bassBoostTag>(bbId);
+ // if set success, then get should match
+ EXPECT_STATUS(expected, mEffect->getParameter(id, &getParam));
+ EXPECT_EQ(expectParam, getParam);
+ }
+ }
+ }
+
+ void addStrengthParam(int strength) {
+ BassBoost bb;
+ bb.set<BassBoost::strengthPm>(strength);
+ mTags.push_back({BassBoost::strengthPm, bb});
+ }
+
+ bool isTagInRange(const BassBoost::Tag& tag, const BassBoost& bb,
+ const Descriptor& desc) const {
+ const BassBoost::Capability& bbCap = desc.capability.get<Capability::bassBoost>();
+ switch (tag) {
+ case BassBoost::strengthPm: {
+ int strength = bb.get<BassBoost::strengthPm>();
+ return isStrengthInRange(bbCap, strength);
+ }
+ default:
+ return false;
+ }
+ return false;
+ }
+
+ bool isStrengthInRange(const BassBoost::Capability& cap, int strength) const {
+ return cap.strengthSupported && strength >= BassBoost::MIN_PER_MILLE_STRENGTH &&
+ strength <= BassBoost::MAX_PER_MILLE_STRENGTH;
+ }
+
+ private:
+ std::vector<std::pair<BassBoost::Tag, BassBoost>> mTags;
+ void CleanUp() { mTags.clear(); }
+};
+
+TEST_P(BassBoostParamTest, SetAndGetStrength) {
+ EXPECT_NO_FATAL_FAILURE(addStrengthParam(mParamStrength));
+ SetAndGetBassBoostParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ BassBoostTest, BassBoostParamTest,
+ ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+ IFactory::descriptor, kBassBoostTypeUUID)),
+ testing::ValuesIn(kStrengthValues)),
+ [](const testing::TestParamInfo<BassBoostParamTest::ParamType>& info) {
+ auto instance = std::get<PARAM_INSTANCE_NAME>(info.param);
+ std::string strength = std::to_string(std::get<PARAM_STRENGTH>(info.param));
+ std::string name = instance.second.uuid.toString() + "_strength_" + strength;
+ std::replace_if(
+ name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+ return name;
+ });
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BassBoostParamTest);
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ ABinderProcess_setThreadPoolMaxThreadCount(1);
+ ABinderProcess_startThreadPool();
+ return RUN_ALL_TESTS();
+}
diff --git a/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp b/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp
index f19dff6..1b147a6 100644
--- a/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp
@@ -327,18 +327,9 @@
IFactory::descriptor, kEqualizerTypeUUID)),
testing::ValuesIn(kBandLevels)),
[](const testing::TestParamInfo<EqualizerTest::ParamType>& info) {
- auto msSinceEpoch = std::chrono::duration_cast<std::chrono::nanoseconds>(
- std::chrono::system_clock::now().time_since_epoch())
- .count();
auto instance = std::get<PARAM_INSTANCE_NAME>(info.param);
std::string bandLevel = std::to_string(std::get<PARAM_BAND_LEVEL>(info.param));
- std::ostringstream address;
- address << msSinceEpoch << "_factory_" << instance.first.get();
- std::string name = address.str() + "_UUID_timeLow_" +
- ::android::internal::ToString(instance.second.uuid.timeLow) +
- "_timeMid_" +
- ::android::internal::ToString(instance.second.uuid.timeMid) +
- "_bandLevel_" + bandLevel;
+ std::string name = instance.second.uuid.toString() + "_bandLevel_" + bandLevel;
std::replace_if(
name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
return name;
diff --git a/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp b/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp
index 1485657..3fd2812 100644
--- a/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp
@@ -15,6 +15,7 @@
*/
#include <aidl/Vintf.h>
+#include <string>
#define LOG_TAG "VtsHalLoudnessEnhancerTest"
@@ -129,19 +130,9 @@
IFactory::descriptor, kLoudnessEnhancerTypeUUID)),
testing::ValuesIn(kGainMbValues)),
[](const testing::TestParamInfo<LoudnessEnhancerParamTest::ParamType>& info) {
- auto msSinceEpoch = std::chrono::duration_cast<std::chrono::nanoseconds>(
- std::chrono::system_clock::now().time_since_epoch())
- .count();
auto instance = std::get<PARAM_INSTANCE_NAME>(info.param);
std::string gainMb = std::to_string(std::get<PARAM_GAIN_MB>(info.param));
-
- std::ostringstream address;
- address << msSinceEpoch << "_factory_" << instance.first.get();
- std::string name = address.str() + "_UUID_timeLow_" +
- ::android::internal::ToString(instance.second.uuid.timeLow) +
- "_timeMid_" +
- ::android::internal::ToString(instance.second.uuid.timeMid) +
- "_gainMb" + gainMb;
+ std::string name = instance.second.uuid.toString() + "_gainMb_" + gainMb;
std::replace_if(
name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
return name;
diff --git a/automotive/can/aidl/Android.bp b/automotive/can/aidl/Android.bp
new file mode 100644
index 0000000..67333b9
--- /dev/null
+++ b/automotive/can/aidl/Android.bp
@@ -0,0 +1,40 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+aidl_interface {
+ name: "android.hardware.automotive.can",
+ vendor_available: true,
+ srcs: ["android/hardware/automotive/can/*.aidl"],
+ stability: "vintf",
+ host_supported: true,
+ backend: {
+ java: {
+ enabled: false,
+ },
+ rust: {
+ enabled: true,
+ },
+ },
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/BusConfig.aidl
similarity index 76%
copy from audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
copy to automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/BusConfig.aidl
index 8ad4848..0212e00 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
+++ b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/BusConfig.aidl
@@ -31,27 +31,16 @@
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
-package android.hardware.audio.effect;
+package android.hardware.automotive.can;
@VintfStability
-union Reverb {
- android.hardware.audio.effect.VendorExtension vendor;
- int roomLevelMb;
- int roomHfLevelMb;
- int decayTimeMs;
- int decayHfRatioPm;
- int levelMb;
- int delayMs;
- int diffusionPm;
- int densityPm;
- boolean bypass;
- @VintfStability
- union Id {
- int vendorExtensionTag;
- android.hardware.audio.effect.Reverb.Tag commonTag;
- }
- @VintfStability
- parcelable Capability {
- android.hardware.audio.effect.VendorExtension extension;
- int maxDecayTimeMs;
+parcelable BusConfig {
+ String name;
+ android.hardware.automotive.can.BusConfig.InterfaceId interfaceId;
+ int bitrate;
+ union InterfaceId {
+ android.hardware.automotive.can.VirtualInterface virtualif;
+ android.hardware.automotive.can.NativeInterface nativeif;
+ android.hardware.automotive.can.SlcanInterface slcan;
+ android.hardware.automotive.can.IndexedInterface indexed;
}
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/ICanController.aidl
similarity index 75%
copy from audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
copy to automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/ICanController.aidl
index 8ad4848..5d032f2 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
+++ b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/ICanController.aidl
@@ -31,27 +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.audio.effect;
+package android.hardware.automotive.can;
@VintfStability
-union Reverb {
- android.hardware.audio.effect.VendorExtension vendor;
- int roomLevelMb;
- int roomHfLevelMb;
- int decayTimeMs;
- int decayHfRatioPm;
- int levelMb;
- int delayMs;
- int diffusionPm;
- int densityPm;
- boolean bypass;
- @VintfStability
- union Id {
- int vendorExtensionTag;
- android.hardware.audio.effect.Reverb.Tag commonTag;
- }
- @VintfStability
- parcelable Capability {
- android.hardware.audio.effect.VendorExtension extension;
- int maxDecayTimeMs;
- }
+interface ICanController {
+ android.hardware.automotive.can.InterfaceType[] getSupportedInterfaceTypes();
+ String getInterfaceName(in String busName);
+ String upBus(in android.hardware.automotive.can.BusConfig config);
+ void downBus(in String name);
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/IndexedInterface.aidl
similarity index 75%
copy from audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
copy to automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/IndexedInterface.aidl
index 8ad4848..1b00adf 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
+++ b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/IndexedInterface.aidl
@@ -31,27 +31,8 @@
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
-package android.hardware.audio.effect;
+package android.hardware.automotive.can;
@VintfStability
-union Reverb {
- android.hardware.audio.effect.VendorExtension vendor;
- int roomLevelMb;
- int roomHfLevelMb;
- int decayTimeMs;
- int decayHfRatioPm;
- int levelMb;
- int delayMs;
- int diffusionPm;
- int densityPm;
- boolean bypass;
- @VintfStability
- union Id {
- int vendorExtensionTag;
- android.hardware.audio.effect.Reverb.Tag commonTag;
- }
- @VintfStability
- parcelable Capability {
- android.hardware.audio.effect.VendorExtension extension;
- int maxDecayTimeMs;
- }
+parcelable IndexedInterface {
+ byte index;
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/InterfaceType.aidl
similarity index 75%
copy from audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
copy to automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/InterfaceType.aidl
index 8ad4848..44865aa 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
+++ b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/InterfaceType.aidl
@@ -31,27 +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.audio.effect;
-@VintfStability
-union Reverb {
- android.hardware.audio.effect.VendorExtension vendor;
- int roomLevelMb;
- int roomHfLevelMb;
- int decayTimeMs;
- int decayHfRatioPm;
- int levelMb;
- int delayMs;
- int diffusionPm;
- int densityPm;
- boolean bypass;
- @VintfStability
- union Id {
- int vendorExtensionTag;
- android.hardware.audio.effect.Reverb.Tag commonTag;
- }
- @VintfStability
- parcelable Capability {
- android.hardware.audio.effect.VendorExtension extension;
- int maxDecayTimeMs;
- }
+package android.hardware.automotive.can;
+@Backing(type="byte") @VintfStability
+enum InterfaceType {
+ VIRTUAL = 0,
+ NATIVE = 1,
+ SLCAN = 2,
+ INDEXED = 3,
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/NativeInterface.aidl
similarity index 76%
copy from audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
copy to automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/NativeInterface.aidl
index 8ad4848..5d6c119 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
+++ b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/NativeInterface.aidl
@@ -31,27 +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.audio.effect;
+package android.hardware.automotive.can;
@VintfStability
-union Reverb {
- android.hardware.audio.effect.VendorExtension vendor;
- int roomLevelMb;
- int roomHfLevelMb;
- int decayTimeMs;
- int decayHfRatioPm;
- int levelMb;
- int delayMs;
- int diffusionPm;
- int densityPm;
- boolean bypass;
- @VintfStability
- union Id {
- int vendorExtensionTag;
- android.hardware.audio.effect.Reverb.Tag commonTag;
- }
- @VintfStability
- parcelable Capability {
- android.hardware.audio.effect.VendorExtension extension;
- int maxDecayTimeMs;
+parcelable NativeInterface {
+ android.hardware.automotive.can.NativeInterface.InterfaceId interfaceId;
+ union InterfaceId {
+ String ifname;
+ String[] serialno;
}
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/Result.aidl
similarity index 75%
copy from audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
copy to automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/Result.aidl
index 8ad4848..010792a 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
+++ b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/Result.aidl
@@ -31,27 +31,15 @@
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
-package android.hardware.audio.effect;
-@VintfStability
-union Reverb {
- android.hardware.audio.effect.VendorExtension vendor;
- int roomLevelMb;
- int roomHfLevelMb;
- int decayTimeMs;
- int decayHfRatioPm;
- int levelMb;
- int delayMs;
- int diffusionPm;
- int densityPm;
- boolean bypass;
- @VintfStability
- union Id {
- int vendorExtensionTag;
- android.hardware.audio.effect.Reverb.Tag commonTag;
- }
- @VintfStability
- parcelable Capability {
- android.hardware.audio.effect.VendorExtension extension;
- int maxDecayTimeMs;
- }
+package android.hardware.automotive.can;
+@Backing(type="int") @VintfStability
+enum Result {
+ OK = 0,
+ UNKNOWN_ERROR = 1,
+ INVALID_STATE = 2,
+ NOT_SUPPORTED = 3,
+ BAD_INTERFACE_ID = 4,
+ BAD_BITRATE = 5,
+ BAD_BUS_NAME = 6,
+ INTERFACE_DOWN = 7,
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/SlcanInterface.aidl
similarity index 76%
copy from audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
copy to automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/SlcanInterface.aidl
index 8ad4848..af0c07d 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
+++ b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/SlcanInterface.aidl
@@ -31,27 +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.audio.effect;
+package android.hardware.automotive.can;
@VintfStability
-union Reverb {
- android.hardware.audio.effect.VendorExtension vendor;
- int roomLevelMb;
- int roomHfLevelMb;
- int decayTimeMs;
- int decayHfRatioPm;
- int levelMb;
- int delayMs;
- int diffusionPm;
- int densityPm;
- boolean bypass;
- @VintfStability
- union Id {
- int vendorExtensionTag;
- android.hardware.audio.effect.Reverb.Tag commonTag;
- }
- @VintfStability
- parcelable Capability {
- android.hardware.audio.effect.VendorExtension extension;
- int maxDecayTimeMs;
+parcelable SlcanInterface {
+ android.hardware.automotive.can.SlcanInterface.InterfaceId interfaceId;
+ union InterfaceId {
+ String ttyname;
+ String[] serialno;
}
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/VirtualInterface.aidl
similarity index 75%
copy from audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
copy to automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/VirtualInterface.aidl
index 8ad4848..c870612 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
+++ b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/VirtualInterface.aidl
@@ -31,27 +31,8 @@
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
-package android.hardware.audio.effect;
+package android.hardware.automotive.can;
@VintfStability
-union Reverb {
- android.hardware.audio.effect.VendorExtension vendor;
- int roomLevelMb;
- int roomHfLevelMb;
- int decayTimeMs;
- int decayHfRatioPm;
- int levelMb;
- int delayMs;
- int diffusionPm;
- int densityPm;
- boolean bypass;
- @VintfStability
- union Id {
- int vendorExtensionTag;
- android.hardware.audio.effect.Reverb.Tag commonTag;
- }
- @VintfStability
- parcelable Capability {
- android.hardware.audio.effect.VendorExtension extension;
- int maxDecayTimeMs;
- }
+parcelable VirtualInterface {
+ String ifname;
}
diff --git a/automotive/can/aidl/android/hardware/automotive/can/BusConfig.aidl b/automotive/can/aidl/android/hardware/automotive/can/BusConfig.aidl
new file mode 100644
index 0000000..4e1027b
--- /dev/null
+++ b/automotive/can/aidl/android/hardware/automotive/can/BusConfig.aidl
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.automotive.can;
+
+import android.hardware.automotive.can.IndexedInterface;
+import android.hardware.automotive.can.NativeInterface;
+import android.hardware.automotive.can.SlcanInterface;
+import android.hardware.automotive.can.VirtualInterface;
+
+/**
+ * Configuration of the (physical or virtual) CAN bus.
+ *
+ * ISO TP and CAN FD support is dependent upon the hardware.
+ */
+@VintfStability
+parcelable BusConfig {
+ /**
+ * Name by which a given bus may be referenced.
+ *
+ * It must consist of only alphanumeric characters and underscore
+ * (a-z, A-Z, 0-9, '_'), at least 1 and at most 32 characters long.
+ *
+ * This field is *not* meant to distinguish between hardware interfaces
+ * nor preselect parameters like bitrate.
+ *
+ * This field represents a more human-friendly name for a CAN bus:
+ * e.x. rather than /some/dev/can1234, "name" might be "BodyCAN" or "CCAN"
+ */
+ String name;
+
+ /**
+ * Hardware interface configuration.
+ *
+ * This union's discriminator has an equivalent enum {@see InterfaceType} to
+ * express compatibility via getSupportedInterfaceTypes().
+ */
+ union InterfaceId {
+ /** Virtual SocketCAN interface. */
+ VirtualInterface virtualif;
+
+ /** Native SocketCAN interface. */
+ NativeInterface nativeif;
+
+ /** Serial line CAN interface. */
+ SlcanInterface slcan;
+
+ /**
+ * Proprietary, device-specific interface.
+ *
+ * Non-SocketCAN interfaces should use this variant.
+ */
+ IndexedInterface indexed;
+ }
+
+ InterfaceId interfaceId;
+
+ /**
+ * Bit rate for CAN communication.
+ *
+ * Typical bit rates are: 100000, 125000, 250000, 500000.
+ *
+ * For {@see interfaceId#virtual} interfaces, this value is ignored.
+ */
+ int bitrate;
+}
diff --git a/automotive/can/aidl/android/hardware/automotive/can/ICanController.aidl b/automotive/can/aidl/android/hardware/automotive/can/ICanController.aidl
new file mode 100644
index 0000000..97c2674
--- /dev/null
+++ b/automotive/can/aidl/android/hardware/automotive/can/ICanController.aidl
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.automotive.can;
+
+import android.hardware.automotive.can.BusConfig;
+import android.hardware.automotive.can.InterfaceType;
+import android.hardware.automotive.can.Result;
+
+/**
+ * Represents a CAN controller that's capable of configuring CAN bus interfaces.
+ *
+ * The goal of this service is to configure and manage CAN interfaces.
+ *
+ * Providing an ICanController interface to configure CAN buses is optional.
+ * A system can elect to configure CAN buses manually if the hardware is
+ * dedicated to a specific application.
+ */
+@VintfStability
+interface ICanController {
+ /**
+ * Fetches the list of interface types supported by this HAL server.
+ *
+ * @return iftypes The list of supported interface types.
+ */
+ InterfaceType[] getSupportedInterfaceTypes();
+
+ /**
+ * Gets the interface name given the name of the bus. This will
+ *
+ * @param busName Name of the CAN bus who's interface name we would like
+ * (e.x. BCAN, CCAN, HS3, BodyCAN, ...)
+ * @return name of the socketcan network interface corresponding to busName
+ * (e.x. can0, vcan5, ...)
+ */
+ String getInterfaceName(in String busName);
+
+ /**
+ * Bring up a CAN bus.
+ *
+ * @param config Configuration for the CAN bus.
+ * @return name of iface if successful
+ */
+ String upBus(in BusConfig config);
+
+ /**
+ * Bring down a CAN bus.
+ *
+ * @param name Name of the bus (@see BusConfig#name} to bring down.
+ */
+ void downBus(in String name);
+}
diff --git a/automotive/can/aidl/android/hardware/automotive/can/IndexedInterface.aidl b/automotive/can/aidl/android/hardware/automotive/can/IndexedInterface.aidl
new file mode 100644
index 0000000..13e223f
--- /dev/null
+++ b/automotive/can/aidl/android/hardware/automotive/can/IndexedInterface.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.can;
+
+@VintfStability
+parcelable IndexedInterface {
+ /** Interface number, 0-based. */
+ byte index;
+}
diff --git a/automotive/can/aidl/android/hardware/automotive/can/InterfaceType.aidl b/automotive/can/aidl/android/hardware/automotive/can/InterfaceType.aidl
new file mode 100644
index 0000000..b13648a
--- /dev/null
+++ b/automotive/can/aidl/android/hardware/automotive/can/InterfaceType.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.automotive.can;
+
+/**
+ * Type of an interface, an equivalent to BusConfig::InterfaceId
+ * union discriminator. Defines a number of specific standard hardware
+ * families and a generic catch-all type of {@see INDEXED}.
+ */
+@VintfStability
+@Backing(type="byte")
+enum InterfaceType {
+ /** Virtual SocketCAN interface. */
+ VIRTUAL,
+
+ /** Native SocketCAN interface. */
+ NATIVE,
+
+ /** Serial line CAN interface. */
+ SLCAN,
+
+ /** Proprietary, device-specific interface. */
+ INDEXED,
+}
diff --git a/automotive/can/aidl/android/hardware/automotive/can/NativeInterface.aidl b/automotive/can/aidl/android/hardware/automotive/can/NativeInterface.aidl
new file mode 100644
index 0000000..30c24c3
--- /dev/null
+++ b/automotive/can/aidl/android/hardware/automotive/can/NativeInterface.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.automotive.can;
+
+@VintfStability
+parcelable NativeInterface {
+ union InterfaceId {
+ /** Interface name, such as can0. */
+ String ifname;
+
+ /**
+ * Alternatively to providing {@see ifname}, one may provide a list of
+ * interface serial number suffixes. If there happens to be a device
+ * (like USB2CAN) with a matching serial number suffix, the HAL service
+ * will locate it.
+ *
+ * Client may utilize this in two ways: by matching against the
+ * entire serial number, or the last few characters (usually
+ * one). The former is better for small-scale test deployments
+ * (with just a handful of vehicles), the latter is good for
+ * larger scale (where a small suffix list may support large
+ * test fleet).
+ */
+ String[] serialno;
+ }
+
+ InterfaceId interfaceId;
+}
diff --git a/automotive/can/aidl/android/hardware/automotive/can/Result.aidl b/automotive/can/aidl/android/hardware/automotive/can/Result.aidl
new file mode 100644
index 0000000..cdd0066
--- /dev/null
+++ b/automotive/can/aidl/android/hardware/automotive/can/Result.aidl
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.automotive.can;
+
+/**
+ * Possible error codes (or OK) for ICanController.
+ */
+@VintfStability
+@Backing(type="int")
+enum Result {
+ OK,
+
+ /**
+ * General error class, if others are not applicable.
+ */
+ UNKNOWN_ERROR,
+
+ /**
+ * Up request was called out of order (i.e. trying to up the interface
+ * twice).
+ */
+ INVALID_STATE,
+
+ /** Interface type is not supported. */
+ NOT_SUPPORTED,
+
+ /**
+ * Provided interface ID (index, name, device path) doesn't exist or there
+ * is no device with a given serial number.
+ */
+ BAD_INTERFACE_ID,
+
+ /** Provided bit rate is not supported by the hardware. */
+ BAD_BITRATE,
+
+ /**
+ * Provided bus name ({@see BusConfig#name}) has invalid format or doesn't exist.
+ */
+ BAD_BUS_NAME,
+
+ /**
+ * The interface for the bus you are trying to interact with is currently
+ * down. As opposed to INVALID_STATE, this serves to warn the caller
+ * _before_ they attempt an invalid operation.
+ */
+ INTERFACE_DOWN,
+}
diff --git a/automotive/can/aidl/android/hardware/automotive/can/SlcanInterface.aidl b/automotive/can/aidl/android/hardware/automotive/can/SlcanInterface.aidl
new file mode 100644
index 0000000..4ed8583
--- /dev/null
+++ b/automotive/can/aidl/android/hardware/automotive/can/SlcanInterface.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.automotive.can;
+
+@VintfStability
+parcelable SlcanInterface {
+ union InterfaceId {
+ /** Path to a device, such as /dev/ttyUSB0. */
+ String ttyname;
+
+ /**
+ * List of interface serial number suffixes.
+ * {@see Socketcan::serialno}
+ */
+ String[] serialno;
+ }
+
+ InterfaceId interfaceId;
+}
diff --git a/automotive/can/aidl/android/hardware/automotive/can/VirtualInterface.aidl b/automotive/can/aidl/android/hardware/automotive/can/VirtualInterface.aidl
new file mode 100644
index 0000000..7e1e5e1
--- /dev/null
+++ b/automotive/can/aidl/android/hardware/automotive/can/VirtualInterface.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.automotive.can;
+
+@VintfStability
+parcelable VirtualInterface {
+ /**
+ * Interface name, such as vcan0. If the interface doesn't
+ * exist, HAL server must create it.
+ */
+ String ifname;
+}
diff --git a/automotive/can/aidl/default/Android.bp b/automotive/can/aidl/default/Android.bp
new file mode 100644
index 0000000..d44cb91
--- /dev/null
+++ b/automotive/can/aidl/default/Android.bp
@@ -0,0 +1,51 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_binary {
+ name: "android.hardware.automotive.can-service",
+ init_rc: ["android.hardware.automotive.can.rc"],
+ defaults: ["android.hardware.automotive.can@defaults"],
+ vendor: true,
+ relative_install_path: "hw",
+ srcs: [
+ "CanBus.cpp",
+ "CanBusSlcan.cpp",
+ "CanBusNative.cpp",
+ "CanBusVirtual.cpp",
+ "CanController.cpp",
+ "service.cpp",
+ ],
+ shared_libs: [
+ "android.hardware.automotive.can-V1-ndk",
+ "libbase",
+ "libbinder_ndk",
+ ],
+ static_libs: [
+ "android.hardware.automotive.can@libnetdevice",
+ "android.hardware.automotive@libc++fs",
+ "libnl++",
+ ],
+ vintf_fragments: ["android.hardware.automotive.can.xml"],
+}
diff --git a/automotive/can/aidl/default/CanBus.cpp b/automotive/can/aidl/default/CanBus.cpp
new file mode 100644
index 0000000..d1f9b78
--- /dev/null
+++ b/automotive/can/aidl/default/CanBus.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CanBus.h"
+
+#include <android-base/logging.h>
+#include <libnetdevice/libnetdevice.h>
+
+namespace aidl::android::hardware::automotive::can {
+
+CanBus::CanBus(std::string_view ifname) : mIfname(ifname) {}
+
+CanBus::~CanBus() {
+ std::lock_guard<std::mutex> lck(mIsUpGuard);
+ CHECK(!mIsUp) << "Interface is still up while being destroyed";
+}
+
+Result CanBus::preUp() {
+ return Result::OK;
+}
+
+bool CanBus::postDown() {
+ return true;
+}
+
+std::string CanBus::getIfaceName() {
+ return mIfname;
+}
+
+Result CanBus::up() {
+ std::lock_guard<std::mutex> lck(mIsUpGuard);
+
+ if (mIsUp) {
+ LOG(WARNING) << "Interface is already up";
+ return Result::INVALID_STATE;
+ }
+
+ const auto preResult = preUp();
+ if (preResult != Result::OK) return preResult;
+
+ const auto isUp = ::android::netdevice::isUp(mIfname);
+ if (!isUp.has_value()) {
+ // preUp() should prepare the interface (either create or make sure it's there)
+ LOG(ERROR) << "Interface " << mIfname << " didn't get prepared";
+ return Result::BAD_INTERFACE_ID;
+ }
+
+ if (!*isUp && !::android::netdevice::up(mIfname)) {
+ LOG(ERROR) << "Can't bring " << mIfname << " up";
+ return Result::UNKNOWN_ERROR;
+ }
+ mDownAfterUse = !*isUp;
+
+ mIsUp = true;
+ return Result::OK;
+}
+
+Result CanBus::down() {
+ std::lock_guard<std::mutex> lck(mIsUpGuard);
+
+ if (!mIsUp) {
+ LOG(WARNING) << "Interface is already down";
+ return Result::INVALID_STATE;
+ }
+ mIsUp = false;
+
+ Result success = Result::OK;
+
+ if (mDownAfterUse && !::android::netdevice::down(mIfname)) {
+ LOG(ERROR) << "Can't bring " << mIfname << " down";
+ // don't return yet, let's try to do best-effort cleanup
+ success = Result::UNKNOWN_ERROR;
+ }
+
+ if (!postDown()) success = Result::UNKNOWN_ERROR;
+
+ return success;
+}
+
+} // namespace aidl::android::hardware::automotive::can
diff --git a/automotive/can/aidl/default/CanBus.h b/automotive/can/aidl/default/CanBus.h
new file mode 100644
index 0000000..abdbe51
--- /dev/null
+++ b/automotive/can/aidl/default/CanBus.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <aidl/android/hardware/automotive/can/Result.h>
+
+#include <android-base/macros.h>
+#include <utils/Mutex.h>
+
+#include <atomic>
+#include <mutex>
+
+namespace aidl::android::hardware::automotive::can {
+
+class CanBus {
+ public:
+ /**
+ * Some interface types (such as SLCAN) don't get an interface name until after being
+ * initialized, hence ifname is optional.
+ *
+ * You MUST ensure mIfname is initialized prior to the completion of preUp().
+ */
+ CanBus(std::string_view ifname = std::string_view{""});
+
+ virtual ~CanBus();
+
+ Result up();
+ Result down();
+ std::string getIfaceName();
+
+ protected:
+ /**
+ * Prepare the SocketCAN interface.
+ *
+ * After calling this method, mIfname network interface is available and ready to be brought up.
+ *
+ * \return true upon success and false upon failure
+ */
+ virtual Result preUp();
+
+ /**
+ * Cleanup after bringing the interface down.
+ *
+ * This is a counterpart to preUp().
+ *
+ * \return true upon success and false upon failure
+ */
+ virtual bool postDown();
+
+ /** Network interface name. */
+ std::string mIfname;
+
+ private:
+ /**
+ * Guard for up flag is required to be held for entire time when the interface is being used
+ * because we don't want the interface to be torn down while executing that operation.
+ */
+ std::mutex mIsUpGuard;
+ bool mIsUp GUARDED_BY(mIsUpGuard) = false;
+
+ bool mDownAfterUse;
+};
+
+} // namespace aidl::android::hardware::automotive::can
diff --git a/automotive/can/aidl/default/CanBusNative.cpp b/automotive/can/aidl/default/CanBusNative.cpp
new file mode 100644
index 0000000..8a7de99
--- /dev/null
+++ b/automotive/can/aidl/default/CanBusNative.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CanBusNative.h"
+
+#include <android-base/logging.h>
+#include <libnetdevice/can.h>
+#include <libnetdevice/libnetdevice.h>
+
+namespace aidl::android::hardware::automotive::can {
+
+using namespace ::android;
+
+CanBusNative::CanBusNative(const std::string& ifname, uint32_t bitrate)
+ : CanBus(ifname), mBitrate(bitrate) {}
+
+Result CanBusNative::preUp() {
+ if (!netdevice::exists(mIfname)) {
+ LOG(ERROR) << "Interface " << mIfname << " doesn't exist";
+ return Result::BAD_INTERFACE_ID;
+ }
+
+ if (mBitrate == 0) {
+ // interface is already up and we just want to register it
+ return Result::OK;
+ }
+
+ if (!netdevice::down(mIfname)) {
+ LOG(ERROR) << "Can't bring " << mIfname << " down (to configure it)";
+ return Result::UNKNOWN_ERROR;
+ }
+
+ if (!netdevice::can::setBitrate(mIfname, mBitrate)) {
+ LOG(ERROR) << "Can't set bitrate " << mBitrate << " for " << mIfname;
+ return Result::BAD_BITRATE;
+ }
+
+ return Result::OK;
+}
+
+} // namespace aidl::android::hardware::automotive::can
diff --git a/automotive/can/aidl/default/CanBusNative.h b/automotive/can/aidl/default/CanBusNative.h
new file mode 100644
index 0000000..32846c7
--- /dev/null
+++ b/automotive/can/aidl/default/CanBusNative.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include "CanBus.h"
+
+namespace aidl::android::hardware::automotive::can {
+
+class CanBusNative : public CanBus {
+ public:
+ CanBusNative(const std::string& ifname, uint32_t bitrate);
+
+ protected:
+ virtual Result preUp() override;
+
+ private:
+ const uint32_t mBitrate;
+};
+
+} // namespace aidl::android::hardware::automotive::can
diff --git a/automotive/can/aidl/default/CanBusSlcan.cpp b/automotive/can/aidl/default/CanBusSlcan.cpp
new file mode 100644
index 0000000..6060419
--- /dev/null
+++ b/automotive/can/aidl/default/CanBusSlcan.cpp
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CanBusSlcan.h"
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <libnetdevice/libnetdevice.h>
+
+#include <linux/serial.h>
+#include <linux/tty.h>
+#include <net/if.h>
+#include <termios.h>
+
+#include <map>
+
+namespace aidl::android::hardware::automotive::can {
+
+using namespace std::string_view_literals;
+using namespace ::android::base;
+
+namespace slcanprotocol {
+static constexpr std::string_view kOpenCommand = "O\r"sv;
+static constexpr std::string_view kCloseCommand = "C\r"sv;
+static constexpr int kSlcanDiscipline = N_SLCAN;
+static constexpr int kDefaultDiscipline = N_TTY;
+
+static const std::map<uint32_t, std::string_view> kBitrateCommands = {
+ {10000, "C\rS0\r"sv}, {20000, "C\rS1\r"sv}, {50000, "C\rS2\r"sv},
+ {100000, "C\rS3\r"sv}, {125000, "C\rS4\r"sv}, {250000, "C\rS5\r"sv},
+ {500000, "C\rS6\r"sv}, {800000, "C\rS7\r"sv}, {1000000, "C\rS8\r"sv}};
+} // namespace slcanprotocol
+
+/**
+ * Serial Line CAN constructor
+ * \param string uartName - name of slcan device (e.x. /dev/ttyUSB0)
+ * \param uint32_t bitrate - speed of the CAN bus (125k = MSCAN, 500k = HSCAN)
+ */
+CanBusSlcan::CanBusSlcan(const std::string& uartName, uint32_t bitrate)
+ : CanBus(), mTtyPath(uartName), kBitrate(bitrate) {}
+
+/** helper function to update CanBusSlcan object's iface name */
+Result CanBusSlcan::updateIfaceName(unique_fd& uartFd) {
+ struct ifreq ifrequest = {};
+ /*
+ * Fetching the iface name with an ioctl won't interfere with an open socketCAN iface attached
+ * to this tty. This is important in the event we are trying to register a SLCAN based iface
+ * that has already been configured and brought up.
+ */
+ if (ioctl(uartFd.get(), SIOCGIFNAME, ifrequest.ifr_name) < 0) {
+ PLOG(ERROR) << "Failed to get the name of the created device";
+ return Result::UNKNOWN_ERROR;
+ }
+
+ // Update the CanBus object with name that was assigned to it
+ mIfname = ifrequest.ifr_name;
+ return Result::OK;
+}
+
+Result CanBusSlcan::preUp() {
+ // verify valid bitrate and translate to serial command format
+ std::optional<std::string_view> canBitrateCommand = std::nullopt;
+ if (kBitrate != 0) {
+ const auto lookupIt = slcanprotocol::kBitrateCommands.find(kBitrate);
+ if (lookupIt == slcanprotocol::kBitrateCommands.end()) {
+ return Result::BAD_BITRATE;
+ }
+ canBitrateCommand = lookupIt->second;
+ }
+
+ /* Attempt to open the uart in r/w without blocking or becoming the
+ * controlling terminal */
+ mFd = unique_fd(open(mTtyPath.c_str(), O_RDWR | O_NONBLOCK | O_NOCTTY | O_CLOEXEC));
+ if (!mFd.ok()) {
+ PLOG(ERROR) << "SLCAN Failed to open " << mTtyPath;
+ return Result::BAD_INTERFACE_ID;
+ }
+
+ // If the device is already up, update the iface name in our CanBusSlcan object
+ if (kBitrate == 0) {
+ return updateIfaceName(mFd);
+ }
+
+ // blank terminal settings and pull them from the device
+ struct termios terminalSettings = {};
+ if (tcgetattr(mFd.get(), &terminalSettings) < 0) {
+ PLOG(ERROR) << "Failed to read attrs of" << mTtyPath;
+ return Result::UNKNOWN_ERROR;
+ }
+
+ // change settings to raw mode
+ cfmakeraw(&terminalSettings);
+
+ // disable software flow control
+ terminalSettings.c_iflag &= ~IXOFF;
+ // enable hardware flow control
+ terminalSettings.c_cflag |= CRTSCTS;
+
+ struct serial_struct serialSettings;
+ // get serial settings
+ if (ioctl(mFd.get(), TIOCGSERIAL, &serialSettings) < 0) {
+ PLOG(ERROR) << "Failed to read serial settings from " << mTtyPath;
+ return Result::UNKNOWN_ERROR;
+ }
+ // set low latency mode
+ serialSettings.flags |= ASYNC_LOW_LATENCY;
+ // apply serial settings
+ if (ioctl(mFd.get(), TIOCSSERIAL, &serialSettings) < 0) {
+ PLOG(ERROR) << "Failed to set low latency mode on " << mTtyPath;
+ return Result::UNKNOWN_ERROR;
+ }
+
+ /* TCSADRAIN applies settings after we finish writing the rest of our
+ * changes (as opposed to TCSANOW, which changes immediately) */
+ if (tcsetattr(mFd.get(), TCSADRAIN, &terminalSettings) < 0) {
+ PLOG(ERROR) << "Failed to apply terminal settings to " << mTtyPath;
+ return Result::UNKNOWN_ERROR;
+ }
+
+ // apply speed setting for CAN
+ if (!WriteStringToFd(*canBitrateCommand, mFd)) {
+ PLOG(ERROR) << "Failed to apply CAN bitrate";
+ return Result::UNKNOWN_ERROR;
+ }
+
+ // TODO(b/144775286): set open flag & support listen only
+ if (!WriteStringToFd(slcanprotocol::kOpenCommand, mFd)) {
+ PLOG(ERROR) << "Failed to set open flag";
+ return Result::UNKNOWN_ERROR;
+ }
+
+ // set line discipline to slcan
+ if (ioctl(mFd.get(), TIOCSETD, &slcanprotocol::kSlcanDiscipline) < 0) {
+ PLOG(ERROR) << "Failed to set line discipline to slcan";
+ return Result::UNKNOWN_ERROR;
+ }
+
+ // Update the CanBus object with name that was assigned to it
+ return updateIfaceName(mFd);
+}
+
+bool CanBusSlcan::postDown() {
+ // reset the line discipline to TTY mode
+ if (ioctl(mFd.get(), TIOCSETD, &slcanprotocol::kDefaultDiscipline) < 0) {
+ LOG(ERROR) << "Failed to reset line discipline!";
+ return false;
+ }
+
+ // issue the close command
+ if (!WriteStringToFd(slcanprotocol::kCloseCommand, mFd)) {
+ LOG(ERROR) << "Failed to close tty!";
+ return false;
+ }
+
+ // close our unique_fd
+ mFd.reset();
+
+ return true;
+}
+
+} // namespace aidl::android::hardware::automotive::can
diff --git a/automotive/can/aidl/default/CanBusSlcan.h b/automotive/can/aidl/default/CanBusSlcan.h
new file mode 100644
index 0000000..a1c908c
--- /dev/null
+++ b/automotive/can/aidl/default/CanBusSlcan.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include "CanBus.h"
+
+#include <android-base/unique_fd.h>
+
+namespace aidl::android::hardware::automotive::can {
+
+class CanBusSlcan : public CanBus {
+ public:
+ CanBusSlcan(const std::string& uartName, uint32_t bitrate);
+
+ protected:
+ virtual Result preUp() override;
+ virtual bool postDown() override;
+
+ private:
+ Result updateIfaceName(::android::base::unique_fd& uartFd);
+
+ const std::string mTtyPath;
+ const uint32_t kBitrate;
+ ::android::base::unique_fd mFd;
+};
+
+} // namespace aidl::android::hardware::automotive::can
diff --git a/automotive/can/aidl/default/CanBusVirtual.cpp b/automotive/can/aidl/default/CanBusVirtual.cpp
new file mode 100644
index 0000000..28a1258
--- /dev/null
+++ b/automotive/can/aidl/default/CanBusVirtual.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CanBusVirtual.h"
+
+#include <android-base/logging.h>
+#include <libnetdevice/libnetdevice.h>
+
+namespace aidl::android::hardware::automotive::can {
+
+using namespace ::android;
+
+CanBusVirtual::CanBusVirtual(const std::string& ifname) : CanBus(ifname) {}
+
+Result CanBusVirtual::preUp() {
+ if (netdevice::exists(mIfname)) return Result::OK;
+
+ LOG(DEBUG) << "Virtual interface " << mIfname << " doesn't exist, creating...";
+ mWasCreated = true;
+ if (!netdevice::add(mIfname, "vcan")) {
+ LOG(ERROR) << "Can't create vcan interface " << mIfname;
+ return Result::UNKNOWN_ERROR;
+ }
+
+ return Result::OK;
+}
+
+bool CanBusVirtual::postDown() {
+ if (mWasCreated) {
+ mWasCreated = false;
+ if (!netdevice::del(mIfname)) {
+ LOG(ERROR) << "Couldn't remove vcan interface " << mIfname;
+ return false;
+ }
+ }
+ return true;
+}
+
+} // namespace aidl::android::hardware::automotive::can
diff --git a/automotive/can/aidl/default/CanBusVirtual.h b/automotive/can/aidl/default/CanBusVirtual.h
new file mode 100644
index 0000000..9c5d35d
--- /dev/null
+++ b/automotive/can/aidl/default/CanBusVirtual.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include "CanBus.h"
+
+namespace aidl::android::hardware::automotive::can {
+
+class CanBusVirtual : public CanBus {
+ public:
+ CanBusVirtual(const std::string& ifname);
+
+ protected:
+ virtual Result preUp() override;
+ virtual bool postDown() override;
+
+ private:
+ bool mWasCreated = false;
+};
+
+} // namespace aidl::android::hardware::automotive::can
diff --git a/automotive/can/aidl/default/CanController.cpp b/automotive/can/aidl/default/CanController.cpp
new file mode 100644
index 0000000..e4b5306
--- /dev/null
+++ b/automotive/can/aidl/default/CanController.cpp
@@ -0,0 +1,333 @@
+/*
+ * Copyright 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CanController.h"
+
+#include "CanBusNative.h"
+#include "CanBusSlcan.h"
+#include "CanBusVirtual.h"
+
+#include <android-base/format.h>
+#include <android-base/logging.h>
+
+#include <automotive/filesystem>
+#include <fstream>
+#include <regex>
+
+namespace aidl::android::hardware::automotive::can {
+
+namespace fs = ::android::hardware::automotive::filesystem;
+
+namespace fsErrors {
+static const std::error_code ok;
+static const std::error_code eperm(EPERM, std::generic_category());
+static const std::error_code enoent(ENOENT, std::generic_category());
+static const std::error_code eacces(EACCES, std::generic_category());
+} // namespace fsErrors
+
+/* In the /sys/devices tree, there are files called "serial", which contain the serial numbers
+ * for various devices. The exact location inside of this directory is dependent upon the
+ * hardware we are running on, so we have to start from /sys/devices and work our way down. */
+static const fs::path kDevPath("/sys/devices/");
+static const std::regex kTtyRe("^tty[A-Z]+[0-9]+$");
+static constexpr auto kOpts = ~(fs::directory_options::follow_directory_symlink |
+ fs::directory_options::skip_permission_denied);
+
+constexpr auto ok = &ndk::ScopedAStatus::ok;
+
+/**
+ * A helper object to associate the interface name and type of a USB to CAN adapter.
+ */
+struct UsbCanIface {
+ InterfaceType iftype;
+ std::string ifaceName;
+};
+
+static bool isValidName(const std::string& name) {
+ static const std::regex nameRE("^[a-zA-Z0-9_]{1,32}$");
+ return std::regex_match(name, nameRE);
+}
+
+/**
+ * Given a path, get the last element from it.
+ *
+ * \param itrPath - the path we want the last element of
+ * \return - the last element in the path (in string form).
+ */
+static std::string getLeaf(const fs::path& itrPath) {
+ /* end() returns an iterator one past the leaf of the path, so we've overshot
+ decrement (--) to go back one to the leaf
+ dereference and now we have our leaf. */
+ return *(--(itrPath.end()));
+}
+
+static ndk::ScopedAStatus resultToStatus(Result res, const std::string& msg = "") {
+ if (msg.empty()) {
+ return ndk::ScopedAStatus(AStatus_fromServiceSpecificError(static_cast<int>(res)));
+ }
+ return ndk::ScopedAStatus(
+ AStatus_fromServiceSpecificErrorWithMessage(static_cast<int>(res), msg.c_str()));
+}
+
+/**
+ * Given a UsbCanIface object, get the ifaceName given the serialPath.
+ *
+ * \param serialPath - Absolute path to a "serial" file for a given device in /sys.
+ * \return A populated UsbCanIface. On failure, nullopt is returned.
+ */
+static std::optional<UsbCanIface> getIfaceName(const fs::path& serialPath) {
+ std::error_code fsStatus;
+ // Since the path is to a file called "serial", we need to search its parent directory.
+ fs::recursive_directory_iterator fsItr(serialPath.parent_path(), kOpts, fsStatus);
+ if (fsStatus != fsErrors::ok) {
+ LOG(ERROR) << "Failed to open " << serialPath.parent_path();
+ return std::nullopt;
+ }
+
+ for (; fsStatus == fsErrors::ok && fsItr != fs::recursive_directory_iterator();
+ fsItr.increment(fsStatus)) {
+ /* We want either a directory called "net" or a directory that looks like tty<something>, so
+ * skip files. */
+ bool isDir = fsItr->is_directory(fsStatus);
+ if (fsStatus != fsErrors::ok || !isDir) continue;
+
+ std::string currentDir = getLeaf(fsItr->path());
+ if (currentDir == "net") {
+ /* This device is a SocketCAN device. The iface name is the only directory under
+ * net/. Multiple directories under net/ is an error.*/
+ fs::directory_iterator netItr(fsItr->path(), kOpts, fsStatus);
+ if (fsStatus != fsErrors::ok) {
+ LOG(ERROR) << "Failed to open " << fsItr->path() << " to get net name!";
+ return std::nullopt;
+ }
+
+ // The leaf of our path should be the interface name.
+ std::string netName = getLeaf(netItr->path());
+
+ // Check if there is more than one item in net/
+ netItr.increment(fsStatus);
+ if (fsStatus != fsErrors::ok) {
+ // It's possible we have a valid net name, but this is most likely an error.
+ LOG(ERROR) << "Failed to verify " << fsItr->path() << " has valid net name!";
+ return std::nullopt;
+ }
+ if (netItr != fs::directory_iterator()) {
+ // There should never be more than one name under net/
+ LOG(ERROR) << "Found more than one net name in " << fsItr->path() << "!";
+ return std::nullopt;
+ }
+ return {{InterfaceType::NATIVE, netName}};
+ } else if (std::regex_match(currentDir, kTtyRe)) {
+ // This device is a USB serial device, and currentDir is the tty name.
+ return {{InterfaceType::SLCAN, "/dev/" + currentDir}};
+ }
+ }
+
+ // check if the loop above exited due to a c++fs error.
+ if (fsStatus != fsErrors::ok) {
+ LOG(ERROR) << "Failed search filesystem: " << fsStatus;
+ }
+ return std::nullopt;
+}
+
+/**
+ * A helper function to read the serial number from a "serial" file in /sys/devices/
+ *
+ * \param serialnoPath - path to the file to read.
+ * \return the serial number, or nullopt on failure.
+ */
+static std::optional<std::string> readSerialNo(const std::string& serialnoPath) {
+ std::ifstream serialnoStream(serialnoPath);
+ std::string serialno;
+ if (!serialnoStream.good()) {
+ LOG(ERROR) << "Failed to read serial number from " << serialnoPath;
+ return std::nullopt;
+ }
+ std::getline(serialnoStream, serialno);
+ return serialno;
+}
+
+/**
+ * Searches for USB devices found in /sys/devices/, and attempts to find a device matching the
+ * provided list of serial numbers.
+ *
+ * \param configSerialnos - a list of serial number (suffixes) from the HAL config.
+ * \param iftype - the type of the interface to be located.
+ * \return a matching USB device. On failure, std::nullopt is returned.
+ */
+static std::optional<UsbCanIface> findUsbDevice(const std::vector<std::string>& configSerialnos) {
+ std::error_code fsStatus;
+ fs::recursive_directory_iterator fsItr(kDevPath, kOpts, fsStatus);
+ if (fsStatus != fsErrors::ok) {
+ LOG(ERROR) << "Failed to open " << kDevPath;
+ return std::nullopt;
+ }
+
+ for (; fsStatus == fsErrors::ok && fsItr != fs::recursive_directory_iterator();
+ fsItr.increment(fsStatus)) {
+ // We want to find a file called "serial", which is in a directory somewhere. Skip files.
+ bool isDir = fsItr->is_directory(fsStatus);
+ if (fsStatus != fsErrors::ok) {
+ LOG(ERROR) << "Failed check if " << fsStatus;
+ return std::nullopt;
+ }
+ if (!isDir) continue;
+
+ auto serialnoPath = fsItr->path() / "serial";
+ bool isReg = fs::is_regular_file(serialnoPath, fsStatus);
+
+ /* Make sure we have permissions to this directory, ignore enoent, since the file
+ * "serial" may not exist, which is ok. */
+ if (fsStatus == fsErrors::eperm || fsStatus == fsErrors::eacces) {
+ /* This means we don't have access to this directory. If we recurse into it, this
+ * will cause the iterator to loose its state and we'll crash. */
+ fsItr.disable_recursion_pending();
+ continue;
+ }
+ if (fsStatus == fsErrors::enoent) continue;
+ if (fsStatus != fsErrors::ok) {
+ LOG(WARNING) << "An unexpected error occurred while checking for serialno: "
+ << fsStatus;
+ continue;
+ }
+ if (!isReg) continue;
+
+ // we found a serial number
+ auto serialno = readSerialNo(serialnoPath);
+ if (!serialno.has_value()) continue;
+
+ // see if the serial number exists in the config
+ for (auto&& cfgSn : configSerialnos) {
+ if (serialno->ends_with(std::string(cfgSn))) {
+ auto ifaceInfo = getIfaceName(serialnoPath);
+ if (!ifaceInfo.has_value()) break;
+ return ifaceInfo;
+ }
+ }
+ }
+ if (fsStatus != fsErrors::ok) {
+ LOG(ERROR) << "Error searching filesystem: " << fsStatus;
+ return std::nullopt;
+ }
+ return std::nullopt;
+}
+
+ndk::ScopedAStatus CanController::getSupportedInterfaceTypes(
+ std::vector<InterfaceType>* supportedTypes) {
+ *supportedTypes = {InterfaceType::VIRTUAL, InterfaceType::NATIVE, InterfaceType::SLCAN};
+ return ok();
+}
+
+ndk::ScopedAStatus CanController::getInterfaceName(const std::string& busName,
+ std::string* ifaceName) {
+ *ifaceName = {};
+ if (mBusesByName.find(busName) == mBusesByName.end()) {
+ return resultToStatus(Result::BAD_BUS_NAME, fmt::format("{} doesn't exist", busName));
+ }
+ *ifaceName = std::string(mBusesByName[busName]->getIfaceName());
+ return ok();
+}
+
+ndk::ScopedAStatus CanController::upBus(const BusConfig& config, std::string* ifaceName) {
+ if (!isValidName(config.name)) {
+ LOG(ERROR) << "Bus name " << config.name << " is invalid";
+ return resultToStatus(Result::BAD_BUS_NAME,
+ fmt::format("{} is not a valid bus name", config.name));
+ } else if (mBusesByName.find(config.name) != mBusesByName.end()) {
+ LOG(ERROR) << "A bus named " << config.name << " already exists!";
+ return resultToStatus(Result::INVALID_STATE,
+ fmt::format("A bus named {} already exists", config.name));
+ }
+
+ if (config.interfaceId.getTag() == BusConfig::InterfaceId::Tag::virtualif) {
+ auto& virtualif = config.interfaceId.get<BusConfig::InterfaceId::Tag::virtualif>();
+ mBusesByName[config.name] = std::make_unique<CanBusVirtual>(virtualif.ifname);
+ }
+
+ else if (config.interfaceId.getTag() == BusConfig::InterfaceId::Tag::nativeif) {
+ auto& nativeif = config.interfaceId.get<BusConfig::InterfaceId::Tag::nativeif>();
+ std::string ifaceName;
+ if (nativeif.interfaceId.getTag() == NativeInterface::InterfaceId::Tag::serialno) {
+ // Configure by serial number.
+ auto selectedDevice = findUsbDevice(
+ nativeif.interfaceId.get<NativeInterface::InterfaceId::Tag::serialno>());
+ // verify the returned device is the correct one
+ if (!selectedDevice.has_value() || selectedDevice->iftype != InterfaceType::NATIVE) {
+ return resultToStatus(
+ Result::BAD_INTERFACE_ID,
+ "Couldn't find a native socketcan device with the given serial number(s)");
+ }
+ ifaceName = selectedDevice->ifaceName;
+ } else {
+ // configure by iface name.
+ ifaceName = nativeif.interfaceId.get<NativeInterface::InterfaceId::Tag::ifname>();
+ }
+ mBusesByName[config.name] = std::make_unique<CanBusNative>(ifaceName, config.bitrate);
+ }
+
+ else if (config.interfaceId.getTag() == BusConfig::InterfaceId::Tag::slcan) {
+ auto& slcanif = config.interfaceId.get<BusConfig::InterfaceId::Tag::slcan>();
+ std::string ttyName;
+ if (slcanif.interfaceId.getTag() == SlcanInterface::InterfaceId::Tag::serialno) {
+ // Configure by serial number.
+ auto selectedDevice = findUsbDevice(
+ slcanif.interfaceId.get<SlcanInterface::InterfaceId::Tag::serialno>());
+ if (!selectedDevice.has_value() || selectedDevice->iftype != InterfaceType::SLCAN) {
+ return resultToStatus(
+ Result::BAD_INTERFACE_ID,
+ "Couldn't find a slcan device with the given serial number(s)");
+ }
+ ttyName = selectedDevice->ifaceName;
+ } else {
+ // Configure by tty name.
+ ttyName = slcanif.interfaceId.get<SlcanInterface::InterfaceId::Tag::ttyname>();
+ }
+ mBusesByName[config.name] = std::make_unique<CanBusSlcan>(ttyName, config.bitrate);
+ }
+
+ else if (config.interfaceId.getTag() == BusConfig::InterfaceId::Tag::indexed) {
+ return resultToStatus(Result::NOT_SUPPORTED,
+ "Indexed devices are not supported in this implementation");
+ } else {
+ // this shouldn't happen.
+ return resultToStatus(Result::UNKNOWN_ERROR, "Unknown interface id type");
+ }
+
+ Result result = mBusesByName[config.name]->up();
+ if (result != Result::OK) {
+ // the bus failed to come up, don't leave a broken entry in the map.
+ mBusesByName.erase(config.name);
+ return resultToStatus(result, fmt::format("CanBus::up failed for {}", config.name));
+ }
+
+ *ifaceName = mBusesByName[config.name]->getIfaceName();
+ return ok();
+}
+
+ndk::ScopedAStatus CanController::downBus(const std::string& busName) {
+ if (mBusesByName.find(busName) == mBusesByName.end()) {
+ return resultToStatus(
+ Result::UNKNOWN_ERROR,
+ fmt::format("Couldn't bring down {}, because it doesn't exist", busName));
+ }
+ Result result = mBusesByName[busName]->down();
+ if (result != Result::OK) {
+ return resultToStatus(result, fmt::format("Couldn't bring down {}!", busName));
+ }
+ mBusesByName.erase(busName);
+ return ok();
+}
+} // namespace aidl::android::hardware::automotive::can
diff --git a/automotive/can/aidl/default/CanController.h b/automotive/can/aidl/default/CanController.h
new file mode 100644
index 0000000..784906e
--- /dev/null
+++ b/automotive/can/aidl/default/CanController.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/automotive/can/BnCanController.h>
+
+#include "CanBus.h"
+
+#include <aidl/android/hardware/automotive/can/Result.h>
+
+#include <map>
+#include <string>
+
+namespace aidl::android::hardware::automotive::can {
+
+class CanController : public BnCanController {
+ public:
+ ndk::ScopedAStatus getSupportedInterfaceTypes(
+ std::vector<InterfaceType>* supportedTypes) override;
+
+ ndk::ScopedAStatus getInterfaceName(const std::string& busName,
+ std::string* ifaceName) override;
+
+ ndk::ScopedAStatus upBus(const BusConfig& config, std::string* ifaceName) override;
+
+ ndk::ScopedAStatus downBus(const std::string& busName) override;
+
+ private:
+ std::map<std::string, std::unique_ptr<CanBus>> mBusesByName = {};
+};
+} // namespace aidl::android::hardware::automotive::can
diff --git a/automotive/can/aidl/default/android.hardware.automotive.can.rc b/automotive/can/aidl/default/android.hardware.automotive.can.rc
new file mode 100644
index 0000000..f843752
--- /dev/null
+++ b/automotive/can/aidl/default/android.hardware.automotive.can.rc
@@ -0,0 +1,5 @@
+service android.hardware.automotive.can /vendor/bin/hw/android.hardware.automotive.can-service
+ class hal
+ capabilities NET_ADMIN
+ user vehicle_network
+ group system inet
diff --git a/automotive/can/aidl/default/android.hardware.automotive.can.xml b/automotive/can/aidl/default/android.hardware.automotive.can.xml
new file mode 100644
index 0000000..873f333
--- /dev/null
+++ b/automotive/can/aidl/default/android.hardware.automotive.can.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest version="1.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.automotive.can</name>
+ <version>1</version>
+ <interface>
+ <name>ICanController</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/automotive/can/aidl/default/service.cpp b/automotive/can/aidl/default/service.cpp
new file mode 100644
index 0000000..eb45167
--- /dev/null
+++ b/automotive/can/aidl/default/service.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CanController.h"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+namespace android::hardware::automotive::can {
+
+using namespace std::string_literals;
+using ::aidl::android::hardware::automotive::can::CanController;
+
+extern "C" int main() {
+ base::SetDefaultTag("CanController");
+ base::SetMinimumLogSeverity(base::VERBOSE);
+
+ LOG(VERBOSE) << "Starting up...";
+ auto service = ndk::SharedRefBase::make<CanController>();
+ const auto instance = CanController::descriptor + "/default"s;
+ const auto status = AServiceManager_addService(service->asBinder().get(), instance.c_str());
+ CHECK_EQ(status, STATUS_OK) << "Failed to add service " << instance;
+ LOG(VERBOSE) << "Started successfully!";
+
+ ABinderProcess_joinThreadPool();
+ LOG(FATAL) << "CanController exited unexpectedly!";
+ return EXIT_FAILURE;
+}
+} // namespace android::hardware::automotive::can
diff --git a/automotive/can/aidl/default/tools/configurator/Android.bp b/automotive/can/aidl/default/tools/configurator/Android.bp
new file mode 100644
index 0000000..1169894
--- /dev/null
+++ b/automotive/can/aidl/default/tools/configurator/Android.bp
@@ -0,0 +1,43 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_binary {
+ name: "canhalconfigurator-aidl",
+ init_rc: ["canhalconfigurator-aidl.rc"],
+ defaults: ["android.hardware.automotive.can@defaults"],
+ srcs: [
+ "canhalconfigurator.cpp",
+ "canprototools.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "libprotobuf-cpp-full",
+ ],
+ static_libs: [
+ "android.hardware.automotive.can-V1-ndk",
+ "android.hardware.automotive.can-aidl-config-format",
+ ],
+}
diff --git a/automotive/can/aidl/default/tools/configurator/canhalconfigurator-aidl.rc b/automotive/can/aidl/default/tools/configurator/canhalconfigurator-aidl.rc
new file mode 100644
index 0000000..e1b4d35
--- /dev/null
+++ b/automotive/can/aidl/default/tools/configurator/canhalconfigurator-aidl.rc
@@ -0,0 +1,3 @@
+service canhalconfigurator /system/bin/canhalconfigurator-aidl
+ class core
+ oneshot
diff --git a/automotive/can/aidl/default/tools/configurator/canhalconfigurator.cpp b/automotive/can/aidl/default/tools/configurator/canhalconfigurator.cpp
new file mode 100644
index 0000000..94e77b4
--- /dev/null
+++ b/automotive/can/aidl/default/tools/configurator/canhalconfigurator.cpp
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "canbus_config.pb.h"
+#include "canprototools.h"
+
+#include <aidl/android/hardware/automotive/can/ICanController.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+
+#include <chrono>
+#include <thread>
+
+namespace android::hardware::automotive::can {
+
+using namespace std::string_literals;
+using ::aidl::android::hardware::automotive::can::ICanController;
+
+static constexpr std::string_view kDefaultConfigPath = "/etc/canbus_config.pb";
+
+/**
+ * Takes output from parsed protobuf config and uses it to configure the CAN HAL.
+ *
+ * \param pb_cfg is an instance of the autogenerated protobuf object for our configuration.
+ * \return boolean status, true on success, false on failure.
+ */
+static bool processPbCfg(const config::CanBusConfig& pb_cfg) {
+ for (auto const& bus : pb_cfg.buses()) {
+ if (bus.name().empty()) {
+ LOG(ERROR) << "Invalid config: Bus config must have a valid name field";
+ return false;
+ }
+
+ auto busCfgMaybe = config::fromPbBus(bus);
+ if (!busCfgMaybe.has_value()) {
+ return false;
+ }
+ auto busCfg = *busCfgMaybe;
+
+ const auto instance = ICanController::descriptor + "/default"s;
+ const auto service = ICanController::fromBinder(
+ ndk::SpAIBinder(AServiceManager_waitForService(instance.c_str())));
+ if (service == nullptr) {
+ LOG(FATAL) << "Can't find CAN HAL! (has it started yet?)";
+ return false;
+ }
+
+ LOG(VERBOSE) << "Bringing up a " << busCfg.name << " @ " << busCfg.bitrate;
+
+ std::string ifaceName;
+ const auto status = service->upBus(busCfg, &ifaceName);
+ if (!status.isOk() && status.getExceptionCode() != EX_SERVICE_SPECIFIC) {
+ LOG(FATAL) << "Binder transaction failed!" << status.getStatus();
+ return false;
+ } else if (!status.isOk()) {
+ LOG(ERROR) << "upBus failed: " << config::resultStringFromStatus(status) << ": "
+ << status.getMessage();
+ continue;
+ }
+
+ LOG(INFO) << bus.name() << " has been successfully configured on " << ifaceName;
+ }
+ return true;
+}
+
+/**
+ * This kicks off the CAN HAL configuration process. This starts the following:
+ * 1. Reading the config file
+ * 2. Setting up CAN buses
+ * 3. Handling services
+ * \param filepath is a string specifying the absolute path of the config file
+ * \return boolean status, true on success, false on failure
+ */
+static bool configuratorStart(const std::string& filepath) {
+ base::SetDefaultTag("CanConfigurator");
+ auto pbCfg = config::parseConfigFile(filepath);
+ if (!pbCfg.has_value()) {
+ return false;
+ }
+ // process the rest of the config file data and configure the CAN buses.
+ if (!processPbCfg(*pbCfg)) {
+ return false;
+ }
+ LOG(INFO) << "CAN HAL has been configured!";
+ return true;
+}
+
+extern "C" int main(int argc, char* argv[]) {
+ std::string configFilepath = static_cast<std::string>(kDefaultConfigPath);
+
+ // allow for CLI specification of a config file.
+ if (argc == 2) {
+ configFilepath = argv[1];
+ } else if (argc > 2) {
+ std::cerr << "usage: " << argv[0] << " [optional config filepath]";
+ return 1;
+ }
+
+ if (!configuratorStart(configFilepath)) {
+ return 1;
+ }
+ return 0;
+}
+
+} // namespace android::hardware::automotive::can
diff --git a/automotive/can/aidl/default/tools/configurator/canprototools.cpp b/automotive/can/aidl/default/tools/configurator/canprototools.cpp
new file mode 100644
index 0000000..2aea315
--- /dev/null
+++ b/automotive/can/aidl/default/tools/configurator/canprototools.cpp
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "canprototools.h"
+
+#include <aidl/android/hardware/automotive/can/IndexedInterface.h>
+#include <aidl/android/hardware/automotive/can/NativeInterface.h>
+#include <aidl/android/hardware/automotive/can/SlcanInterface.h>
+#include <aidl/android/hardware/automotive/can/VirtualInterface.h>
+
+#include <android-base/logging.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/text_format.h>
+
+#include <fstream>
+
+namespace android::hardware::automotive::can::config {
+
+using ::aidl::android::hardware::automotive::can::BusConfig;
+using ::aidl::android::hardware::automotive::can::IndexedInterface;
+using ::aidl::android::hardware::automotive::can::InterfaceType;
+using ::aidl::android::hardware::automotive::can::NativeInterface;
+using ::aidl::android::hardware::automotive::can::Result;
+using ::aidl::android::hardware::automotive::can::SlcanInterface;
+using ::aidl::android::hardware::automotive::can::VirtualInterface;
+
+/**
+ * Helper function for parseConfigFile. readString is used to get the fist n characters (n) from an
+ * istream object (s) and return it as a string object.
+ *
+ * \param s istream of the file you intend to read.
+ * \param n streamsize object of the number of characters you'd like.
+ * \return optional string containing up to n characters from the stream(s) you provided.
+ */
+static std::optional<std::string> readString(std::istream& s, std::streamsize n) {
+ char buff[n];
+ auto got = s.read(buff, n).gcount();
+ if (!s.good() && !s.eof()) return std::nullopt;
+ 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.
+ 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";
+ return std::nullopt;
+ }
+ cfg_stream.seekg(0);
+
+ // check if any of the textHeaders are at the start of the config file.
+ bool text_format = false;
+ for (auto const& header : text_headers) {
+ if (cfg_file_snippet->compare(0, header.length(), header) == 0) {
+ text_format = true;
+ break;
+ }
+ }
+
+ CanBusConfig config;
+ 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;
+ return std::nullopt;
+ }
+ } else if (!config.ParseFromIstream(&cfg_stream)) {
+ LOG(ERROR) << "Failed to parse (binary format) " << filepath;
+ return std::nullopt;
+ }
+ return config;
+}
+
+std::optional<BusConfig> fromPbBus(const Bus& pb_bus) {
+ BusConfig bus_cfg = {};
+ bus_cfg.name = pb_bus.name();
+
+ switch (pb_bus.iface_type_case()) {
+ case Bus::kNative: {
+ const std::string ifname = pb_bus.native().ifname();
+ const std::vector<std::string> serials = {pb_bus.native().serialno().begin(),
+ pb_bus.native().serialno().end()};
+ if (ifname.empty() == serials.empty()) {
+ LOG(ERROR) << "Invalid config: native type bus must have an iface name xor a "
+ << "serial number";
+ return std::nullopt;
+ }
+ bus_cfg.bitrate = pb_bus.bitrate();
+ NativeInterface nativeif = {};
+ if (!ifname.empty())
+ nativeif.interfaceId.set<NativeInterface::InterfaceId::Tag::ifname>(ifname);
+ if (!serials.empty())
+ nativeif.interfaceId.set<NativeInterface::InterfaceId::Tag::serialno>(serials);
+ bus_cfg.interfaceId.set<BusConfig::InterfaceId::Tag::nativeif>(nativeif);
+ break;
+ }
+ case Bus::kSlcan: {
+ const std::string ttyname = pb_bus.slcan().ttyname();
+ const std::vector<std::string> serials = {pb_bus.slcan().serialno().begin(),
+ pb_bus.slcan().serialno().end()};
+ if (ttyname.empty() == serials.empty()) {
+ LOG(ERROR) << "Invalid config: slcan type bus must have a tty name xor a serial "
+ << "number";
+ return std::nullopt;
+ }
+ bus_cfg.bitrate = pb_bus.bitrate();
+ SlcanInterface slcan = {};
+ if (!ttyname.empty())
+ slcan.interfaceId.set<SlcanInterface::InterfaceId::Tag::ttyname>(ttyname);
+ if (!serials.empty())
+ slcan.interfaceId.set<SlcanInterface::InterfaceId::Tag::serialno>(serials);
+ bus_cfg.interfaceId.set<BusConfig::InterfaceId::Tag::slcan>(slcan);
+ break;
+ }
+ case Bus::kVirtual: {
+ // Theoretically, we could just create the next available vcan iface.
+ const std::string ifname = pb_bus.virtual_().ifname();
+ if (ifname.empty()) {
+ LOG(ERROR) << "Invalid config: native type bus must have an iface name";
+ return std::nullopt;
+ }
+ VirtualInterface virtualif = {};
+ virtualif.ifname = ifname;
+ bus_cfg.interfaceId.set<BusConfig::InterfaceId::Tag::virtualif>(virtualif);
+ break;
+ }
+ case Bus::kIndexed: {
+ const uint8_t index = pb_bus.indexed().index();
+ if (index > UINT8_MAX) {
+ LOG(ERROR) << "Interface index out of range: " << index;
+ return std::nullopt;
+ }
+ IndexedInterface indexedif = {};
+ indexedif.index = index;
+ bus_cfg.interfaceId.set<BusConfig::InterfaceId::Tag::indexed>(indexedif);
+ break;
+ }
+ default:
+ LOG(ERROR) << "Invalid config: bad interface type for " << bus_cfg.name;
+ return std::nullopt;
+ }
+ return bus_cfg;
+}
+
+std::optional<InterfaceType> getHalIftype(const Bus& pb_bus) {
+ switch (pb_bus.iface_type_case()) {
+ case Bus::kNative:
+ return InterfaceType::NATIVE;
+ case Bus::kSlcan:
+ return InterfaceType::SLCAN;
+ case Bus::kVirtual:
+ return InterfaceType::VIRTUAL;
+ case Bus::kIndexed:
+ return InterfaceType::INDEXED;
+ default:
+ return std::nullopt;
+ }
+}
+
+std::string resultStringFromStatus(const ndk::ScopedAStatus& status) {
+ const auto res = static_cast<Result>(status.getServiceSpecificError());
+ switch (res) {
+ case Result::OK:
+ return "OK";
+ case Result::UNKNOWN_ERROR:
+ return "UNKNOWN_ERROR";
+ case Result::INVALID_STATE:
+ return "INVALID_STATE";
+ case Result::NOT_SUPPORTED:
+ return "NOT_SUPPORTED";
+ case Result::BAD_INTERFACE_ID:
+ return "BAD_INTERFACE_ID";
+ case Result::BAD_BITRATE:
+ return "BAD_BITRATE";
+ case Result::BAD_BUS_NAME:
+ return "BAD_BUS_NAME";
+ case Result::INTERFACE_DOWN:
+ return "INTERFACE_DOWN";
+ default:
+ return "Invalid Result!";
+ }
+}
+
+} // namespace android::hardware::automotive::can::config
diff --git a/automotive/can/aidl/default/tools/configurator/canprototools.h b/automotive/can/aidl/default/tools/configurator/canprototools.h
new file mode 100644
index 0000000..377ee7f
--- /dev/null
+++ b/automotive/can/aidl/default/tools/configurator/canprototools.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include "canbus_config.pb.h"
+
+#include <aidl/android/hardware/automotive/can/BusConfig.h>
+#include <aidl/android/hardware/automotive/can/InterfaceType.h>
+#include <aidl/android/hardware/automotive/can/Result.h>
+
+namespace android::hardware::automotive::can::config {
+
+/**
+ * This reads the protobuf config file into a protobuf object. Both text based protobuf files as
+ * well as binary format protobuf files are supported.
+ *
+ * \param filepath string containing the name of the config file to read.
+ * \return a CanBusConfig protobuf object constructed from the config file.
+ */
+std::optional<CanBusConfig> parseConfigFile(const std::string& filepath);
+
+/**
+ * Converts protobuf format single-bus config object to a HAL bus config object.
+ *
+ * \param pb_bus is the protobuf object representing a the configuration of one CAN bus.
+ * \return a converted HAL bus config object.
+ */
+std::optional<::aidl::android::hardware::automotive::can::BusConfig> fromPbBus(const Bus& pb_bus);
+
+/**
+ * Get the CAN HAL interface type specified by a given protobuf config object.
+ *
+ * \param pb_bus is the protobuf object representing a the configuration of one CAN bus.
+ * \return the CAN HAL interface type.
+ */
+std::optional<::aidl::android::hardware::automotive::can::InterfaceType> getHalIftype(
+ const Bus& pb_bus);
+
+std::string resultStringFromStatus(const ndk::ScopedAStatus& status);
+
+} // namespace android::hardware::automotive::can::config
diff --git a/automotive/can/aidl/default/tools/configurator/proto/Android.bp b/automotive/can/aidl/default/tools/configurator/proto/Android.bp
new file mode 100644
index 0000000..da1b37c
--- /dev/null
+++ b/automotive/can/aidl/default/tools/configurator/proto/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 {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_static {
+ name: "android.hardware.automotive.can-aidl-config-format",
+ defaults: ["android.hardware.automotive.can@defaults"],
+ proto: {
+ export_proto_headers: true,
+ type: "full",
+ },
+ strip: {
+ keep_symbols: true,
+ },
+ srcs: ["canbus_config.proto"],
+}
diff --git a/automotive/can/aidl/default/tools/configurator/proto/canbus_config.proto b/automotive/can/aidl/default/tools/configurator/proto/canbus_config.proto
new file mode 100644
index 0000000..b03b035
--- /dev/null
+++ b/automotive/can/aidl/default/tools/configurator/proto/canbus_config.proto
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto3";
+
+package android.hardware.automotive.can.config;
+
+message IfaceNative {
+ string ifname = 1;
+ repeated string serialno = 2;
+};
+
+message IfaceSlcan {
+ string ttyname = 1;
+ repeated string serialno = 2;
+};
+
+message IfaceVirtual {
+ string ifname = 1;
+};
+
+message IfaceIndexed {
+ uint32 index = 1;
+};
+
+message Bus {
+ string name = 1; // this is the name presented in the HAL
+ oneof iface_type {
+ IfaceNative native = 2;
+ IfaceSlcan slcan = 3;
+ IfaceVirtual virtual = 4;
+ IfaceIndexed indexed = 5;
+ }
+ uint32 bitrate = 6;
+};
+
+message CanBusConfig {
+ repeated Bus buses = 1;
+};
diff --git a/automotive/can/aidl/vts/functional/Android.bp b/automotive/can/aidl/vts/functional/Android.bp
new file mode 100644
index 0000000..b816a49
--- /dev/null
+++ b/automotive/can/aidl/vts/functional/Android.bp
@@ -0,0 +1,51 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_test {
+ name: "VtsHalCanControllerV1_0Test",
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "android.hardware.automotive.can@defaults",
+ "use_libaidlvintf_gtest_helper_static",
+ ],
+ cpp_std: "experimental",
+ srcs: [
+ "CanControllerAidlTest.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ ],
+ static_libs: [
+ "android.hardware.automotive.can-V1-ndk",
+ "android.hardware.automotive.can@libnetdevice",
+ "libnl++",
+ "libgmock",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+}
diff --git a/automotive/can/aidl/vts/functional/CanControllerAidlTest.cpp b/automotive/can/aidl/vts/functional/CanControllerAidlTest.cpp
new file mode 100644
index 0000000..c2b2879
--- /dev/null
+++ b/automotive/can/aidl/vts/functional/CanControllerAidlTest.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/automotive/can/BusConfig.h>
+#include <aidl/android/hardware/automotive/can/ICanController.h>
+#include <aidl/android/hardware/automotive/can/Result.h>
+#include <aidl/android/hardware/automotive/can/VirtualInterface.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <gtest/gtest.h>
+#include <libnetdevice/libnetdevice.h>
+#include <libnl++/MessageFactory.h>
+#include <libnl++/Socket.h>
+#include <libnl++/printer.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+#include <chrono>
+#include <thread>
+
+using aidl::android::hardware::automotive::can::BusConfig;
+using aidl::android::hardware::automotive::can::ICanController;
+using aidl::android::hardware::automotive::can::VirtualInterface;
+using namespace std::chrono_literals;
+using namespace std::string_literals;
+
+class CanControllerAidlTest : public ::testing::TestWithParam<std::string> {
+ public:
+ virtual void SetUp() override {
+ android::base::SetDefaultTag("CAN_HAL_VTS");
+ android::base::SetMinimumLogSeverity(android::base::VERBOSE);
+ const auto instance = ICanController::descriptor + "/default"s;
+ mCanControllerService = ICanController::fromBinder(
+ ndk::SpAIBinder(AServiceManager_waitForService(instance.c_str())));
+
+ ASSERT_NE(mCanControllerService, nullptr);
+ }
+ virtual void TearDown() override {}
+
+ static bool mTestCaseInitialized;
+ std::shared_ptr<ICanController> mCanControllerService;
+};
+
+// we can't test a real bus, since we can't make any assumptions about hardware
+// this checks upBus, getInterfaceName, and downBus
+TEST_P(CanControllerAidlTest, ToggleBus) {
+ const std::string_view canIface = "vcan50";
+ const std::string busName = "VTS_CAN";
+
+ std::string upBusReturn; // should be vcan50
+ BusConfig config = {};
+ VirtualInterface iface = {};
+ iface.ifname = canIface;
+ config.interfaceId.set<BusConfig::InterfaceId::Tag::virtualif>(iface);
+ config.name = busName;
+ auto aidlStatus = mCanControllerService->upBus(config, &upBusReturn);
+ ASSERT_TRUE(aidlStatus.isOk());
+ EXPECT_EQ(upBusReturn, canIface);
+
+ std::string ifaceName;
+ aidlStatus = mCanControllerService->getInterfaceName(busName, &ifaceName);
+ ASSERT_TRUE(aidlStatus.isOk());
+ EXPECT_EQ(ifaceName, canIface);
+
+ aidlStatus = mCanControllerService->downBus(busName);
+ ASSERT_TRUE(aidlStatus.isOk());
+}
+
+TEST_P(CanControllerAidlTest, GetSupported) {
+ LOG(VERBOSE) << "Get the supported iface types";
+ std::vector<::aidl::android::hardware::automotive::can::InterfaceType> supportedTypes;
+ auto aidlStatus = mCanControllerService->getSupportedInterfaceTypes(&supportedTypes);
+ ASSERT_TRUE(aidlStatus.isOk());
+ EXPECT_FALSE(supportedTypes.empty());
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(CanControllerAidlTest);
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, CanControllerAidlTest,
+ testing::ValuesIn(android::getAidlHalInstanceNames(ICanController::descriptor)),
+ android::PrintInstanceNameToString);
diff --git a/automotive/can/aidl/vts/functional/OWNERS b/automotive/can/aidl/vts/functional/OWNERS
new file mode 100644
index 0000000..85257a3
--- /dev/null
+++ b/automotive/can/aidl/vts/functional/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 533426
+twasilczyk@google.com
+chrisweir@google.com
diff --git a/automotive/vehicle/aidl/Android.bp b/automotive/vehicle/aidl/Android.bp
index 9aeb4d2..18a5046 100644
--- a/automotive/vehicle/aidl/Android.bp
+++ b/automotive/vehicle/aidl/Android.bp
@@ -27,6 +27,7 @@
srcs: [
"android/hardware/automotive/vehicle/**/*.aidl",
],
+ frozen: false,
stability: "vintf",
backend: {
cpp: {
diff --git a/biometrics/common/aidl/Android.bp b/biometrics/common/aidl/Android.bp
index 3cd76fd..88edf04 100644
--- a/biometrics/common/aidl/Android.bp
+++ b/biometrics/common/aidl/Android.bp
@@ -13,6 +13,7 @@
srcs: [
"android/hardware/biometrics/common/*.aidl",
],
+ frozen: false,
stability: "vintf",
backend: {
java: {
diff --git a/camera/common/aidl/Android.bp b/camera/common/aidl/Android.bp
index e1c9cc5..4ffcfd9 100644
--- a/camera/common/aidl/Android.bp
+++ b/camera/common/aidl/Android.bp
@@ -11,6 +11,7 @@
name: "android.hardware.camera.common",
vendor_available: true,
srcs: ["android/hardware/camera/common/*.aidl"],
+ frozen: true,
stability: "vintf",
backend: {
cpp: {
diff --git a/camera/device/aidl/Android.bp b/camera/device/aidl/Android.bp
index 2e5b667..bf5bf63 100644
--- a/camera/device/aidl/Android.bp
+++ b/camera/device/aidl/Android.bp
@@ -11,6 +11,7 @@
name: "android.hardware.camera.device",
vendor_available: true,
srcs: ["android/hardware/camera/device/*.aidl"],
+ frozen: false,
stability: "vintf",
imports: [
"android.hardware.common-V2",
diff --git a/camera/metadata/aidl/Android.bp b/camera/metadata/aidl/Android.bp
index 0113a4b..7bec61d 100644
--- a/camera/metadata/aidl/Android.bp
+++ b/camera/metadata/aidl/Android.bp
@@ -11,6 +11,7 @@
name: "android.hardware.camera.metadata",
vendor_available: true,
srcs: ["android/hardware/camera/metadata/*.aidl"],
+ frozen: false,
stability: "vintf",
backend: {
cpp: {
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index 9f43219..d4b1fad 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -31,6 +31,13 @@
<interface>
<name>IModule</name>
<instance>default</instance>
+ <instance>a2dp</instance>
+ <instance>bluetooth</instance>
+ <instance>hearing_aid</instance>
+ <instance>msd</instance>
+ <instance>r_submix</instance>
+ <instance>stub</instance>
+ <instance>usb</instance>
</interface>
<interface>
<name>IConfig</name>
@@ -68,6 +75,14 @@
<instance>default</instance>
</interface>
</hal>
+ <hal format="aidl" optional="true">
+ <name>android.hardware.automotive.can</name>
+ <version>1</version>
+ <interface>
+ <name>ICanController</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
<hal format="hidl" optional="true">
<name>android.hardware.automotive.can</name>
<version>1.0</version>
@@ -577,6 +592,7 @@
</hal>
<hal format="aidl" optional="true">
<name>android.hardware.sensors</name>
+ <version>2</version>
<interface>
<name>ISensors</name>
<instance>default</instance>
@@ -707,14 +723,6 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.wifi</name>
- <version>1.3-6</version>
- <interface>
- <name>IWifi</name>
- <instance>default</instance>
- </interface>
- </hal>
<hal format="aidl" optional="true">
<name>android.hardware.uwb</name>
<version>1</version>
diff --git a/graphics/composer/2.2/utils/vts/ComposerVts.cpp b/graphics/composer/2.2/utils/vts/ComposerVts.cpp
index b706596..a6dfcaf 100644
--- a/graphics/composer/2.2/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.2/utils/vts/ComposerVts.cpp
@@ -126,15 +126,23 @@
ASSERT_EQ(Error::NONE, error) << "failed to setReadbackBuffer";
}
-void ComposerClient::getReadbackBufferAttributes(Display display, PixelFormat* outPixelFormat,
- Dataspace* outDataspace) {
+void ComposerClient::getRequiredReadbackBufferAttributes(Display display,
+ PixelFormat* outPixelFormat,
+ Dataspace* outDataspace) {
+ ASSERT_EQ(Error::NONE, getReadbackBufferAttributes(display, outPixelFormat, outDataspace));
+}
+
+Error ComposerClient::getReadbackBufferAttributes(Display display, PixelFormat* outPixelFormat,
+ Dataspace* outDataspace) {
+ Error error;
mClient->getReadbackBufferAttributes(
- display,
- [&](const auto& tmpError, const auto& tmpOutPixelFormat, const auto& tmpOutDataspace) {
- ASSERT_EQ(Error::NONE, tmpError) << "failed to get readback buffer attributes";
- *outPixelFormat = tmpOutPixelFormat;
- *outDataspace = tmpOutDataspace;
- });
+ display, [&](const Error& tmpError, const PixelFormat& tmpPixelFormat,
+ const Dataspace& tmpDataspace) {
+ error = tmpError;
+ *outPixelFormat = tmpPixelFormat;
+ *outDataspace = tmpDataspace;
+ });
+ return error;
}
void ComposerClient::getReadbackBufferFence(Display display, int32_t* outFence) {
diff --git a/graphics/composer/2.2/utils/vts/ReadbackVts.cpp b/graphics/composer/2.2/utils/vts/ReadbackVts.cpp
index a1794af..5dd68df 100644
--- a/graphics/composer/2.2/utils/vts/ReadbackVts.cpp
+++ b/graphics/composer/2.2/utils/vts/ReadbackVts.cpp
@@ -19,6 +19,8 @@
#include "renderengine/ExternalTexture.h"
#include "renderengine/impl/ExternalTexture.h"
+using ::android::status_t;
+
namespace android {
namespace hardware {
namespace graphics {
@@ -107,6 +109,40 @@
}
}
+void ReadbackHelper::fillBufferAndGetFence(const sp<GraphicBuffer>& graphicBuffer,
+ IComposerClient::Color desiredColor, int* fillFence) {
+ ASSERT_NE(nullptr, fillFence);
+ std::vector<IComposerClient::Color> desiredColors(
+ static_cast<size_t>(graphicBuffer->getWidth() * graphicBuffer->getHeight()));
+ ::android::Rect bounds = graphicBuffer->getBounds();
+ fillColorsArea(desiredColors, static_cast<int32_t>(graphicBuffer->getWidth()),
+ {bounds.left, bounds.top, bounds.right, bounds.bottom}, desiredColor);
+ ASSERT_NO_FATAL_FAILURE(fillBufferAndGetFence(graphicBuffer, desiredColors, fillFence));
+}
+
+void ReadbackHelper::fillBufferAndGetFence(const sp<GraphicBuffer>& graphicBuffer,
+ const std::vector<IComposerClient::Color>& desiredColors,
+ int* fillFence) {
+ ASSERT_TRUE(graphicBuffer->getPixelFormat() == ::android::PIXEL_FORMAT_RGB_888 ||
+ graphicBuffer->getPixelFormat() == ::android::PIXEL_FORMAT_RGBA_8888);
+ void* bufData;
+ int32_t bytesPerPixel = -1;
+ int32_t bytesPerStride = -1;
+ status_t status =
+ graphicBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+ &bufData, &bytesPerPixel, &bytesPerStride);
+ ASSERT_EQ(::android::OK, status);
+
+ const uint32_t stride = (bytesPerPixel > 0 && bytesPerStride > 0)
+ ? static_cast<uint32_t>(bytesPerStride / bytesPerPixel)
+ : graphicBuffer->getStride();
+ ReadbackHelper::fillBuffer(graphicBuffer->getWidth(), graphicBuffer->getHeight(), stride,
+ bufData, static_cast<PixelFormat>(graphicBuffer->getPixelFormat()),
+ desiredColors);
+ status = graphicBuffer->unlockAsync(fillFence);
+ ASSERT_EQ(::android::OK, status);
+}
+
void ReadbackHelper::fillBuffer(int32_t width, int32_t height, uint32_t stride, void* bufferData,
PixelFormat pixelFormat,
std::vector<IComposerClient::Color> desiredPixelColors) {
@@ -116,16 +152,16 @@
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
int pixel = row * width + col;
- IComposerClient::Color srcColor = desiredPixelColors[pixel];
+ IComposerClient::Color desiredColor = desiredPixelColors[pixel];
int offset = (row * stride + col) * bytesPerPixel;
uint8_t* pixelColor = (uint8_t*)bufferData + offset;
- pixelColor[0] = srcColor.r;
- pixelColor[1] = srcColor.g;
- pixelColor[2] = srcColor.b;
+ pixelColor[0] = desiredColor.r;
+ pixelColor[1] = desiredColor.g;
+ pixelColor[2] = desiredColor.b;
if (bytesPerPixel == 4) {
- pixelColor[3] = srcColor.a;
+ pixelColor[3] = desiredColor.a;
}
}
}
@@ -152,12 +188,14 @@
}
}
-bool ReadbackHelper::readbackSupported(const PixelFormat& pixelFormat, const Dataspace& dataspace,
- const Error error) {
+bool ReadbackHelper::readbackSupported(PixelFormat pixelFormat, Dataspace dataspace, Error error) {
if (error != Error::NONE) {
return false;
}
- // TODO: add support for RGBA_1010102
+ return readbackSupported(pixelFormat, dataspace);
+}
+
+bool ReadbackHelper::readbackSupported(PixelFormat pixelFormat, Dataspace dataspace) {
if (pixelFormat != PixelFormat::RGB_888 && pixelFormat != PixelFormat::RGBA_8888) {
return false;
}
@@ -167,71 +205,94 @@
return true;
}
-void ReadbackHelper::compareColorBuffers(std::vector<IComposerClient::Color>& expectedColors,
- void* bufferData, const uint32_t stride,
- const uint32_t width, const uint32_t height,
- const PixelFormat pixelFormat) {
- const int32_t bytesPerPixel = ReadbackHelper::GetBytesPerPixel(pixelFormat);
- ASSERT_NE(-1, bytesPerPixel);
- for (int row = 0; row < height; row++) {
- for (int col = 0; col < width; col++) {
- int pixel = row * width + col;
- int offset = (row * stride + col) * bytesPerPixel;
- uint8_t* pixelColor = (uint8_t*)bufferData + offset;
+void ReadbackHelper::createReadbackBuffer(uint32_t width, uint32_t height, PixelFormat pixelFormat,
+ Dataspace dataspace, sp<GraphicBuffer>* graphicBuffer) {
+ ASSERT_NE(nullptr, graphicBuffer);
+ if (!readbackSupported(pixelFormat, dataspace)) {
+ *graphicBuffer = nullptr;
+ }
+ android::PixelFormat bufferFormat = static_cast<android::PixelFormat>(pixelFormat);
+ uint32_t layerCount = 1;
+ uint64_t usage = static_cast<uint64_t>(static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN) |
+ static_cast<uint64_t>(BufferUsage::GPU_TEXTURE));
+ *graphicBuffer = sp<GraphicBuffer>::make(width, height, bufferFormat, layerCount, usage,
+ "ReadbackBuffer");
+ ASSERT_NE(nullptr, *graphicBuffer);
+ ASSERT_EQ(::android::OK, (*graphicBuffer)->initCheck());
+}
- ASSERT_EQ(expectedColors[pixel].r, pixelColor[0]);
- ASSERT_EQ(expectedColors[pixel].g, pixelColor[1]);
- ASSERT_EQ(expectedColors[pixel].b, pixelColor[2]);
+void ReadbackHelper::compareColorToBuffer(IComposerClient::Color expectedColor,
+ const sp<GraphicBuffer>& graphicBuffer, int32_t fence) {
+ std::vector<IComposerClient::Color> expectedColors(
+ static_cast<size_t>(graphicBuffer->getWidth() * graphicBuffer->getHeight()));
+ ::android::Rect bounds = graphicBuffer->getBounds();
+ fillColorsArea(expectedColors, static_cast<int32_t>(graphicBuffer->getWidth()),
+ {bounds.left, bounds.top, bounds.right, bounds.bottom}, expectedColor);
+ compareColorsToBuffer(expectedColors, graphicBuffer, fence);
+}
+
+void ReadbackHelper::compareColorsToBuffer(std::vector<IComposerClient::Color>& expectedColors,
+ const sp<GraphicBuffer>& graphicBuffer, int32_t fence) {
+ ASSERT_TRUE(graphicBuffer->getPixelFormat() == ::android::PIXEL_FORMAT_RGB_888 ||
+ graphicBuffer->getPixelFormat() == ::android::PIXEL_FORMAT_RGBA_8888);
+
+ int bytesPerPixel = -1;
+ int bytesPerStride = -1;
+ void* bufData = nullptr;
+ status_t status = graphicBuffer->lockAsync(GRALLOC_USAGE_SW_READ_OFTEN, &bufData, fence,
+ &bytesPerPixel, &bytesPerStride);
+ ASSERT_EQ(::android::OK, status);
+
+ const uint32_t stride = (bytesPerPixel > 0 && bytesPerStride > 0)
+ ? static_cast<uint32_t>(bytesPerStride / bytesPerPixel)
+ : graphicBuffer->getStride();
+
+ if (bytesPerPixel == -1) {
+ PixelFormat pixelFormat = static_cast<PixelFormat>(graphicBuffer->getPixelFormat());
+ bytesPerPixel = ReadbackHelper::GetBytesPerPixel(pixelFormat);
+ }
+ ASSERT_NE(-1, bytesPerPixel);
+ for (int row = 0; row < graphicBuffer->getHeight(); row++) {
+ for (int col = 0; col < graphicBuffer->getWidth(); col++) {
+ int pixel = row * static_cast<int32_t>(graphicBuffer->getWidth()) + col;
+ int offset = (row * static_cast<int32_t>(stride) + col) * bytesPerPixel;
+ uint8_t* pixelColor = (uint8_t*)bufData + offset;
+ const IComposerClient::Color expectedColor = expectedColors[static_cast<size_t>(pixel)];
+ ASSERT_EQ(std::round(255.0f * expectedColor.r), pixelColor[0]);
+ ASSERT_EQ(std::round(255.0f * expectedColor.g), pixelColor[1]);
+ ASSERT_EQ(std::round(255.0f * expectedColor.b), pixelColor[2]);
}
}
+
+ status = graphicBuffer->unlock();
+ ASSERT_EQ(::android::OK, status);
}
ReadbackBuffer::ReadbackBuffer(Display display, const std::shared_ptr<ComposerClient>& client,
- const std::shared_ptr<Gralloc>& gralloc, uint32_t width,
- uint32_t height, PixelFormat pixelFormat, Dataspace dataspace) {
+ uint32_t width, uint32_t height, PixelFormat pixelFormat) {
mDisplay = display;
-
mComposerClient = client;
- mGralloc = gralloc;
-
- mPixelFormat = pixelFormat;
- mDataspace = dataspace;
-
mWidth = width;
mHeight = height;
+ mPixelFormat = pixelFormat;
mLayerCount = 1;
- mFormat = mPixelFormat;
mUsage = static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::GPU_TEXTURE);
-
- mAccessRegion.top = 0;
- mAccessRegion.left = 0;
- mAccessRegion.width = width;
- mAccessRegion.height = height;
}
void ReadbackBuffer::setReadbackBuffer() {
- mBufferHandle.reset(new Gralloc::NativeHandleWrapper(
- mGralloc->allocate(mWidth, mHeight, mLayerCount, mFormat, mUsage,
- /*import*/ true, &mStride)));
- ASSERT_NE(false, mGralloc->validateBufferSize(mBufferHandle->get(), mWidth, mHeight,
- mLayerCount, mFormat, mUsage, mStride));
- ASSERT_NO_FATAL_FAILURE(mComposerClient->setReadbackBuffer(mDisplay, mBufferHandle->get(), -1));
+ mGraphicBuffer = sp<GraphicBuffer>::make(mWidth, mHeight,
+ static_cast<::android::PixelFormat>(mPixelFormat),
+ mLayerCount, mUsage, "ReadbackBuffer");
+ ASSERT_NE(nullptr, mGraphicBuffer);
+ ASSERT_EQ(::android::OK, mGraphicBuffer->initCheck());
+ mComposerClient->setReadbackBuffer(mDisplay, mGraphicBuffer->handle, -1 /* fence */);
}
void ReadbackBuffer::checkReadbackBuffer(std::vector<IComposerClient::Color> expectedColors) {
// lock buffer for reading
int32_t fenceHandle;
ASSERT_NO_FATAL_FAILURE(mComposerClient->getReadbackBufferFence(mDisplay, &fenceHandle));
-
- void* bufData = mGralloc->lock(mBufferHandle->get(), mUsage, mAccessRegion, fenceHandle);
- ASSERT_TRUE(mPixelFormat == PixelFormat::RGB_888 || mPixelFormat == PixelFormat::RGBA_8888);
- ReadbackHelper::compareColorBuffers(expectedColors, bufData, mStride, mWidth, mHeight,
- mPixelFormat);
- int32_t unlockFence = mGralloc->unlock(mBufferHandle->get());
- if (unlockFence != -1) {
- sync_wait(unlockFence, -1);
- close(unlockFence);
- }
+ ReadbackHelper::compareColorsToBuffer(expectedColors, mGraphicBuffer, fenceHandle);
}
void TestColorLayer::write(const std::shared_ptr<CommandWriterBase>& writer) {
diff --git a/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp b/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
index 1700b2a..254ff3b 100644
--- a/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
+++ b/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
@@ -83,9 +83,7 @@
void TestRenderEngine::checkColorBuffer(std::vector<V2_2::IComposerClient::Color>& expectedColors) {
void* bufferData;
ASSERT_EQ(0, mGraphicBuffer->lock(mGraphicBuffer->getUsage(), &bufferData));
- ReadbackHelper::compareColorBuffers(expectedColors, bufferData, mGraphicBuffer->getStride(),
- mGraphicBuffer->getWidth(), mGraphicBuffer->getHeight(),
- mFormat);
+ ReadbackHelper::compareColorsToBuffer(expectedColors, mGraphicBuffer, -1 /* fence */);
ASSERT_EQ(0, mGraphicBuffer->unlock());
}
diff --git a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
index 02d7bdb..bbf8ef3 100644
--- a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
+++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
@@ -78,8 +78,10 @@
PixelFormat format, Dataspace dataspace);
void setPowerMode_2_2(Display display, IComposerClient::PowerMode mode);
void setReadbackBuffer(Display display, const native_handle_t* buffer, int32_t releaseFence);
- void getReadbackBufferAttributes(Display display, PixelFormat* outPixelFormat,
- Dataspace* outDataspace);
+ void getRequiredReadbackBufferAttributes(Display display, PixelFormat* outPixelFormat,
+ Dataspace* outDataspace);
+ Error getReadbackBufferAttributes(Display display, PixelFormat* outPixelFormat,
+ Dataspace* outDataspace);
void getReadbackBufferFence(Display display, int32_t* outFence);
std::vector<ColorMode> getColorModes(Display display);
diff --git a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h
index 58efde9..7100297 100644
--- a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h
+++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h
@@ -34,6 +34,8 @@
namespace V2_2 {
namespace vts {
+using android::GraphicBuffer;
+using android::sp;
using android::hardware::hidl_handle;
using common::V1_1::BufferUsage;
using common::V1_1::Dataspace;
@@ -156,6 +158,13 @@
static int32_t GetBytesPerPixel(PixelFormat pixelFormat);
+ static void fillBufferAndGetFence(const sp<GraphicBuffer>& graphicBuffer,
+ IComposerClient::Color desiredColor, int* fillFence);
+
+ static void fillBufferAndGetFence(const sp<GraphicBuffer>& graphicBuffer,
+ const std::vector<IComposerClient::Color>& desiredColors,
+ int* fillFence);
+
static void fillBuffer(int32_t width, int32_t height, uint32_t stride, void* bufferData,
PixelFormat pixelFormat,
std::vector<IComposerClient::Color> desiredPixelColors);
@@ -166,40 +175,39 @@
static void fillColorsArea(std::vector<IComposerClient::Color>& expectedColors, int32_t stride,
IComposerClient::Rect area, IComposerClient::Color color);
- static bool readbackSupported(const PixelFormat& pixelFormat, const Dataspace& dataspace,
- const Error error);
-
static const std::vector<ColorMode> colorModes;
static const std::vector<Dataspace> dataspaces;
- static void compareColorBuffers(std::vector<IComposerClient::Color>& expectedColors,
- void* bufferData, const uint32_t stride, const uint32_t width,
- const uint32_t height, const PixelFormat pixelFormat);
+ static bool readbackSupported(PixelFormat pixelFormat, Dataspace dataspace, Error error);
+ static bool readbackSupported(PixelFormat pixelFormat, Dataspace dataspace);
+
+ static void createReadbackBuffer(uint32_t width, uint32_t height, PixelFormat pixelFormat,
+ Dataspace dataspace, sp<GraphicBuffer>* graphicBuffer);
+
+ static void compareColorToBuffer(IComposerClient::Color expectedColors,
+ const sp<GraphicBuffer>& graphicBuffer, int32_t fence);
+
+ static void compareColorsToBuffer(std::vector<IComposerClient::Color>& expectedColors,
+ const sp<GraphicBuffer>& graphicBuffer, int32_t fence);
};
class ReadbackBuffer {
public:
- ReadbackBuffer(Display display, const std::shared_ptr<ComposerClient>& client,
- const std::shared_ptr<Gralloc>& gralloc, uint32_t width, uint32_t height,
- PixelFormat pixelFormat, Dataspace dataspace);
+ ReadbackBuffer(Display display, const std::shared_ptr<ComposerClient>& client, uint32_t width,
+ uint32_t height, PixelFormat pixelFormat);
void setReadbackBuffer();
void checkReadbackBuffer(std::vector<IComposerClient::Color> expectedColors);
protected:
+ sp<GraphicBuffer> mGraphicBuffer;
uint32_t mWidth;
uint32_t mHeight;
- uint32_t mLayerCount;
- PixelFormat mFormat;
- uint64_t mUsage;
- AccessRegion mAccessRegion;
- uint32_t mStride;
- std::unique_ptr<Gralloc::NativeHandleWrapper> mBufferHandle = nullptr;
PixelFormat mPixelFormat;
- Dataspace mDataspace;
+ uint32_t mLayerCount;
+ uint64_t mUsage;
Display mDisplay;
- std::shared_ptr<Gralloc> mGralloc;
std::shared_ptr<ComposerClient> mComposerClient;
};
diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
index e2a0f4d..5b8ce3f 100644
--- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
+++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
@@ -40,7 +40,6 @@
namespace {
using android::Rect;
-using common::V1_1::BufferUsage;
using common::V1_1::Dataspace;
using common::V1_1::PixelFormat;
using V2_1::Config;
@@ -100,8 +99,8 @@
mTestRenderEngine->initGraphicBuffer(
static_cast<uint32_t>(mDisplayWidth), static_cast<uint32_t>(mDisplayHeight), 1,
- static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::GPU_RENDER_TARGET));
+ GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_OFTEN |
+ GRALLOC_USAGE_HW_RENDER);
mTestRenderEngine->setDisplaySettings(clientCompositionDisplay);
}
@@ -116,6 +115,22 @@
}
}
+ sp<GraphicBuffer> allocateBuffer(uint32_t width, uint32_t height, uint32_t usage) {
+ const auto& graphicBuffer = sp<GraphicBuffer>::make(
+ width, height, android::PIXEL_FORMAT_RGBA_8888,
+ /*layerCount*/ 1u, usage, "VtsHalGraphicsComposer2_2_ReadbackTest");
+
+ if (graphicBuffer && android::OK == graphicBuffer->initCheck()) {
+ return nullptr;
+ }
+ return graphicBuffer;
+ }
+
+ sp<GraphicBuffer> allocateBuffer(uint32_t usage) {
+ return allocateBuffer(static_cast<uint32_t>(mDisplayWidth),
+ static_cast<uint32_t>(mDisplayHeight), usage);
+ }
+
void clearCommandReaderState() {
mReader->mCompositionChanges.clear();
mReader->mErrors.clear();
@@ -193,15 +208,9 @@
ASSERT_NO_FATAL_FAILURE(
mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
- mComposerClient->getRaw()->getReadbackBufferAttributes(
- mPrimaryDisplay,
- [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
- mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
- tmpDataspace, tmpError);
- mPixelFormat = tmpPixelFormat;
- mDataspace = tmpDataspace;
- });
-
+ Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &mPixelFormat,
+ &mDataspace);
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(mPixelFormat, mDataspace, error);
if (!mHasReadbackBuffer) {
std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
@@ -220,8 +229,8 @@
std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, coloredSquare, BLUE);
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+ mDisplayHeight, mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(layers);
@@ -255,15 +264,9 @@
ASSERT_NO_FATAL_FAILURE(
mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
- mComposerClient->getRaw()->getReadbackBufferAttributes(
- mPrimaryDisplay,
- [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
- mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
- tmpDataspace, tmpError);
- mPixelFormat = tmpPixelFormat;
- mDataspace = tmpDataspace;
- });
-
+ Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &mPixelFormat,
+ &mDataspace);
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(mPixelFormat, mDataspace, error);
if (!mHasReadbackBuffer) {
std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
@@ -272,8 +275,8 @@
mWriter->selectDisplay(mPrimaryDisplay);
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+ mDisplayHeight, mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
@@ -319,6 +322,155 @@
}
}
+TEST_P(GraphicsCompositionTest, SetLayerBufferWithSlotsToClear) {
+ Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &mPixelFormat,
+ &mDataspace);
+ if (error == Error::UNSUPPORTED) {
+ GTEST_SUCCEED() << "Readback is unsupported";
+ return;
+ }
+ ASSERT_EQ(Error::NONE, error);
+
+ sp<GraphicBuffer> readbackBuffer;
+ ASSERT_NO_FATAL_FAILURE(ReadbackHelper::createReadbackBuffer(
+ mDisplayWidth, mDisplayHeight, mPixelFormat, mDataspace, &readbackBuffer));
+ if (readbackBuffer == nullptr) {
+ GTEST_SUCCEED() << "Unsupported readback buffer attributes";
+ return;
+ }
+ // no fence needed for the readback buffer
+ int noFence = -1;
+
+ sp<GraphicBuffer> clearSlotBuffer = allocateBuffer(1u, 1u, GRALLOC_USAGE_HW_COMPOSER);
+ ASSERT_NE(nullptr, clearSlotBuffer);
+
+ // red buffer
+ uint32_t usage = GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_OFTEN;
+ sp<GraphicBuffer> redBuffer = allocateBuffer(usage);
+ ASSERT_NE(nullptr, redBuffer);
+ int redFence;
+ ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBufferAndGetFence(redBuffer, RED, &redFence));
+
+ // blue buffer
+ sp<GraphicBuffer> blueBuffer = allocateBuffer(usage);
+ ASSERT_NE(nullptr, blueBuffer);
+ int blueFence;
+ ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBufferAndGetFence(blueBuffer, BLUE, &blueFence));
+
+ // layer defaults
+ IComposerClient::Rect rectFullDisplay = {0, 0, mDisplayWidth, mDisplayHeight};
+ Layer layer = mComposerClient->createLayer(mPrimaryDisplay, 3);
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->selectLayer(layer);
+ mWriter->setLayerDisplayFrame(rectFullDisplay);
+ mWriter->setLayerCompositionType(IComposerClient::Composition::DEVICE);
+
+ // set the layer to the blue buffer
+ // should be blue
+ {
+ ASSERT_NO_FATAL_FAILURE(mComposerClient->setReadbackBuffer(
+ mPrimaryDisplay, readbackBuffer->handle, noFence));
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->selectLayer(layer);
+ mWriter->setLayerBuffer(/*slot*/ 0, blueBuffer->handle, blueFence);
+ mWriter->validateDisplay();
+ execute();
+ ASSERT_TRUE(mReader->mCompositionChanges.empty());
+ ASSERT_TRUE(mReader->mErrors.size());
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->presentDisplay();
+ execute();
+ int32_t fence;
+ ASSERT_NO_FATAL_FAILURE(mComposerClient->getReadbackBufferFence(mPrimaryDisplay, &fence));
+ ASSERT_NO_FATAL_FAILURE(ReadbackHelper::compareColorToBuffer(BLUE, readbackBuffer, fence));
+ }
+
+ // change the layer to the red buffer
+ // should be red
+ {
+ ASSERT_NO_FATAL_FAILURE(mComposerClient->setReadbackBuffer(
+ mPrimaryDisplay, readbackBuffer->handle, noFence));
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->selectLayer(layer);
+ mWriter->setLayerBuffer(/*slot*/ 1, redBuffer->handle, redFence);
+ mWriter->validateDisplay();
+ execute();
+ ASSERT_TRUE(mReader->mCompositionChanges.empty());
+ ASSERT_TRUE(mReader->mErrors.size());
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->presentDisplay();
+ execute();
+ int32_t fence;
+ ASSERT_NO_FATAL_FAILURE(mComposerClient->getReadbackBufferFence(mPrimaryDisplay, &fence));
+ ReadbackHelper::compareColorToBuffer(RED, readbackBuffer, fence);
+ }
+
+ // clear the slot for the blue buffer
+ // should still be red
+ {
+ ASSERT_NO_FATAL_FAILURE(mComposerClient->setReadbackBuffer(
+ mPrimaryDisplay, readbackBuffer->handle, noFence));
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->selectLayer(layer);
+ mWriter->setLayerBuffer(/*slot*/ 0, clearSlotBuffer->handle, /*fence*/ -1);
+ mWriter->validateDisplay();
+ execute();
+ ASSERT_TRUE(mReader->mCompositionChanges.empty());
+ ASSERT_TRUE(mReader->mErrors.size());
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->presentDisplay();
+ execute();
+ int32_t fence;
+ ASSERT_NO_FATAL_FAILURE(mComposerClient->getReadbackBufferFence(mPrimaryDisplay, &fence));
+ ReadbackHelper::compareColorToBuffer(RED, readbackBuffer, fence);
+ }
+
+ // clear the slot for the red buffer, and set the buffer with the same slot to the blue buffer
+ // should be blue
+ {
+ ASSERT_NO_FATAL_FAILURE(mComposerClient->setReadbackBuffer(
+ mPrimaryDisplay, readbackBuffer->handle, noFence));
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->selectLayer(layer);
+ mWriter->setLayerBuffer(/*slot*/ 1, clearSlotBuffer->handle, /*fence*/ -1);
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->selectLayer(layer);
+ mWriter->setLayerBuffer(/*slot*/ 1, blueBuffer->handle, blueFence);
+ mWriter->validateDisplay();
+ execute();
+ ASSERT_TRUE(mReader->mCompositionChanges.empty());
+ ASSERT_TRUE(mReader->mErrors.size());
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->presentDisplay();
+ execute();
+ int32_t fence;
+ ASSERT_NO_FATAL_FAILURE(mComposerClient->getReadbackBufferFence(mPrimaryDisplay, &fence));
+ ReadbackHelper::compareColorToBuffer(BLUE, readbackBuffer, fence);
+ }
+
+ // clear the slot for the now-blue buffer
+ // should be black (no buffer)
+ // TODO(b/262037933) Ensure we never clear the active buffer's slot with the placeholder buffer
+ // by setting the layer to the color black
+ {
+ ASSERT_NO_FATAL_FAILURE(mComposerClient->setReadbackBuffer(
+ mPrimaryDisplay, readbackBuffer->handle, noFence));
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->selectLayer(layer);
+ mWriter->setLayerBuffer(/*slot*/ 1, clearSlotBuffer->handle, /*fence*/ -1);
+ mWriter->validateDisplay();
+ execute();
+ ASSERT_TRUE(mReader->mCompositionChanges.empty());
+ ASSERT_TRUE(mReader->mErrors.size());
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->presentDisplay();
+ execute();
+ int32_t fence;
+ ASSERT_NO_FATAL_FAILURE(mComposerClient->getReadbackBufferFence(mPrimaryDisplay, &fence));
+ ReadbackHelper::compareColorToBuffer(BLACK, readbackBuffer, fence);
+ }
+}
+
TEST_P(GraphicsCompositionTest, SetLayerBufferNoEffect) {
for (ColorMode mode : mTestColorModes) {
std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
@@ -327,15 +479,9 @@
ASSERT_NO_FATAL_FAILURE(
mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
- mComposerClient->getRaw()->getReadbackBufferAttributes(
- mPrimaryDisplay,
- [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
- mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
- tmpDataspace, tmpError);
- mPixelFormat = tmpPixelFormat;
- mDataspace = tmpDataspace;
- });
-
+ Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &mPixelFormat,
+ &mDataspace);
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(mPixelFormat, mDataspace, error);
if (!mHasReadbackBuffer) {
std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
@@ -350,8 +496,7 @@
layer->write(mWriter);
// This following buffer call should have no effect
- uint64_t usage =
- static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN);
+ uint32_t usage = GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_OFTEN;
NativeHandleWrapper bufferHandle =
mGralloc->allocate(mDisplayWidth, mDisplayHeight, 1, PixelFormat::RGBA_8888, usage);
mWriter->setLayerBuffer(0, bufferHandle.get(), -1);
@@ -360,8 +505,8 @@
std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, coloredSquare, BLUE);
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+ mDisplayHeight, mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
mWriter->validateDisplay();
@@ -392,15 +537,11 @@
ASSERT_NO_FATAL_FAILURE(
mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
- mComposerClient->getRaw()->getReadbackBufferAttributes(
- mPrimaryDisplay,
- [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
- mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
- tmpDataspace, tmpError);
- mPixelFormat = tmpPixelFormat;
- mDataspace = tmpDataspace;
- });
-
+ PixelFormat pixelFormat;
+ Dataspace dataspace;
+ Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &pixelFormat,
+ &dataspace);
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(pixelFormat, dataspace, error);
if (!mHasReadbackBuffer) {
std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
@@ -428,8 +569,8 @@
std::vector<std::shared_ptr<TestLayer>> layers = {layer};
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+ mDisplayHeight, mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(layers);
ASSERT_EQ(0, mReader->mErrors.size());
@@ -441,9 +582,8 @@
ASSERT_EQ(1, mReader->mCompositionChanges[0].second);
PixelFormat clientFormat = PixelFormat::RGBA_8888;
- uint64_t clientUsage = static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN |
- BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_CLIENT_TARGET);
+ uint32_t clientUsage = GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_OFTEN |
+ GRALLOC_USAGE_HW_FB;
Dataspace clientDataspace = ReadbackHelper::getDataspaceForColorMode(mode);
IComposerClient::Rect damage{0, 0, mDisplayWidth, mDisplayHeight};
@@ -510,15 +650,9 @@
ASSERT_NO_FATAL_FAILURE(
mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
- mComposerClient->getRaw()->getReadbackBufferAttributes(
- mPrimaryDisplay,
- [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
- mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
- tmpDataspace, tmpError);
- mPixelFormat = tmpPixelFormat;
- mDataspace = tmpDataspace;
- });
-
+ Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &mPixelFormat,
+ &mDataspace);
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(mPixelFormat, mDataspace, error);
if (!mHasReadbackBuffer) {
std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
@@ -531,8 +665,8 @@
ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
{0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, RED);
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+ mDisplayHeight, mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
auto deviceLayer = std::make_shared<TestBufferLayer>(
@@ -552,9 +686,8 @@
deviceLayer->write(mWriter);
PixelFormat clientFormat = PixelFormat::RGBA_8888;
- uint64_t clientUsage =
- static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_CLIENT_TARGET);
+ uint32_t clientUsage =
+ GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_FB;
Dataspace clientDataspace = ReadbackHelper::getDataspaceForColorMode(mode);
int32_t clientWidth = mDisplayWidth;
int32_t clientHeight = mDisplayHeight / 2;
@@ -633,15 +766,9 @@
ASSERT_NO_FATAL_FAILURE(
mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
- mComposerClient->getRaw()->getReadbackBufferAttributes(
- mPrimaryDisplay,
- [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
- mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
- tmpDataspace, tmpError);
- mPixelFormat = tmpPixelFormat;
- mDataspace = tmpDataspace;
- });
-
+ Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &mPixelFormat,
+ &mDataspace);
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(mPixelFormat, mDataspace, error);
if (!mHasReadbackBuffer) {
std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
@@ -665,8 +792,8 @@
std::vector<std::shared_ptr<TestLayer>> layers = {layer};
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+ mDisplayHeight, mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(layers);
@@ -718,15 +845,9 @@
ASSERT_NO_FATAL_FAILURE(
mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
- mComposerClient->getRaw()->getReadbackBufferAttributes(
- mPrimaryDisplay,
- [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
- mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
- tmpDataspace, tmpError);
- mPixelFormat = tmpPixelFormat;
- mDataspace = tmpDataspace;
- });
-
+ Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &mPixelFormat,
+ &mDataspace);
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(mPixelFormat, mDataspace, error);
if (!mHasReadbackBuffer) {
std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
@@ -742,8 +863,8 @@
std::vector<std::shared_ptr<TestLayer>> layers = {layer};
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+ mDisplayHeight, mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
@@ -779,15 +900,9 @@
ASSERT_NO_FATAL_FAILURE(
mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
- mComposerClient->getRaw()->getReadbackBufferAttributes(
- mPrimaryDisplay,
- [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
- mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
- tmpDataspace, tmpError);
- mPixelFormat = tmpPixelFormat;
- mDataspace = tmpDataspace;
- });
-
+ Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &mPixelFormat,
+ &mDataspace);
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(mPixelFormat, mDataspace, error);
if (!mHasReadbackBuffer) {
std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
@@ -819,8 +934,8 @@
// update expected colors to match crop
ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
{0, 0, mDisplayWidth, mDisplayHeight}, BLUE);
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+ mDisplayHeight, mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(layers);
ASSERT_EQ(0, mReader->mErrors.size());
@@ -850,15 +965,9 @@
ASSERT_NO_FATAL_FAILURE(
mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
- mComposerClient->getRaw()->getReadbackBufferAttributes(
- mPrimaryDisplay,
- [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
- mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
- tmpDataspace, tmpError);
- mPixelFormat = tmpPixelFormat;
- mDataspace = tmpDataspace;
- });
-
+ Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &mPixelFormat,
+ &mDataspace);
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(mPixelFormat, mDataspace, error);
if (!mHasReadbackBuffer) {
std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
@@ -886,8 +995,8 @@
ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, blueRect, BLUE);
ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+ mDisplayHeight, mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(layers);
@@ -1019,15 +1128,9 @@
ASSERT_NO_FATAL_FAILURE(
mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
- mComposerClient->getRaw()->getReadbackBufferAttributes(
- mPrimaryDisplay,
- [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
- mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
- tmpDataspace, tmpError);
- mPixelFormat = tmpPixelFormat;
- mDataspace = tmpDataspace;
- });
-
+ Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &mPixelFormat,
+ &mDataspace);
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(mPixelFormat, mDataspace, error);
if (!mHasReadbackBuffer) {
std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
@@ -1043,8 +1146,8 @@
setUpLayers(IComposerClient::BlendMode::NONE);
setExpectedColors(expectedColors);
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+ mDisplayHeight, mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(mLayers);
ASSERT_EQ(0, mReader->mErrors.size());
@@ -1077,15 +1180,9 @@
ASSERT_NO_FATAL_FAILURE(
mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
- mComposerClient->getRaw()->getReadbackBufferAttributes(
- mPrimaryDisplay,
- [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
- mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
- tmpDataspace, tmpError);
- mPixelFormat = tmpPixelFormat;
- mDataspace = tmpDataspace;
- });
-
+ Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &mPixelFormat,
+ &mDataspace);
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(mPixelFormat, mDataspace, error);
if (!mHasReadbackBuffer) {
std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
@@ -1102,8 +1199,8 @@
setUpLayers(IComposerClient::BlendMode::COVERAGE);
setExpectedColors(expectedColors);
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+ mDisplayHeight, mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(mLayers);
ASSERT_EQ(0, mReader->mErrors.size());
@@ -1130,15 +1227,9 @@
ASSERT_NO_FATAL_FAILURE(
mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
- mComposerClient->getRaw()->getReadbackBufferAttributes(
- mPrimaryDisplay,
- [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
- mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
- tmpDataspace, tmpError);
- mPixelFormat = tmpPixelFormat;
- mDataspace = tmpDataspace;
- });
-
+ Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &mPixelFormat,
+ &mDataspace);
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(mPixelFormat, mDataspace, error);
if (!mHasReadbackBuffer) {
std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
@@ -1153,8 +1244,8 @@
setUpLayers(IComposerClient::BlendMode::PREMULTIPLIED);
setExpectedColors(expectedColors);
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+ mDisplayHeight, mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(mLayers);
ASSERT_EQ(0, mReader->mErrors.size());
@@ -1222,22 +1313,16 @@
ASSERT_NO_FATAL_FAILURE(
mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
- mComposerClient->getRaw()->getReadbackBufferAttributes(
- mPrimaryDisplay,
- [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
- mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
- tmpDataspace, tmpError);
- mPixelFormat = tmpPixelFormat;
- mDataspace = tmpDataspace;
- });
-
+ Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &mPixelFormat,
+ &mDataspace);
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(mPixelFormat, mDataspace, error);
if (!mHasReadbackBuffer) {
std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
return;
}
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+ mDisplayHeight, mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
mLayer->setTransform(Transform::FLIP_H);
mLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
@@ -1277,22 +1362,16 @@
ASSERT_NO_FATAL_FAILURE(
mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
- mComposerClient->getRaw()->getReadbackBufferAttributes(
- mPrimaryDisplay,
- [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
- mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
- tmpDataspace, tmpError);
- mPixelFormat = tmpPixelFormat;
- mDataspace = tmpDataspace;
- });
-
+ Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &mPixelFormat,
+ &mDataspace);
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(mPixelFormat, mDataspace, error);
if (!mHasReadbackBuffer) {
std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
return;
}
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+ mDisplayHeight, mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
mLayer->setTransform(Transform::FLIP_V);
@@ -1332,22 +1411,16 @@
ASSERT_NO_FATAL_FAILURE(
mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
- mComposerClient->getRaw()->getReadbackBufferAttributes(
- mPrimaryDisplay,
- [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
- mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
- tmpDataspace, tmpError);
- mPixelFormat = tmpPixelFormat;
- mDataspace = tmpDataspace;
- });
-
+ Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &mPixelFormat,
+ &mDataspace);
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(mPixelFormat, mDataspace, error);
if (!mHasReadbackBuffer) {
std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
return;
}
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+ mDisplayHeight, mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
mLayer->setTransform(Transform::ROT_180);
diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
index 7e25a2e..f8fbb04 100644
--- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
+++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
@@ -23,6 +23,7 @@
#include <composer-vts/2.1/TestCommandReader.h>
#include <composer-vts/2.2/ComposerVts.h>
#include <gtest/gtest.h>
+#include <hardware/gralloc.h>
#include <hidl/GtestPrinter.h>
#include <hidl/ServiceManagement.h>
#include <mapper-vts/2.0/MapperVts.h>
@@ -35,7 +36,6 @@
namespace vts {
namespace {
-using common::V1_0::BufferUsage;
using common::V1_1::ColorMode;
using common::V1_1::Dataspace;
using common::V1_1::PixelFormat;
@@ -65,17 +65,13 @@
mComposerClient->setVsyncEnabled(mPrimaryDisplay, false);
mComposerCallback->setVsyncAllowed(false);
- mComposerClient->getRaw()->getReadbackBufferAttributes(
- mPrimaryDisplay,
- [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
- mHasReadbackBuffer = tmpError == Error::NONE;
- if (mHasReadbackBuffer) {
- mReadbackPixelFormat = tmpPixelFormat;
- mReadbackDataspace = tmpDataspace;
- ASSERT_LT(static_cast<PixelFormat>(0), mReadbackPixelFormat);
- ASSERT_NE(Dataspace::UNKNOWN, mReadbackDataspace);
- }
- });
+ Error error = mComposerClient->getReadbackBufferAttributes(
+ mPrimaryDisplay, &mReadbackPixelFormat, &mReadbackDataspace);
+ mHasReadbackBuffer = error == Error::NONE;
+ if (mHasReadbackBuffer) {
+ ASSERT_LT(static_cast<PixelFormat>(0), mReadbackPixelFormat);
+ ASSERT_NE(Dataspace::UNKNOWN, mReadbackDataspace);
+ }
mInvalidDisplayId = GetInvalidDisplayId();
}
@@ -153,10 +149,9 @@
}
NativeHandleWrapper allocate() {
- uint64_t usage =
- static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN);
return mGralloc->allocate(/*width*/ 64, /*height*/ 64, /*layerCount*/ 1,
- PixelFormat::RGBA_8888, usage);
+ PixelFormat::RGBA_8888,
+ GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_OFTEN);
}
void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); }
@@ -434,9 +429,7 @@
}
// BufferUsage::COMPOSER_OUTPUT is missing
- uint64_t usage =
- static_cast<uint64_t>(BufferUsage::COMPOSER_OVERLAY | BufferUsage::CPU_READ_OFTEN);
-
+ uint64_t usage = GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_SW_READ_OFTEN;
std::unique_ptr<Gralloc> gralloc;
std::unique_ptr<NativeHandleWrapper> buffer;
ASSERT_NO_FATAL_FAILURE(gralloc = std::make_unique<Gralloc>());
@@ -457,9 +450,7 @@
return;
}
- uint64_t usage =
- static_cast<uint64_t>(BufferUsage::COMPOSER_OVERLAY | BufferUsage::CPU_READ_OFTEN);
-
+ uint64_t usage = GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_SW_READ_OFTEN;
std::unique_ptr<Gralloc> gralloc;
std::unique_ptr<NativeHandleWrapper> buffer;
ASSERT_NO_FATAL_FAILURE(gralloc = std::make_unique<Gralloc>());
diff --git a/graphics/composer/aidl/vts/ReadbackVts.cpp b/graphics/composer/aidl/vts/ReadbackVts.cpp
index abb58e2..b59793f 100644
--- a/graphics/composer/aidl/vts/ReadbackVts.cpp
+++ b/graphics/composer/aidl/vts/ReadbackVts.cpp
@@ -20,6 +20,8 @@
#include "renderengine/ExternalTexture.h"
#include "renderengine/impl/ExternalTexture.h"
+using ::android::status_t;
+
namespace aidl::android::hardware::graphics::composer3::vts {
const std::vector<ColorMode> ReadbackHelper::colorModes = {ColorMode::SRGB, ColorMode::DISPLAY_P3};
@@ -27,6 +29,9 @@
common::Dataspace::DISPLAY_P3};
void TestLayer::write(ComposerClientWriter& writer) {
+ ::android::status_t status = ::android::OK;
+ ASSERT_EQ(::android::OK, status);
+
writer.setLayerDisplayFrame(mDisplay, mLayer, mDisplayFrame);
writer.setLayerSourceCrop(mDisplay, mLayer, mSourceCrop);
writer.setLayerZOrder(mDisplay, mLayer, mZOrder);
@@ -37,6 +42,40 @@
writer.setLayerBrightness(mDisplay, mLayer, mBrightness);
}
+bool ReadbackHelper::readbackSupported(const common::PixelFormat& pixelFormat,
+ const common::Dataspace& dataspace) {
+ // TODO: add support for RGBA_1010102
+ if (pixelFormat != common::PixelFormat::RGB_888 &&
+ pixelFormat != common::PixelFormat::RGBA_8888) {
+ return false;
+ }
+ if (std::find(dataspaces.begin(), dataspaces.end(), dataspace) == dataspaces.end()) {
+ return false;
+ }
+ return true;
+}
+
+void ReadbackHelper::createReadbackBuffer(ReadbackBufferAttributes readbackBufferAttributes,
+ const VtsDisplay& display,
+ sp<GraphicBuffer>* graphicBuffer) {
+ ASSERT_NE(nullptr, graphicBuffer);
+ if (!readbackSupported(readbackBufferAttributes.format, readbackBufferAttributes.dataspace)) {
+ *graphicBuffer = nullptr;
+ }
+ uint64_t usage =
+ static_cast<uint64_t>(static_cast<uint64_t>(common::BufferUsage::CPU_READ_OFTEN) |
+ static_cast<uint64_t>(common::BufferUsage::GPU_TEXTURE));
+
+ uint32_t layerCount = 1;
+ *graphicBuffer = sp<GraphicBuffer>::make(
+ static_cast<uint32_t>(display.getDisplayWidth()),
+ static_cast<uint32_t>(display.getDisplayHeight()),
+ static_cast<::android::PixelFormat>(readbackBufferAttributes.format), layerCount, usage,
+ "ReadbackBuffer");
+ ASSERT_NE(nullptr, *graphicBuffer);
+ ASSERT_EQ(::android::OK, (*graphicBuffer)->initCheck());
+}
+
std::string ReadbackHelper::getColorModeString(ColorMode mode) {
switch (mode) {
case ColorMode::SRGB:
@@ -103,11 +142,11 @@
return layerSettings;
}
-int32_t ReadbackHelper::GetBytesPerPixel(common::PixelFormat pixelFormat) {
+int32_t ReadbackHelper::GetBytesPerPixel(PixelFormat pixelFormat) {
switch (pixelFormat) {
- case common::PixelFormat::RGBA_8888:
+ case PixelFormat::RGBA_8888:
return 4;
- case common::PixelFormat::RGB_888:
+ case PixelFormat::RGB_888:
return 3;
default:
return -1;
@@ -116,136 +155,161 @@
void ReadbackHelper::fillBuffer(uint32_t width, uint32_t height, uint32_t stride, void* bufferData,
common::PixelFormat pixelFormat,
- std::vector<Color> desiredPixelColors) {
+ const std::vector<Color>& desiredColors) {
ASSERT_TRUE(pixelFormat == common::PixelFormat::RGB_888 ||
pixelFormat == common::PixelFormat::RGBA_8888);
int32_t bytesPerPixel = GetBytesPerPixel(pixelFormat);
ASSERT_NE(-1, bytesPerPixel);
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
- auto pixel = row * static_cast<int32_t>(width) + col;
- Color srcColor = desiredPixelColors[static_cast<size_t>(pixel)];
+ int pixel = row * static_cast<int32_t>(width) + col;
+ Color desiredColor = desiredColors[static_cast<size_t>(pixel)];
int offset = (row * static_cast<int32_t>(stride) + col) * bytesPerPixel;
uint8_t* pixelColor = (uint8_t*)bufferData + offset;
- pixelColor[0] = static_cast<uint8_t>(std::round(255.0f * srcColor.r));
- pixelColor[1] = static_cast<uint8_t>(std::round(255.0f * srcColor.g));
- pixelColor[2] = static_cast<uint8_t>(std::round(255.0f * srcColor.b));
+ pixelColor[0] = static_cast<uint8_t>(std::round(255.0f * desiredColor.r));
+ pixelColor[1] = static_cast<uint8_t>(std::round(255.0f * desiredColor.g));
+ pixelColor[2] = static_cast<uint8_t>(std::round(255.0f * desiredColor.b));
if (bytesPerPixel == 4) {
- pixelColor[3] = static_cast<uint8_t>(std::round(255.0f * srcColor.a));
+ pixelColor[3] = static_cast<uint8_t>(std::round(255.0f * desiredColor.a));
}
}
}
}
-void ReadbackHelper::clearColors(std::vector<Color>& expectedColors, int32_t width, int32_t height,
+void ReadbackHelper::clearColors(std::vector<Color>& colors, int32_t width, int32_t height,
int32_t displayWidth) {
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
int pixel = row * displayWidth + col;
- expectedColors[static_cast<size_t>(pixel)] = BLACK;
+ colors[static_cast<size_t>(pixel)] = BLACK;
}
}
}
-void ReadbackHelper::fillColorsArea(std::vector<Color>& expectedColors, int32_t stride, Rect area,
- Color color) {
+void ReadbackHelper::fillColorsArea(std::vector<Color>& colors, int32_t stride, Rect area,
+ Color desiredColor) {
for (int row = area.top; row < area.bottom; row++) {
for (int col = area.left; col < area.right; col++) {
int pixel = row * stride + col;
- expectedColors[static_cast<size_t>(pixel)] = color;
+ colors[static_cast<size_t>(pixel)] = desiredColor;
}
}
}
-bool ReadbackHelper::readbackSupported(const common::PixelFormat& pixelFormat,
- const common::Dataspace& dataspace) {
- if (pixelFormat != common::PixelFormat::RGB_888 &&
- pixelFormat != common::PixelFormat::RGBA_8888) {
- return false;
- }
- if (std::find(dataspaces.begin(), dataspaces.end(), dataspace) == dataspaces.end()) {
- return false;
- }
- return true;
+void ReadbackHelper::fillBufferAndGetFence(const sp<GraphicBuffer>& graphicBuffer,
+ Color desiredColor, int* fillFence) {
+ ASSERT_NE(nullptr, fillFence);
+ std::vector<Color> desiredColors(
+ static_cast<size_t>(graphicBuffer->getWidth() * graphicBuffer->getHeight()));
+ ::android::Rect bounds = graphicBuffer->getBounds();
+ fillColorsArea(desiredColors, static_cast<int32_t>(graphicBuffer->getWidth()),
+ {bounds.left, bounds.top, bounds.right, bounds.bottom}, desiredColor);
+ ASSERT_NO_FATAL_FAILURE(fillBufferAndGetFence(graphicBuffer, desiredColors, fillFence));
}
-void ReadbackHelper::compareColorBuffers(const std::vector<Color>& expectedColors, void* bufferData,
- const uint32_t stride, const uint32_t width,
- const uint32_t height, common::PixelFormat pixelFormat) {
- const int32_t bytesPerPixel = ReadbackHelper::GetBytesPerPixel(pixelFormat);
+void ReadbackHelper::fillBufferAndGetFence(const sp<GraphicBuffer>& graphicBuffer,
+ const std::vector<Color>& desiredColors,
+ int* fillFence) {
+ ASSERT_TRUE(graphicBuffer->getPixelFormat() == ::android::PIXEL_FORMAT_RGB_888 ||
+ graphicBuffer->getPixelFormat() == ::android::PIXEL_FORMAT_RGBA_8888);
+ void* bufData;
+ int32_t bytesPerPixel = -1;
+ int32_t bytesPerStride = -1;
+ status_t status =
+ graphicBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+ &bufData, &bytesPerPixel, &bytesPerStride);
+ ASSERT_EQ(::android::OK, status);
+
+ const uint32_t stride = (bytesPerPixel > 0 && bytesPerStride > 0)
+ ? static_cast<uint32_t>(bytesPerStride / bytesPerPixel)
+ : graphicBuffer->getStride();
+ ReadbackHelper::fillBuffer(
+ graphicBuffer->getWidth(), graphicBuffer->getHeight(), stride, bufData,
+ static_cast<common::PixelFormat>(graphicBuffer->getPixelFormat()), desiredColors);
+ status = graphicBuffer->unlockAsync(fillFence);
+ ASSERT_EQ(::android::OK, status);
+}
+
+void ReadbackHelper::compareColorToBuffer(Color expectedColor,
+ const sp<GraphicBuffer>& graphicBuffer,
+ const ndk::ScopedFileDescriptor& fence) {
+ std::vector<Color> expectedColors(
+ static_cast<size_t>(graphicBuffer->getWidth() * graphicBuffer->getHeight()));
+ ::android::Rect bounds = graphicBuffer->getBounds();
+ fillColorsArea(expectedColors, static_cast<int32_t>(graphicBuffer->getWidth()),
+ {bounds.left, bounds.top, bounds.right, bounds.bottom}, expectedColor);
+ compareColorsToBuffer(expectedColors, graphicBuffer, fence);
+}
+
+void ReadbackHelper::compareColorsToBuffer(const std::vector<Color>& expectedColors,
+ const sp<GraphicBuffer>& graphicBuffer,
+ const ndk::ScopedFileDescriptor& fence) {
+ ASSERT_TRUE(graphicBuffer->getPixelFormat() == ::android::PIXEL_FORMAT_RGB_888 ||
+ graphicBuffer->getPixelFormat() == ::android::PIXEL_FORMAT_RGBA_8888);
+
+ int bytesPerPixel = -1;
+ int bytesPerStride = -1;
+ void* bufData = nullptr;
+ status_t status = graphicBuffer->lockAsync(GRALLOC_USAGE_SW_READ_OFTEN, &bufData,
+ dup(fence.get()), &bytesPerPixel, &bytesPerStride);
+ ASSERT_EQ(::android::OK, status);
+
+ const uint32_t stride = (bytesPerPixel > 0 && bytesPerStride > 0)
+ ? static_cast<uint32_t>(bytesPerStride / bytesPerPixel)
+ : graphicBuffer->getStride();
+
+ if (bytesPerPixel == -1) {
+ bytesPerPixel = ReadbackHelper::GetBytesPerPixel(
+ static_cast<PixelFormat>(graphicBuffer->getPixelFormat()));
+ }
ASSERT_NE(-1, bytesPerPixel);
- for (int row = 0; row < height; row++) {
- for (int col = 0; col < width; col++) {
- auto pixel = row * static_cast<int32_t>(width) + col;
+ for (int row = 0; row < graphicBuffer->getHeight(); row++) {
+ for (int col = 0; col < graphicBuffer->getWidth(); col++) {
+ int pixel = row * static_cast<int32_t>(graphicBuffer->getWidth()) + col;
int offset = (row * static_cast<int32_t>(stride) + col) * bytesPerPixel;
- uint8_t* pixelColor = (uint8_t*)bufferData + offset;
+ uint8_t* pixelColor = (uint8_t*)bufData + offset;
const Color expectedColor = expectedColors[static_cast<size_t>(pixel)];
ASSERT_EQ(std::round(255.0f * expectedColor.r), pixelColor[0]);
ASSERT_EQ(std::round(255.0f * expectedColor.g), pixelColor[1]);
ASSERT_EQ(std::round(255.0f * expectedColor.b), pixelColor[2]);
}
}
+
+ status = graphicBuffer->unlock();
+ ASSERT_EQ(::android::OK, status);
}
ReadbackBuffer::ReadbackBuffer(int64_t display, const std::shared_ptr<VtsComposerClient>& client,
- int32_t width, int32_t height, common::PixelFormat pixelFormat,
- common::Dataspace dataspace)
+ int32_t width, int32_t height, common::PixelFormat pixelFormat)
: mComposerClient(client) {
mDisplay = display;
-
- mPixelFormat = pixelFormat;
- mDataspace = dataspace;
-
mWidth = static_cast<uint32_t>(width);
mHeight = static_cast<uint32_t>(height);
+ mPixelFormat = pixelFormat;
mLayerCount = 1;
mUsage = static_cast<uint64_t>(static_cast<uint64_t>(common::BufferUsage::CPU_READ_OFTEN) |
static_cast<uint64_t>(common::BufferUsage::GPU_TEXTURE));
-
- mAccessRegion.top = 0;
- mAccessRegion.left = 0;
- mAccessRegion.right = static_cast<int32_t>(width);
- mAccessRegion.bottom = static_cast<int32_t>(height);
-}
-
-::android::sp<::android::GraphicBuffer> ReadbackBuffer::allocateBuffer() {
- return ::android::sp<::android::GraphicBuffer>::make(
- mWidth, mHeight, static_cast<::android::PixelFormat>(mPixelFormat), mLayerCount, mUsage,
- "ReadbackBuffer");
}
void ReadbackBuffer::setReadbackBuffer() {
- mGraphicBuffer = allocateBuffer();
+ mGraphicBuffer = sp<GraphicBuffer>::make(mWidth, mHeight,
+ static_cast<::android::PixelFormat>(mPixelFormat),
+ mLayerCount, mUsage, "ReadbackBuffer");
ASSERT_NE(nullptr, mGraphicBuffer);
ASSERT_EQ(::android::OK, mGraphicBuffer->initCheck());
- const auto& bufferHandle = mGraphicBuffer->handle;
- ::ndk::ScopedFileDescriptor fence = ::ndk::ScopedFileDescriptor(-1);
- EXPECT_TRUE(mComposerClient->setReadbackBuffer(mDisplay, bufferHandle, fence).isOk());
+ ::ndk::ScopedFileDescriptor noFence = ::ndk::ScopedFileDescriptor(-1);
+ const auto& status =
+ mComposerClient->setReadbackBuffer(mDisplay, mGraphicBuffer->handle, noFence);
+ ASSERT_TRUE(status.isOk());
}
void ReadbackBuffer::checkReadbackBuffer(const std::vector<Color>& expectedColors) {
- ASSERT_NE(nullptr, mGraphicBuffer);
// lock buffer for reading
const auto& [fenceStatus, bufferFence] = mComposerClient->getReadbackBufferFence(mDisplay);
- EXPECT_TRUE(fenceStatus.isOk());
-
- int bytesPerPixel = -1;
- int bytesPerStride = -1;
- void* bufData = nullptr;
-
- auto status = mGraphicBuffer->lockAsync(mUsage, mAccessRegion, &bufData, dup(bufferFence.get()),
- &bytesPerPixel, &bytesPerStride);
- EXPECT_EQ(::android::OK, status);
- ASSERT_TRUE(mPixelFormat == PixelFormat::RGB_888 || mPixelFormat == PixelFormat::RGBA_8888);
- const uint32_t stride = (bytesPerPixel > 0 && bytesPerStride > 0)
- ? static_cast<uint32_t>(bytesPerStride / bytesPerPixel)
- : mGraphicBuffer->getStride();
- ReadbackHelper::compareColorBuffers(expectedColors, bufData, stride, mWidth, mHeight,
- mPixelFormat);
- status = mGraphicBuffer->unlock();
- EXPECT_EQ(::android::OK, status);
+ ASSERT_TRUE(fenceStatus.isOk());
+ ReadbackHelper::compareColorsToBuffer(expectedColors, mGraphicBuffer, bufferFence);
}
void TestColorLayer::write(ComposerClientWriter& writer) {
@@ -323,9 +387,8 @@
const uint32_t stride = (bytesPerPixel > 0 && bytesPerStride > 0)
? static_cast<uint32_t>(bytesPerStride / bytesPerPixel)
: mGraphicBuffer->getStride();
- EXPECT_EQ(::android::OK, status);
- ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(mWidth, mHeight, stride, bufData,
- mPixelFormat, expectedColors));
+ ASSERT_EQ(::android::OK, status);
+ ReadbackHelper::fillBuffer(mWidth, mHeight, stride, bufData, mPixelFormat, expectedColors);
const auto unlockStatus = mGraphicBuffer->unlockAsync(&mFillFence);
ASSERT_EQ(::android::OK, unlockStatus);
@@ -335,13 +398,13 @@
mGraphicBuffer = allocateBuffer();
ASSERT_NE(nullptr, mGraphicBuffer);
ASSERT_EQ(::android::OK, mGraphicBuffer->initCheck());
- ASSERT_NO_FATAL_FAILURE(fillBuffer(colors));
+ fillBuffer(colors);
}
-::android::sp<::android::GraphicBuffer> TestBufferLayer::allocateBuffer() {
- return ::android::sp<::android::GraphicBuffer>::make(
- mWidth, mHeight, static_cast<::android::PixelFormat>(mPixelFormat), mLayerCount, mUsage,
- "TestBufferLayer");
+sp<GraphicBuffer> TestBufferLayer::allocateBuffer() {
+ return sp<GraphicBuffer>::make(mWidth, mHeight,
+ static_cast<::android::PixelFormat>(mPixelFormat), mLayerCount,
+ mUsage, "TestBufferLayer");
}
void TestBufferLayer::setDataspace(common::Dataspace dataspace, ComposerClientWriter& writer) {
diff --git a/graphics/composer/aidl/vts/ReadbackVts.h b/graphics/composer/aidl/vts/ReadbackVts.h
index ee9f0d5..ecf0d52 100644
--- a/graphics/composer/aidl/vts/ReadbackVts.h
+++ b/graphics/composer/aidl/vts/ReadbackVts.h
@@ -33,6 +33,8 @@
using common::Dataspace;
using common::PixelFormat;
using IMapper2_1 = ::android::hardware::graphics::mapper::V2_1::IMapper;
+using ::android::GraphicBuffer;
+using ::android::sp;
static const Color BLACK = {0.0f, 0.0f, 0.0f, 1.0f};
static const Color RED = {1.0f, 0.0f, 0.0f, 1.0f};
@@ -146,7 +148,7 @@
protected:
Composition mComposition;
- ::android::sp<::android::GraphicBuffer> mGraphicBuffer;
+ sp<GraphicBuffer> mGraphicBuffer;
TestRenderEngine& mRenderEngine;
int32_t mFillFence;
uint32_t mWidth;
@@ -162,6 +164,11 @@
class ReadbackHelper {
public:
+ static bool readbackSupported(const PixelFormat& pixelFormat, const Dataspace& dataspace);
+
+ static void createReadbackBuffer(ReadbackBufferAttributes readbackBufferAttributes,
+ const VtsDisplay& display, sp<GraphicBuffer>* graphicBuffer);
+
static std::string getColorModeString(ColorMode mode);
static std::string getDataspaceString(Dataspace dataspace);
@@ -171,28 +178,36 @@
static int32_t GetBytesPerPixel(PixelFormat pixelFormat);
static void fillBuffer(uint32_t width, uint32_t height, uint32_t stride, void* bufferData,
- PixelFormat pixelFormat, std::vector<Color> desiredPixelColors);
+ PixelFormat pixelFormat, const std::vector<Color>& desriedColors);
- static void clearColors(std::vector<Color>& expectedColors, int32_t width, int32_t height,
+ static void clearColors(std::vector<Color>& colors, int32_t width, int32_t height,
int32_t displayWidth);
- static void fillColorsArea(std::vector<Color>& expectedColors, int32_t stride, Rect area,
- Color color);
+ static void fillColorsArea(std::vector<Color>& colors, int32_t stride, Rect area,
+ Color desiredColor);
- static bool readbackSupported(const PixelFormat& pixelFormat, const Dataspace& dataspace);
+ static void fillBufferAndGetFence(const sp<GraphicBuffer>& buffer, Color desiredColor,
+ int* fillFence);
+
+ static void fillBufferAndGetFence(const sp<GraphicBuffer>& buffer,
+ const std::vector<Color>& desiredColors, int* fillFence);
+
+ static void compareColorToBuffer(
+ Color expectedColor, const sp<GraphicBuffer>& graphicBuffer,
+ const ndk::ScopedFileDescriptor& fence = ::ndk::ScopedFileDescriptor(-1));
+
+ static void compareColorsToBuffer(
+ const std::vector<Color>& expectedColors, const sp<GraphicBuffer>& graphicBuffer,
+ const ndk::ScopedFileDescriptor& fence = ::ndk::ScopedFileDescriptor(-1));
static const std::vector<ColorMode> colorModes;
static const std::vector<Dataspace> dataspaces;
-
- static void compareColorBuffers(const std::vector<Color>& expectedColors, void* bufferData,
- const uint32_t stride, const uint32_t width,
- const uint32_t height, PixelFormat pixelFormat);
};
class ReadbackBuffer {
public:
ReadbackBuffer(int64_t display, const std::shared_ptr<VtsComposerClient>& client, int32_t width,
- int32_t height, common::PixelFormat pixelFormat, common::Dataspace dataspace);
+ int32_t height, common::PixelFormat pixelFormat);
void setReadbackBuffer();
@@ -201,18 +216,12 @@
protected:
uint32_t mWidth;
uint32_t mHeight;
+ PixelFormat mPixelFormat;
uint32_t mLayerCount;
uint32_t mUsage;
- PixelFormat mPixelFormat;
- Dataspace mDataspace;
int64_t mDisplay;
- ::android::sp<::android::GraphicBuffer> mGraphicBuffer;
+ sp<GraphicBuffer> mGraphicBuffer;
std::shared_ptr<VtsComposerClient> mComposerClient;
- ::android::Rect mAccessRegion;
- native_handle_t mBufferHandle;
-
- private:
- ::android::sp<::android::GraphicBuffer> allocateBuffer();
};
} // namespace aidl::android::hardware::graphics::composer3::vts
diff --git a/graphics/composer/aidl/vts/RenderEngineVts.cpp b/graphics/composer/aidl/vts/RenderEngineVts.cpp
index 66779c8..b84d0d0 100644
--- a/graphics/composer/aidl/vts/RenderEngineVts.cpp
+++ b/graphics/composer/aidl/vts/RenderEngineVts.cpp
@@ -76,18 +76,7 @@
}
void TestRenderEngine::checkColorBuffer(const std::vector<Color>& expectedColors) {
- void* bufferData;
- int32_t bytesPerPixel = -1;
- int32_t bytesPerStride = -1;
- ASSERT_EQ(0, mGraphicBuffer->lock(static_cast<uint32_t>(mGraphicBuffer->getUsage()),
- &bufferData, &bytesPerPixel, &bytesPerStride));
- const uint32_t stride = (bytesPerPixel > 0 && bytesPerStride > 0)
- ? static_cast<uint32_t>(bytesPerStride / bytesPerPixel)
- : mGraphicBuffer->getStride();
- ReadbackHelper::compareColorBuffers(expectedColors, bufferData, stride,
- mGraphicBuffer->getWidth(), mGraphicBuffer->getHeight(),
- mFormat);
- ASSERT_EQ(::android::OK, mGraphicBuffer->unlock());
+ ReadbackHelper::compareColorsToBuffer(expectedColors, mGraphicBuffer);
}
} // namespace aidl::android::hardware::graphics::composer3::vts
diff --git a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
index 6fa3392..93d9693 100644
--- a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
+++ b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
@@ -18,7 +18,6 @@
#include <aidl/Gtest.h>
#include <aidl/Vintf.h>
-#include <aidl/android/hardware/graphics/common/BufferUsage.h>
#include <aidl/android/hardware/graphics/composer3/IComposer.h>
#include <gtest/gtest.h>
#include <ui/DisplayId.h>
@@ -81,13 +80,11 @@
clientCompositionDisplay.physicalDisplay = Rect(getDisplayWidth(), getDisplayHeight());
clientCompositionDisplay.clip = clientCompositionDisplay.physicalDisplay;
- mTestRenderEngine->initGraphicBuffer(
- static_cast<uint32_t>(getDisplayWidth()), static_cast<uint32_t>(getDisplayHeight()),
- /*layerCount*/ 1U,
- static_cast<uint64_t>(
- static_cast<uint64_t>(common::BufferUsage::CPU_READ_OFTEN) |
- static_cast<uint64_t>(common::BufferUsage::CPU_WRITE_OFTEN) |
- static_cast<uint64_t>(common::BufferUsage::GPU_RENDER_TARGET)));
+ mTestRenderEngine->initGraphicBuffer(static_cast<uint32_t>(getDisplayWidth()),
+ static_cast<uint32_t>(getDisplayHeight()),
+ /*layerCount*/ 1U,
+ GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_SW_READ_OFTEN |
+ GRALLOC_USAGE_SW_WRITE_OFTEN);
mTestRenderEngine->setDisplaySettings(clientCompositionDisplay);
}
@@ -115,18 +112,21 @@
ASSERT_EQ(status.getServiceSpecificError(), serviceSpecificError);
}
- std::pair<bool, ::android::sp<::android::GraphicBuffer>> allocateBuffer(uint32_t usage) {
- const auto width = static_cast<uint32_t>(getDisplayWidth());
- const auto height = static_cast<uint32_t>(getDisplayHeight());
-
- const auto& graphicBuffer = ::android::sp<::android::GraphicBuffer>::make(
- width, height, ::android::PIXEL_FORMAT_RGBA_8888,
- /*layerCount*/ 1u, usage, "VtsHalGraphicsComposer3_ReadbackTest");
+ sp<GraphicBuffer> allocateBuffer(uint32_t width, uint32_t height, uint64_t usage) {
+ sp<GraphicBuffer> graphicBuffer =
+ sp<GraphicBuffer>::make(width, height, ::android::PIXEL_FORMAT_RGBA_8888,
+ /*layerCount*/ 1u, static_cast<uint32_t>(usage),
+ "VtsHalGraphicsComposer3_ReadbackTest");
if (graphicBuffer && ::android::OK == graphicBuffer->initCheck()) {
- return {true, graphicBuffer};
+ return graphicBuffer;
}
- return {false, graphicBuffer};
+ return nullptr;
+ }
+
+ sp<GraphicBuffer> allocateBuffer(uint64_t usage) {
+ return allocateBuffer(static_cast<uint32_t>(getDisplayWidth()),
+ static_cast<uint32_t>(getDisplayHeight()), usage);
}
uint64_t getStableDisplayId(int64_t display) {
@@ -293,7 +293,7 @@
ReadbackHelper::fillColorsArea(expectedColors, getDisplayWidth(), coloredSquare, BLUE);
ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
- getDisplayHeight(), mPixelFormat, mDataspace);
+ getDisplayHeight(), mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(layers);
@@ -332,7 +332,7 @@
}
ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
- getDisplayHeight(), mPixelFormat, mDataspace);
+ getDisplayHeight(), mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
std::vector<Color> expectedColors(
static_cast<size_t>(getDisplayWidth() * getDisplayHeight()));
@@ -378,6 +378,143 @@
}
}
+TEST_P(GraphicsCompositionTest, SetLayerBufferWithSlotsToClear) {
+ const auto& [status, readbackBufferAttributes] =
+ mComposerClient->getReadbackBufferAttributes(getPrimaryDisplayId());
+ if (!status.isOk()) {
+ GTEST_SUCCEED() << "Readback not supported";
+ return;
+ }
+
+ sp<GraphicBuffer> readbackBuffer;
+ ASSERT_NO_FATAL_FAILURE(ReadbackHelper::createReadbackBuffer(
+ readbackBufferAttributes, getPrimaryDisplay(), &readbackBuffer));
+ if (readbackBuffer == nullptr) {
+ GTEST_SUCCEED() << "Unsupported readback buffer attributes";
+ return;
+ }
+ // no fence needed for the readback buffer
+ ScopedFileDescriptor noFence(-1);
+
+ sp<GraphicBuffer> clearSlotBuffer = allocateBuffer(1u, 1u, GRALLOC_USAGE_HW_COMPOSER);
+ ASSERT_NE(nullptr, clearSlotBuffer);
+
+ // red buffer
+ uint64_t usage = GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_OFTEN;
+ sp<GraphicBuffer> redBuffer = allocateBuffer(usage);
+ ASSERT_NE(nullptr, redBuffer);
+ int redFence;
+ ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBufferAndGetFence(redBuffer, RED, &redFence));
+
+ // blue buffer
+ sp<GraphicBuffer> blueBuffer = allocateBuffer(usage);
+ ASSERT_NE(nullptr, blueBuffer);
+ int blueFence;
+ ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBufferAndGetFence(blueBuffer, BLUE, &blueFence));
+
+ // layer defaults
+ common::Rect rectFullDisplay = {0, 0, getDisplayWidth(), getDisplayHeight()};
+ int64_t display = getPrimaryDisplayId();
+ auto [layerStatus, layer] = mComposerClient->createLayer(getPrimaryDisplayId(), 3);
+ ASSERT_TRUE(layerStatus.isOk());
+ mWriter->setLayerDisplayFrame(display, layer, rectFullDisplay);
+ mWriter->setLayerCompositionType(display, layer, Composition::DEVICE);
+
+ // set the layer to the blue buffer
+ // should be blue
+ {
+ auto status = mComposerClient->setReadbackBuffer(display, readbackBuffer->handle, noFence);
+ ASSERT_TRUE(status.isOk());
+ mWriter->setLayerBuffer(display, layer, /*slot*/ 0, blueBuffer->handle, blueFence);
+ mWriter->validateDisplay(display, ComposerClientWriter::kNoTimestamp);
+ execute();
+ ASSERT_TRUE(mReader.takeChangedCompositionTypes(display).empty());
+ ASSERT_TRUE(mReader.takeErrors().empty());
+ mWriter->presentDisplay(display);
+ execute();
+ auto [fenceStatus, fence] = mComposerClient->getReadbackBufferFence(display);
+ ASSERT_TRUE(fenceStatus.isOk());
+ ReadbackHelper::compareColorToBuffer(BLUE, readbackBuffer, fence);
+ }
+
+ // change the layer to the red buffer
+ // should be red
+ {
+ auto status = mComposerClient->setReadbackBuffer(display, readbackBuffer->handle, noFence);
+ ASSERT_TRUE(status.isOk());
+ mWriter->setLayerBuffer(display, layer, /*slot*/ 1, redBuffer->handle, redFence);
+ mWriter->validateDisplay(display, ComposerClientWriter::kNoTimestamp);
+ execute();
+ ASSERT_TRUE(mReader.takeChangedCompositionTypes(display).empty());
+ ASSERT_TRUE(mReader.takeErrors().empty());
+ mWriter->presentDisplay(display);
+ execute();
+ auto [fenceStatus, fence] = mComposerClient->getReadbackBufferFence(display);
+ ASSERT_TRUE(fenceStatus.isOk());
+ ReadbackHelper::compareColorToBuffer(RED, readbackBuffer, fence);
+ }
+
+ // clear the slot for the blue buffer
+ // should still be red
+ {
+ auto status = mComposerClient->setReadbackBuffer(display, readbackBuffer->handle, noFence);
+ ASSERT_TRUE(status.isOk());
+ mWriter->setLayerBufferWithNewCommand(display, layer, /*slot*/ 0, clearSlotBuffer->handle,
+ /*fence*/ -1);
+ mWriter->validateDisplay(display, ComposerClientWriter::kNoTimestamp);
+ execute();
+ ASSERT_TRUE(mReader.takeChangedCompositionTypes(display).empty());
+ ASSERT_TRUE(mReader.takeErrors().empty());
+ mWriter->presentDisplay(display);
+ execute();
+ auto [fenceStatus, fence] = mComposerClient->getReadbackBufferFence(display);
+ ASSERT_TRUE(fenceStatus.isOk());
+ ReadbackHelper::compareColorToBuffer(RED, readbackBuffer, fence);
+ }
+
+ // clear the slot for the red buffer, and set the buffer with the same slot to the blue buffer
+ // should be blue
+ {
+ auto status = mComposerClient->setReadbackBuffer(display, readbackBuffer->handle, noFence);
+ ASSERT_TRUE(status.isOk());
+ mWriter->setLayerBufferWithNewCommand(display, layer, /*slot*/ 1, clearSlotBuffer->handle,
+ /*fence*/ -1);
+ mWriter->setLayerBuffer(display, layer, /*slot*/ 1, blueBuffer->handle, blueFence);
+ mWriter->validateDisplay(display, ComposerClientWriter::kNoTimestamp);
+ execute();
+ ASSERT_TRUE(mReader.takeChangedCompositionTypes(display).empty());
+ ASSERT_TRUE(mReader.takeErrors().empty());
+ mWriter->presentDisplay(display);
+ execute();
+ auto [fenceStatus, fence] = mComposerClient->getReadbackBufferFence(display);
+ ASSERT_TRUE(fenceStatus.isOk());
+ ReadbackHelper::compareColorToBuffer(BLUE, readbackBuffer, fence);
+ }
+
+ // clear the slot for the now-blue buffer
+ // should be black (no buffer)
+ // TODO(b/262037933) Ensure we never clear the active buffer's slot with the placeholder buffer
+ // by setting the layer to the color black
+ {
+ auto status = mComposerClient->setReadbackBuffer(display, readbackBuffer->handle, noFence);
+ ASSERT_TRUE(status.isOk());
+ mWriter->setLayerBufferWithNewCommand(display, layer, /*slot*/ 1, clearSlotBuffer->handle,
+ /*fence*/ -1);
+ mWriter->validateDisplay(display, ComposerClientWriter::kNoTimestamp);
+ execute();
+ if (!mReader.takeChangedCompositionTypes(display).empty()) {
+ GTEST_SUCCEED();
+ return;
+ }
+ ASSERT_TRUE(mReader.takeErrors().empty());
+ mWriter->presentDisplay(display);
+ execute();
+ auto [fenceStatus, fence] = mComposerClient->getReadbackBufferFence(display);
+ ASSERT_TRUE(fenceStatus.isOk());
+ ReadbackHelper::compareColorToBuffer(BLACK, readbackBuffer, fence);
+ }
+}
+
TEST_P(GraphicsCompositionTest, SetLayerBufferNoEffect) {
for (ColorMode mode : mTestColorModes) {
EXPECT_TRUE(mComposerClient
@@ -399,10 +536,9 @@
layer->write(*mWriter);
// This following buffer call should have no effect
- const auto usage = static_cast<uint32_t>(common::BufferUsage::CPU_WRITE_OFTEN) |
- static_cast<uint32_t>(common::BufferUsage::CPU_READ_OFTEN);
- const auto& [graphicBufferStatus, graphicBuffer] = allocateBuffer(usage);
- ASSERT_TRUE(graphicBufferStatus);
+ uint64_t usage = GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_OFTEN;
+ sp<GraphicBuffer> graphicBuffer = allocateBuffer(usage);
+ ASSERT_NE(nullptr, graphicBuffer);
const auto& buffer = graphicBuffer->handle;
mWriter->setLayerBuffer(getPrimaryDisplayId(), layer->getLayer(), /*slot*/ 0, buffer,
/*acquireFence*/ -1);
@@ -413,7 +549,7 @@
ReadbackHelper::fillColorsArea(expectedColors, getDisplayWidth(), coloredSquare, BLUE);
ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
- getDisplayHeight(), mPixelFormat, mDataspace);
+ getDisplayHeight(), mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
@@ -441,7 +577,7 @@
}
ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
- getDisplayHeight(), mPixelFormat, mDataspace);
+ getDisplayHeight(), mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
}
@@ -454,10 +590,9 @@
return;
}
- const auto usage = static_cast<uint32_t>(common::BufferUsage::CPU_WRITE_OFTEN) |
- static_cast<uint32_t>(common::BufferUsage::CPU_READ_OFTEN);
- const auto& [graphicBufferStatus, graphicBuffer] = allocateBuffer(usage);
- ASSERT_TRUE(graphicBufferStatus);
+ uint64_t usage = GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_OFTEN;
+ sp<GraphicBuffer> graphicBuffer = allocateBuffer(usage);
+ ASSERT_NE(nullptr, graphicBuffer);
const auto& bufferHandle = graphicBuffer->handle;
::ndk::ScopedFileDescriptor fence = ::ndk::ScopedFileDescriptor(-1);
@@ -539,7 +674,7 @@
std::vector<std::shared_ptr<TestLayer>> layers = {layer};
ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
- getDisplayHeight(), mPixelFormat, mDataspace);
+ getDisplayHeight(), mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(layers);
ASSERT_TRUE(mReader.takeErrors().empty());
@@ -552,16 +687,14 @@
ASSERT_EQ(Composition::CLIENT, changedCompositionTypes[0].composition);
PixelFormat clientFormat = PixelFormat::RGBA_8888;
- auto clientUsage = static_cast<uint32_t>(
- static_cast<uint32_t>(common::BufferUsage::CPU_READ_OFTEN) |
- static_cast<uint32_t>(common::BufferUsage::CPU_WRITE_OFTEN) |
- static_cast<uint32_t>(common::BufferUsage::COMPOSER_CLIENT_TARGET));
+ auto clientUsage = GRALLOC_USAGE_HW_FB | GRALLOC_USAGE_SW_READ_OFTEN |
+ GRALLOC_USAGE_SW_WRITE_OFTEN;
Dataspace clientDataspace = ReadbackHelper::getDataspaceForColorMode(mode);
common::Rect damage{0, 0, getDisplayWidth(), getDisplayHeight()};
// create client target buffer
- const auto& [graphicBufferStatus, graphicBuffer] = allocateBuffer(clientUsage);
- ASSERT_TRUE(graphicBufferStatus);
+ sp<GraphicBuffer> graphicBuffer = allocateBuffer(clientUsage);
+ ASSERT_NE(nullptr, graphicBuffer);
const auto& buffer = graphicBuffer->handle;
void* clientBufData;
const auto stride = static_cast<uint32_t>(graphicBuffer->stride);
@@ -618,7 +751,7 @@
{0, getDisplayHeight() / 2, getDisplayWidth(), getDisplayHeight()}, RED);
ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
- getDisplayHeight(), mPixelFormat, mDataspace);
+ getDisplayHeight(), mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
auto deviceLayer = std::make_shared<TestBufferLayer>(
@@ -637,10 +770,8 @@
deviceLayer->write(*mWriter);
PixelFormat clientFormat = PixelFormat::RGBA_8888;
- auto clientUsage = static_cast<uint32_t>(
- static_cast<uint64_t>(common::BufferUsage::CPU_READ_OFTEN) |
- static_cast<uint32_t>(common::BufferUsage::CPU_WRITE_OFTEN) |
- static_cast<uint32_t>(common::BufferUsage::COMPOSER_CLIENT_TARGET));
+ auto clientUsage =
+ GRALLOC_USAGE_HW_FB | GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN;
Dataspace clientDataspace = ReadbackHelper::getDataspaceForColorMode(mode);
int32_t clientWidth = getDisplayWidth();
int32_t clientHeight = getDisplayHeight() / 2;
@@ -662,8 +793,8 @@
}
// create client target buffer
ASSERT_EQ(Composition::CLIENT, changedCompositionTypes[0].composition);
- const auto& [graphicBufferStatus, graphicBuffer] = allocateBuffer(clientUsage);
- ASSERT_TRUE(graphicBufferStatus);
+ sp<GraphicBuffer> graphicBuffer = allocateBuffer(clientUsage);
+ ASSERT_NE(nullptr, graphicBuffer);
const auto& buffer = graphicBuffer->handle;
void* clientBufData;
@@ -725,7 +856,7 @@
std::vector<std::shared_ptr<TestLayer>> layers = {layer};
ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
- getDisplayHeight(), mPixelFormat, mDataspace);
+ getDisplayHeight(), mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(layers);
@@ -793,7 +924,7 @@
std::vector<std::shared_ptr<TestLayer>> layers = {layer};
ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
- getDisplayHeight(), mPixelFormat, mDataspace);
+ getDisplayHeight(), mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
@@ -859,7 +990,7 @@
ReadbackHelper::fillColorsArea(expectedColors, getDisplayWidth(),
{0, 0, getDisplayWidth(), getDisplayHeight()}, BLUE);
ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
- getDisplayHeight(), mPixelFormat, mDataspace);
+ getDisplayHeight(), mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(layers);
ASSERT_TRUE(mReader.takeErrors().empty());
@@ -916,7 +1047,7 @@
ReadbackHelper::fillColorsArea(expectedColors, getDisplayWidth(), redRect, RED);
ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
- getDisplayHeight(), mPixelFormat, mDataspace);
+ getDisplayHeight(), mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(layers);
@@ -1026,7 +1157,7 @@
ReadbackHelper::fillColorsArea(expectedColors, getDisplayWidth(), dimmerRedRect, DIM_RED);
ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
- getDisplayHeight(), mPixelFormat, mDataspace);
+ getDisplayHeight(), mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(layers);
@@ -1162,7 +1293,7 @@
setExpectedColors(expectedColors);
ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
- getDisplayHeight(), mPixelFormat, mDataspace);
+ getDisplayHeight(), mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(mLayers);
ASSERT_TRUE(mReader.takeErrors().empty());
@@ -1207,7 +1338,7 @@
setExpectedColors(expectedColors);
ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
- getDisplayHeight(), mPixelFormat, mDataspace);
+ getDisplayHeight(), mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(mLayers);
ASSERT_TRUE(mReader.takeErrors().empty());
@@ -1247,7 +1378,7 @@
setExpectedColors(expectedColors);
ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
- getDisplayHeight(), mPixelFormat, mDataspace);
+ getDisplayHeight(), mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(mLayers);
ASSERT_TRUE(mReader.takeErrors().empty());
@@ -1321,7 +1452,7 @@
return;
}
ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
- getDisplayHeight(), mPixelFormat, mDataspace);
+ getDisplayHeight(), mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
mLayer->setTransform(Transform::FLIP_H);
mLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), *mWriter);
@@ -1366,7 +1497,7 @@
return;
}
ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
- getDisplayHeight(), mPixelFormat, mDataspace);
+ getDisplayHeight(), mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
mLayer->setTransform(Transform::FLIP_V);
@@ -1411,7 +1542,7 @@
return;
}
ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
- getDisplayHeight(), mPixelFormat, mDataspace);
+ getDisplayHeight(), mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
mLayer->setTransform(Transform::ROT_180);
diff --git a/identity/aidl/Android.bp b/identity/aidl/Android.bp
index 2090473..6a25e62 100644
--- a/identity/aidl/Android.bp
+++ b/identity/aidl/Android.bp
@@ -18,7 +18,7 @@
"android.hardware.security.rkp-V3",
],
stability: "vintf",
- frozen: true,
+ frozen: false,
backend: {
java: {
platform_apis: true,
@@ -67,20 +67,20 @@
cc_defaults {
name: "identity_use_latest_hal_aidl_ndk_static",
static_libs: [
- "android.hardware.identity-V4-ndk",
+ "android.hardware.identity-V5-ndk",
],
}
cc_defaults {
name: "identity_use_latest_hal_aidl_ndk_shared",
shared_libs: [
- "android.hardware.identity-V4-ndk",
+ "android.hardware.identity-V5-ndk",
],
}
cc_defaults {
name: "identity_use_latest_hal_aidl_cpp_static",
static_libs: [
- "android.hardware.identity-V4-cpp",
+ "android.hardware.identity-V5-cpp",
],
}
diff --git a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredential.aidl b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredential.aidl
index 5065641..4f2fe0b 100644
--- a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredential.aidl
+++ b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredential.aidl
@@ -51,4 +51,5 @@
byte[] deleteCredentialWithChallenge(in byte[] challenge);
byte[] proveOwnership(in byte[] challenge);
android.hardware.identity.IWritableIdentityCredential updateCredential();
+ @SuppressWarnings(value={"out-array"}) void finishRetrievalWithSignature(out byte[] mac, out byte[] deviceNameSpaces, out byte[] ecdsaSignature);
}
diff --git a/identity/aidl/android/hardware/identity/IIdentityCredential.aidl b/identity/aidl/android/hardware/identity/IIdentityCredential.aidl
index 82b0a83..abdb00b 100644
--- a/identity/aidl/android/hardware/identity/IIdentityCredential.aidl
+++ b/identity/aidl/android/hardware/identity/IIdentityCredential.aidl
@@ -194,7 +194,8 @@
* is permissible for this to be empty in which case the readerSignature parameter
* must also be empty. If this is not the case, the call fails with STATUS_FAILED.
*
- * If the SessionTranscript CBOR is not empty, the X and Y coordinates of the public
+ * If mdoc session encryption is used (e.g. createEphemeralKeyPair() has been called)
+ * and the SessionTranscript CBOR is not empty, the X and Y coordinates of the public
* part of the key-pair previously generated by createEphemeralKeyPair() must appear
* somewhere in the bytes of the CBOR. Each of these coordinates must appear encoded
* with the most significant bits first and use the exact amount of bits indicated by
@@ -239,8 +240,8 @@
* and remove the corresponding requests from the counts.
*/
void startRetrieval(in SecureAccessControlProfile[] accessControlProfiles,
- in HardwareAuthToken authToken, in byte[] itemsRequest, in byte[] signingKeyBlob,
- in byte[] sessionTranscript, in byte[] readerSignature, in int[] requestCounts);
+ in HardwareAuthToken authToken, in byte[] itemsRequest, in byte[] signingKeyBlob,
+ in byte[] sessionTranscript, in byte[] readerSignature, in int[] requestCounts);
/**
* Starts retrieving an entry, subject to access control requirements. Entries must be
@@ -271,8 +272,8 @@
* is given and this profile wasn't passed to startRetrieval() this call fails
* with STATUS_INVALID_DATA.
*/
- void startRetrieveEntryValue(in @utf8InCpp String nameSpace, in @utf8InCpp String name,
- in int entrySize, in int[] accessControlProfileIds);
+ void startRetrieveEntryValue(in @utf8InCpp String nameSpace,
+ in @utf8InCpp String name, in int entrySize, in int[] accessControlProfileIds);
/**
* Retrieves an entry value, or part of one, if the entry value is larger than gcmChunkSize.
@@ -293,11 +294,13 @@
* returned data.
*
* If signingKeyBlob or the sessionTranscript parameter passed to startRetrieval() is
- * empty then the returned MAC will be empty.
+ * empty or if mdoc session encryption is not being used (e.g. if createEphemeralKeyPair()
+ * was not called) then the returned MAC will be empty.
*
- * @param out mac is empty if signingKeyBlob or the sessionTranscript passed to
- * startRetrieval() is empty. Otherwise it is a COSE_Mac0 with empty payload
- * and the detached content is set to DeviceAuthenticationBytes as defined below.
+ * @param out mac is empty if signingKeyBlob, or the sessionTranscript passed to
+ * startRetrieval() is empty, or if mdoc session encryption is not being used (e.g. if
+ * createEphemeralKeyPair() was not called). Otherwise it is a COSE_Mac0 with empty
+ * payload and the detached content is set to DeviceAuthenticationBytes as defined below.
* This code is produced by using the key agreement and key derivation function
* from the ciphersuite with the authentication private key and the reader
* ephemeral public key to compute a shared message authentication code (MAC)
@@ -407,13 +410,13 @@
*/
void setRequestedNamespaces(in RequestNamespace[] requestNamespaces);
- /**
- * Sets the VerificationToken. This method must be called before startRetrieval() is
- * called. This token uses the same challenge as returned by createAuthChallenge().
- *
- * @param verificationToken
- * The verification token. This token is only valid if the timestamp field is non-zero.
- */
+ /**
+ * Sets the VerificationToken. This method must be called before startRetrieval() is
+ * called. This token uses the same challenge as returned by createAuthChallenge().
+ *
+ * @param verificationToken
+ * The verification token. This token is only valid if the timestamp field is non-zero.
+ */
void setVerificationToken(in VerificationToken verificationToken);
/**
@@ -485,4 +488,20 @@
* @return an IWritableIdentityCredential
*/
IWritableIdentityCredential updateCredential();
+
+ /**
+ * Like finishRetrieval() but also returns an ECDSA signature in addition to the MAC.
+ *
+ * See section 9.1.3.6 of ISO/IEC 18013-5:2021 for details of how the signature is calculated.
+ *
+ * Unlike MACing, an ECDSA signature will be returned even if mdoc session encryption isn't
+ * being used.
+ *
+ * This method was introduced in API version 5.
+ *
+ * @param ecdsaSignature a COSE_Sign1 signature described above.
+ */
+ @SuppressWarnings(value={"out-array"})
+ void finishRetrievalWithSignature(
+ out byte[] mac, out byte[] deviceNameSpaces, out byte[] ecdsaSignature);
}
diff --git a/identity/aidl/android/hardware/identity/IPresentationSession.aidl b/identity/aidl/android/hardware/identity/IPresentationSession.aidl
index b0449f0..0a06740 100644
--- a/identity/aidl/android/hardware/identity/IPresentationSession.aidl
+++ b/identity/aidl/android/hardware/identity/IPresentationSession.aidl
@@ -70,6 +70,17 @@
*
* This can be empty but if it's non-empty it must be valid CBOR.
*
+ * If mdoc session encryption is used (e.g. getEphemeralKeyPair() has been called)
+ * and the SessionTranscript CBOR is not empty, the X and Y coordinates of the public
+ * part of the key-pair previously generated by createEphemeralKeyPair() must appear
+ * somewhere in the bytes of the CBOR. Each of these coordinates must appear encoded
+ * with the most significant bits first and use the exact amount of bits indicated by
+ * the key size of the ephemeral keys. For example, if the ephemeral key is using the
+ * P-256 curve then the 32 bytes for the X coordinate encoded with the most significant
+ * bits first must appear somewhere in the CBOR and ditto for the 32 bytes for the Y
+ * coordinate. If this is not satisfied, the call fails with
+ * STATUS_EPHEMERAL_PUBLIC_KEY_NOT_FOUND.
+ *
* This method may only be called once per instance. If called more than once, STATUS_FAILED
* must be returned.
*
diff --git a/identity/aidl/default/FakeSecureHardwareProxy.cpp b/identity/aidl/default/FakeSecureHardwareProxy.cpp
index 9b9a749..8551ab7 100644
--- a/identity/aidl/default/FakeSecureHardwareProxy.cpp
+++ b/identity/aidl/default/FakeSecureHardwareProxy.cpp
@@ -596,10 +596,10 @@
return eicPresentationStartRetrieveEntries(&ctx_);
}
-bool FakeSecureHardwarePresentationProxy::calcMacKey(
+bool FakeSecureHardwarePresentationProxy::prepareDeviceAuthentication(
const vector<uint8_t>& sessionTranscript, const vector<uint8_t>& readerEphemeralPublicKey,
const vector<uint8_t>& signingKeyBlob, const string& docType,
- unsigned int numNamespacesWithValues, size_t expectedProofOfProvisioningSize) {
+ unsigned int numNamespacesWithValues, size_t expectedDeviceNamespacesSize) {
if (!validateId(__func__)) {
return false;
}
@@ -608,10 +608,10 @@
eicDebug("Unexpected size %zd of signingKeyBlob, expected 60", signingKeyBlob.size());
return false;
}
- return eicPresentationCalcMacKey(&ctx_, sessionTranscript.data(), sessionTranscript.size(),
- readerEphemeralPublicKey.data(), signingKeyBlob.data(),
- docType.c_str(), docType.size(), numNamespacesWithValues,
- expectedProofOfProvisioningSize);
+ return eicPresentationPrepareDeviceAuthentication(
+ &ctx_, sessionTranscript.data(), sessionTranscript.size(),
+ readerEphemeralPublicKey.data(), readerEphemeralPublicKey.size(), signingKeyBlob.data(),
+ docType.c_str(), docType.size(), numNamespacesWithValues, expectedDeviceNamespacesSize);
}
AccessCheckResult FakeSecureHardwarePresentationProxy::startRetrieveEntryValue(
@@ -673,6 +673,25 @@
return content;
}
+optional<pair<vector<uint8_t>, vector<uint8_t>>>
+FakeSecureHardwarePresentationProxy::finishRetrievalWithSignature() {
+ if (!validateId(__func__)) {
+ return std::nullopt;
+ }
+
+ vector<uint8_t> mac(32);
+ size_t macSize = 32;
+ vector<uint8_t> ecdsaSignature(EIC_ECDSA_P256_SIGNATURE_SIZE);
+ size_t ecdsaSignatureSize = EIC_ECDSA_P256_SIGNATURE_SIZE;
+ if (!eicPresentationFinishRetrievalWithSignature(&ctx_, mac.data(), &macSize,
+ ecdsaSignature.data(), &ecdsaSignatureSize)) {
+ return std::nullopt;
+ }
+ mac.resize(macSize);
+ ecdsaSignature.resize(ecdsaSignatureSize);
+ return std::make_pair(mac, ecdsaSignature);
+}
+
optional<vector<uint8_t>> FakeSecureHardwarePresentationProxy::finishRetrieval() {
if (!validateId(__func__)) {
return std::nullopt;
diff --git a/identity/aidl/default/FakeSecureHardwareProxy.h b/identity/aidl/default/FakeSecureHardwareProxy.h
index 2512074..b56ab93 100644
--- a/identity/aidl/default/FakeSecureHardwareProxy.h
+++ b/identity/aidl/default/FakeSecureHardwareProxy.h
@@ -175,11 +175,11 @@
const vector<uint8_t>& requestMessage, int coseSignAlg,
const vector<uint8_t>& readerSignatureOfToBeSigned) override;
- bool calcMacKey(const vector<uint8_t>& sessionTranscript,
- const vector<uint8_t>& readerEphemeralPublicKey,
- const vector<uint8_t>& signingKeyBlob, const string& docType,
- unsigned int numNamespacesWithValues,
- size_t expectedProofOfProvisioningSize) override;
+ bool prepareDeviceAuthentication(const vector<uint8_t>& sessionTranscript,
+ const vector<uint8_t>& readerEphemeralPublicKey,
+ const vector<uint8_t>& signingKeyBlob, const string& docType,
+ unsigned int numNamespacesWithValues,
+ size_t expectedDeviceNamespacesSize) override;
AccessCheckResult startRetrieveEntryValue(
const string& nameSpace, const string& name, unsigned int newNamespaceNumEntries,
@@ -191,6 +191,8 @@
optional<vector<uint8_t>> finishRetrieval() override;
+ optional<pair<vector<uint8_t>, vector<uint8_t>>> finishRetrievalWithSignature() override;
+
optional<vector<uint8_t>> deleteCredential(const string& docType,
const vector<uint8_t>& challenge,
bool includeChallenge,
diff --git a/identity/aidl/default/common/IdentityCredential.cpp b/identity/aidl/default/common/IdentityCredential.cpp
index ff80752..4c3b7b2 100644
--- a/identity/aidl/default/common/IdentityCredential.cpp
+++ b/identity/aidl/default/common/IdentityCredential.cpp
@@ -457,17 +457,16 @@
}
if (session_) {
- // If presenting in a session, the TA has already done this check.
-
+ // If presenting in a session, the TA has already done the check for (X, Y) as done
+ // below, see eicSessionSetSessionTranscript().
} else {
- // To prevent replay-attacks, we check that the public part of the ephemeral
- // key we previously created, is present in the DeviceEngagement part of
- // SessionTranscript as a COSE_Key, in uncompressed form.
+ // If mdoc session encryption is in use, check that the
+ // public part of the ephemeral key we previously created, is
+ // present in the DeviceEngagement part of SessionTranscript
+ // as a COSE_Key, in uncompressed form.
//
// We do this by just searching for the X and Y coordinates.
- //
- // Would be nice to move this check to the TA.
- if (sessionTranscript.size() > 0) {
+ if (sessionTranscript.size() > 0 && ephemeralPublicKey_.size() > 0) {
auto [getXYSuccess, ePubX, ePubY] = support::ecPublicKeyGetXandY(ephemeralPublicKey_);
if (!getXYSuccess) {
return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
@@ -608,33 +607,36 @@
// Finally, pass info so the HMAC key can be derived and the TA can start
// creating the DeviceNameSpaces CBOR...
if (!session_) {
- if (sessionTranscript_.size() > 0 && readerPublicKey_.size() > 0 &&
- signingKeyBlob.size() > 0) {
- // We expect the reader ephemeral public key to be same size and curve
- // as the ephemeral key we generated (e.g. P-256 key), otherwise ECDH
- // won't work. So its length should be 65 bytes and it should be
- // starting with 0x04.
- if (readerPublicKey_.size() != 65 || readerPublicKey_[0] != 0x04) {
- return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
- IIdentityCredentialStore::STATUS_FAILED,
- "Reader public key is not in expected format"));
+ if (sessionTranscript_.size() > 0 && signingKeyBlob.size() > 0) {
+ vector<uint8_t> eReaderKeyP256;
+ if (readerPublicKey_.size() > 0) {
+ // If set, we expect the reader ephemeral public key to be same size and curve
+ // as the ephemeral key we generated (e.g. P-256 key), otherwise ECDH won't
+ // work. So its length should be 65 bytes and it should be starting with 0x04.
+ if (readerPublicKey_.size() != 65 || readerPublicKey_[0] != 0x04) {
+ return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+ IIdentityCredentialStore::STATUS_FAILED,
+ "Reader public key is not in expected format"));
+ }
+ eReaderKeyP256 =
+ vector<uint8_t>(readerPublicKey_.begin() + 1, readerPublicKey_.end());
}
- vector<uint8_t> pubKeyP256(readerPublicKey_.begin() + 1, readerPublicKey_.end());
- if (!hwProxy_->calcMacKey(sessionTranscript_, pubKeyP256, signingKeyBlob, docType_,
- numNamespacesWithValues, expectedDeviceNameSpacesSize_)) {
+ if (!hwProxy_->prepareDeviceAuthentication(
+ sessionTranscript_, eReaderKeyP256, signingKeyBlob, docType_,
+ numNamespacesWithValues, expectedDeviceNameSpacesSize_)) {
return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
IIdentityCredentialStore::STATUS_FAILED,
"Error starting retrieving entries"));
}
}
} else {
- if (session_->getSessionTranscript().size() > 0 &&
- session_->getReaderEphemeralPublicKey().size() > 0 && signingKeyBlob.size() > 0) {
+ if (session_->getSessionTranscript().size() > 0 && signingKeyBlob.size() > 0) {
// Don't actually pass the reader ephemeral public key in, the TA will get
// it from the session object.
//
- if (!hwProxy_->calcMacKey(sessionTranscript_, {}, signingKeyBlob, docType_,
- numNamespacesWithValues, expectedDeviceNameSpacesSize_)) {
+ if (!hwProxy_->prepareDeviceAuthentication(sessionTranscript_, {}, signingKeyBlob,
+ docType_, numNamespacesWithValues,
+ expectedDeviceNameSpacesSize_)) {
return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
IIdentityCredentialStore::STATUS_FAILED,
"Error starting retrieving entries"));
@@ -924,8 +926,9 @@
return ndk::ScopedAStatus::ok();
}
-ndk::ScopedAStatus IdentityCredential::finishRetrieval(vector<uint8_t>* outMac,
- vector<uint8_t>* outDeviceNameSpaces) {
+ndk::ScopedAStatus IdentityCredential::finishRetrievalWithSignature(
+ vector<uint8_t>* outMac, vector<uint8_t>* outDeviceNameSpaces,
+ vector<uint8_t>* outEcdsaSignature) {
ndk::ScopedAStatus status = ensureHwProxy();
if (!status.isOk()) {
return status;
@@ -948,17 +951,34 @@
.c_str()));
}
+ optional<vector<uint8_t>> digestToBeMaced;
+ optional<vector<uint8_t>> signatureToBeSigned;
+
+ // This relies on the fact that binder calls never pass a nullptr
+ // for out parameters. Hence if it's null here we know this was
+ // called from finishRetrieval() below.
+ if (outEcdsaSignature == nullptr) {
+ digestToBeMaced = hwProxy_->finishRetrieval();
+ if (!digestToBeMaced) {
+ return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+ IIdentityCredentialStore::STATUS_INVALID_DATA,
+ "Error generating digestToBeMaced"));
+ }
+ } else {
+ auto macAndSignature = hwProxy_->finishRetrievalWithSignature();
+ if (!macAndSignature) {
+ return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+ IIdentityCredentialStore::STATUS_INVALID_DATA,
+ "Error generating digestToBeMaced and signatureToBeSigned"));
+ }
+ digestToBeMaced = macAndSignature->first;
+ signatureToBeSigned = macAndSignature->second;
+ }
+
// If the TA calculated a MAC (it might not have), format it as a COSE_Mac0
//
- optional<vector<uint8_t>> mac;
- optional<vector<uint8_t>> digestToBeMaced = hwProxy_->finishRetrieval();
-
- // The MAC not being set means an error occurred.
- if (!digestToBeMaced) {
- return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
- IIdentityCredentialStore::STATUS_INVALID_DATA, "Error generating digestToBeMaced"));
- }
// Size 0 means that the MAC isn't set. If it's set, it has to be 32 bytes.
+ optional<vector<uint8_t>> mac;
if (digestToBeMaced.value().size() != 0) {
if (digestToBeMaced.value().size() != 32) {
return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
@@ -967,12 +987,27 @@
}
mac = support::coseMacWithDigest(digestToBeMaced.value(), {} /* data */);
}
-
*outMac = mac.value_or(vector<uint8_t>({}));
+
+ optional<vector<uint8_t>> signature;
+ if (signatureToBeSigned && signatureToBeSigned.value().size() != 0) {
+ signature = support::coseSignEcDsaWithSignature(signatureToBeSigned.value(), {}, // data
+ {}); // certificateChain
+ }
+ if (outEcdsaSignature != nullptr) {
+ *outEcdsaSignature = signature.value_or(vector<uint8_t>({}));
+ }
+
*outDeviceNameSpaces = encodedDeviceNameSpaces;
+
return ndk::ScopedAStatus::ok();
}
+ndk::ScopedAStatus IdentityCredential::finishRetrieval(vector<uint8_t>* outMac,
+ vector<uint8_t>* outDeviceNameSpaces) {
+ return finishRetrievalWithSignature(outMac, outDeviceNameSpaces, nullptr);
+}
+
ndk::ScopedAStatus IdentityCredential::generateSigningKeyPair(
vector<uint8_t>* outSigningKeyBlob, Certificate* outSigningKeyCertificate) {
if (session_) {
diff --git a/identity/aidl/default/common/IdentityCredential.h b/identity/aidl/default/common/IdentityCredential.h
index 5929829..1e0cd64 100644
--- a/identity/aidl/default/common/IdentityCredential.h
+++ b/identity/aidl/default/common/IdentityCredential.h
@@ -92,6 +92,10 @@
ndk::ScopedAStatus updateCredential(
shared_ptr<IWritableIdentityCredential>* outWritableCredential) override;
+ ndk::ScopedAStatus finishRetrievalWithSignature(vector<uint8_t>* outMac,
+ vector<uint8_t>* outDeviceNameSpaces,
+ vector<uint8_t>* outEcdsaSignature) override;
+
private:
ndk::ScopedAStatus deleteCredentialCommon(const vector<uint8_t>& challenge,
bool includeChallenge,
diff --git a/identity/aidl/default/common/PresentationSession.cpp b/identity/aidl/default/common/PresentationSession.cpp
index 2eb7f2e..cf5b066 100644
--- a/identity/aidl/default/common/PresentationSession.cpp
+++ b/identity/aidl/default/common/PresentationSession.cpp
@@ -54,19 +54,6 @@
}
id_ = id.value();
- optional<vector<uint8_t>> ephemeralKeyPriv = hwProxy_->getEphemeralKeyPair();
- if (!ephemeralKeyPriv) {
- LOG(ERROR) << "Error getting ephemeral private key for session";
- return IIdentityCredentialStore::STATUS_FAILED;
- }
- optional<vector<uint8_t>> ephemeralKeyPair =
- support::ecPrivateKeyToKeyPair(ephemeralKeyPriv.value());
- if (!ephemeralKeyPair) {
- LOG(ERROR) << "Error creating ephemeral key-pair";
- return IIdentityCredentialStore::STATUS_FAILED;
- }
- ephemeralKeyPair_ = ephemeralKeyPair.value();
-
optional<uint64_t> authChallenge = hwProxy_->getAuthChallenge();
if (!authChallenge) {
LOG(ERROR) << "Error getting authChallenge for session";
@@ -78,6 +65,23 @@
}
ndk::ScopedAStatus PresentationSession::getEphemeralKeyPair(vector<uint8_t>* outKeyPair) {
+ if (ephemeralKeyPair_.size() == 0) {
+ optional<vector<uint8_t>> ephemeralKeyPriv = hwProxy_->getEphemeralKeyPair();
+ if (!ephemeralKeyPriv) {
+ LOG(ERROR) << "Error getting ephemeral private key for session";
+ return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+ IIdentityCredentialStore::STATUS_FAILED,
+ "Error getting ephemeral private key for session"));
+ }
+ optional<vector<uint8_t>> ephemeralKeyPair =
+ support::ecPrivateKeyToKeyPair(ephemeralKeyPriv.value());
+ if (!ephemeralKeyPair) {
+ LOG(ERROR) << "Error creating ephemeral key-pair";
+ return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+ IIdentityCredentialStore::STATUS_FAILED, "Error creating ephemeral key-pair"));
+ }
+ ephemeralKeyPair_ = ephemeralKeyPair.value();
+ }
*outKeyPair = ephemeralKeyPair_;
return ndk::ScopedAStatus::ok();
}
diff --git a/identity/aidl/default/common/PresentationSession.h b/identity/aidl/default/common/PresentationSession.h
index 4cb174a..b3d46f9 100644
--- a/identity/aidl/default/common/PresentationSession.h
+++ b/identity/aidl/default/common/PresentationSession.h
@@ -72,9 +72,11 @@
// Set by initialize()
uint64_t id_;
- vector<uint8_t> ephemeralKeyPair_;
uint64_t authChallenge_;
+ // Set by getEphemeralKeyPair()
+ vector<uint8_t> ephemeralKeyPair_;
+
// Set by setReaderEphemeralPublicKey()
vector<uint8_t> readerPublicKey_;
diff --git a/identity/aidl/default/common/SecureHardwareProxy.h b/identity/aidl/default/common/SecureHardwareProxy.h
index 9f63ad8..6463318 100644
--- a/identity/aidl/default/common/SecureHardwareProxy.h
+++ b/identity/aidl/default/common/SecureHardwareProxy.h
@@ -194,11 +194,12 @@
const vector<uint8_t>& requestMessage, int coseSignAlg,
const vector<uint8_t>& readerSignatureOfToBeSigned) = 0;
- virtual bool calcMacKey(const vector<uint8_t>& sessionTranscript,
- const vector<uint8_t>& readerEphemeralPublicKey,
- const vector<uint8_t>& signingKeyBlob, const string& docType,
- unsigned int numNamespacesWithValues,
- size_t expectedProofOfProvisioningSize) = 0;
+ virtual bool prepareDeviceAuthentication(const vector<uint8_t>& sessionTranscript,
+ const vector<uint8_t>& readerEphemeralPublicKey,
+ const vector<uint8_t>& signingKeyBlob,
+ const string& docType,
+ unsigned int numNamespacesWithValues,
+ size_t expectedDeviceNamespacesSize) = 0;
virtual AccessCheckResult startRetrieveEntryValue(
const string& nameSpace, const string& name, unsigned int newNamespaceNumEntries,
@@ -209,6 +210,7 @@
const vector<int32_t>& accessControlProfileIds) = 0;
virtual optional<vector<uint8_t>> finishRetrieval();
+ virtual optional<pair<vector<uint8_t>, vector<uint8_t>>> finishRetrievalWithSignature();
virtual optional<vector<uint8_t>> deleteCredential(const string& docType,
const vector<uint8_t>& challenge,
diff --git a/identity/aidl/default/identity-default.xml b/identity/aidl/default/identity-default.xml
index cc0ddc7..d0d43af 100644
--- a/identity/aidl/default/identity-default.xml
+++ b/identity/aidl/default/identity-default.xml
@@ -1,7 +1,7 @@
<manifest version="1.0" type="device">
<hal format="aidl">
<name>android.hardware.identity</name>
- <version>4</version>
+ <version>5</version>
<interface>
<name>IIdentityCredentialStore</name>
<instance>default</instance>
diff --git a/identity/aidl/default/libeic/EicPresentation.c b/identity/aidl/default/libeic/EicPresentation.c
index 104a559..23fd0b3 100644
--- a/identity/aidl/default/libeic/EicPresentation.c
+++ b/identity/aidl/default/libeic/EicPresentation.c
@@ -557,87 +557,11 @@
return true;
}
-bool eicPresentationCalcMacKey(EicPresentation* ctx, const uint8_t* sessionTranscript,
- size_t sessionTranscriptSize,
- const uint8_t readerEphemeralPublicKey[EIC_P256_PUB_KEY_SIZE],
- const uint8_t signingKeyBlob[60], const char* docType,
- size_t docTypeLength, unsigned int numNamespacesWithValues,
- size_t expectedDeviceNamespacesSize) {
- if (ctx->sessionId != 0) {
- EicSession* session = eicSessionGetForId(ctx->sessionId);
- if (session == NULL) {
- eicDebug("Error looking up session for sessionId %" PRIu32, ctx->sessionId);
- return false;
- }
- EicSha256Ctx sha256;
- uint8_t sessionTranscriptSha256[EIC_SHA256_DIGEST_SIZE];
- eicOpsSha256Init(&sha256);
- eicOpsSha256Update(&sha256, sessionTranscript, sessionTranscriptSize);
- eicOpsSha256Final(&sha256, sessionTranscriptSha256);
- if (eicCryptoMemCmp(sessionTranscriptSha256, session->sessionTranscriptSha256,
- EIC_SHA256_DIGEST_SIZE) != 0) {
- eicDebug("SessionTranscript mismatch");
- return false;
- }
- readerEphemeralPublicKey = session->readerEphemeralPublicKey;
- }
-
- uint8_t signingKeyPriv[EIC_P256_PRIV_KEY_SIZE];
- if (!eicOpsDecryptAes128Gcm(ctx->storageKey, signingKeyBlob, 60, (const uint8_t*)docType,
- docTypeLength, signingKeyPriv)) {
- eicDebug("Error decrypting signingKeyBlob");
- return false;
- }
-
- uint8_t sharedSecret[EIC_P256_COORDINATE_SIZE];
- if (!eicOpsEcdh(readerEphemeralPublicKey, signingKeyPriv, sharedSecret)) {
- eicDebug("ECDH failed");
- return false;
- }
-
- EicCbor cbor;
- eicCborInit(&cbor, NULL, 0);
- eicCborAppendSemantic(&cbor, EIC_CBOR_SEMANTIC_TAG_ENCODED_CBOR);
- eicCborAppendByteString(&cbor, sessionTranscript, sessionTranscriptSize);
- uint8_t salt[EIC_SHA256_DIGEST_SIZE];
- eicCborFinal(&cbor, salt);
-
- const uint8_t info[7] = {'E', 'M', 'a', 'c', 'K', 'e', 'y'};
- uint8_t derivedKey[32];
- if (!eicOpsHkdf(sharedSecret, EIC_P256_COORDINATE_SIZE, salt, sizeof(salt), info, sizeof(info),
- derivedKey, sizeof(derivedKey))) {
- eicDebug("HKDF failed");
- return false;
- }
-
- eicCborInitHmacSha256(&ctx->cbor, NULL, 0, derivedKey, sizeof(derivedKey));
- ctx->buildCbor = true;
-
- // What we're going to calculate the HMAC-SHA256 is the COSE ToBeMaced
- // structure which looks like the following:
- //
- // MAC_structure = [
- // context : "MAC" / "MAC0",
- // protected : empty_or_serialized_map,
- // external_aad : bstr,
- // payload : bstr
- // ]
- //
- eicCborAppendArray(&ctx->cbor, 4);
- eicCborAppendStringZ(&ctx->cbor, "MAC0");
-
- // The COSE Encoded protected headers is just a single field with
- // COSE_LABEL_ALG (1) -> COSE_ALG_HMAC_256_256 (5). For simplicitly we just
- // hard-code the CBOR encoding:
- static const uint8_t coseEncodedProtectedHeaders[] = {0xa1, 0x01, 0x05};
- eicCborAppendByteString(&ctx->cbor, coseEncodedProtectedHeaders,
- sizeof(coseEncodedProtectedHeaders));
-
- // We currently don't support Externally Supplied Data (RFC 8152 section 4.3)
- // so external_aad is the empty bstr
- static const uint8_t externalAad[0] = {};
- eicCborAppendByteString(&ctx->cbor, externalAad, sizeof(externalAad));
-
+// Helper used to append the DeviceAuthencation prelude, used for both MACing and ECDSA signing.
+static size_t appendDeviceAuthentication(EicCbor* cbor, const uint8_t* sessionTranscript,
+ size_t sessionTranscriptSize, const char* docType,
+ size_t docTypeLength,
+ size_t expectedDeviceNamespacesSize) {
// For the payload, the _encoded_ form follows here. We handle this by simply
// opening a bstr, and then writing the CBOR. This requires us to know the
// size of said bstr, ahead of time... the CBOR to be written is
@@ -674,26 +598,148 @@
dabCalculatedSize += calculatedSize;
// Begin the bytestring for DeviceAuthenticationBytes;
- eicCborBegin(&ctx->cbor, EIC_CBOR_MAJOR_TYPE_BYTE_STRING, dabCalculatedSize);
+ eicCborBegin(cbor, EIC_CBOR_MAJOR_TYPE_BYTE_STRING, dabCalculatedSize);
- eicCborAppendSemantic(&ctx->cbor, EIC_CBOR_SEMANTIC_TAG_ENCODED_CBOR);
+ eicCborAppendSemantic(cbor, EIC_CBOR_SEMANTIC_TAG_ENCODED_CBOR);
// Begins the bytestring for DeviceAuthentication;
- eicCborBegin(&ctx->cbor, EIC_CBOR_MAJOR_TYPE_BYTE_STRING, calculatedSize);
+ eicCborBegin(cbor, EIC_CBOR_MAJOR_TYPE_BYTE_STRING, calculatedSize);
- eicCborAppendArray(&ctx->cbor, 4);
- eicCborAppendStringZ(&ctx->cbor, "DeviceAuthentication");
- eicCborAppend(&ctx->cbor, sessionTranscript, sessionTranscriptSize);
- eicCborAppendString(&ctx->cbor, docType, docTypeLength);
+ eicCborAppendArray(cbor, 4);
+ eicCborAppendStringZ(cbor, "DeviceAuthentication");
+ eicCborAppend(cbor, sessionTranscript, sessionTranscriptSize);
+ eicCborAppendString(cbor, docType, docTypeLength);
// For the payload, the _encoded_ form follows here. We handle this by simply
// opening a bstr, and then writing the CBOR. This requires us to know the
// size of said bstr, ahead of time.
- eicCborAppendSemantic(&ctx->cbor, EIC_CBOR_SEMANTIC_TAG_ENCODED_CBOR);
- eicCborBegin(&ctx->cbor, EIC_CBOR_MAJOR_TYPE_BYTE_STRING, expectedDeviceNamespacesSize);
- ctx->expectedCborSizeAtEnd = expectedDeviceNamespacesSize + ctx->cbor.size;
+ eicCborAppendSemantic(cbor, EIC_CBOR_SEMANTIC_TAG_ENCODED_CBOR);
+ eicCborBegin(cbor, EIC_CBOR_MAJOR_TYPE_BYTE_STRING, expectedDeviceNamespacesSize);
+ size_t expectedCborSizeAtEnd = expectedDeviceNamespacesSize + cbor->size;
- eicCborAppendMap(&ctx->cbor, numNamespacesWithValues);
+ return expectedCborSizeAtEnd;
+}
+
+bool eicPresentationPrepareDeviceAuthentication(
+ EicPresentation* ctx, const uint8_t* sessionTranscript, size_t sessionTranscriptSize,
+ const uint8_t* readerEphemeralPublicKey, size_t readerEphemeralPublicKeySize,
+ const uint8_t signingKeyBlob[60], const char* docType, size_t docTypeLength,
+ unsigned int numNamespacesWithValues, size_t expectedDeviceNamespacesSize) {
+ if (ctx->sessionId != 0) {
+ if (readerEphemeralPublicKeySize != 0) {
+ eicDebug("In a session but readerEphemeralPublicKeySize is non-zero");
+ return false;
+ }
+ EicSession* session = eicSessionGetForId(ctx->sessionId);
+ if (session == NULL) {
+ eicDebug("Error looking up session for sessionId %" PRIu32, ctx->sessionId);
+ return false;
+ }
+ EicSha256Ctx sha256;
+ uint8_t sessionTranscriptSha256[EIC_SHA256_DIGEST_SIZE];
+ eicOpsSha256Init(&sha256);
+ eicOpsSha256Update(&sha256, sessionTranscript, sessionTranscriptSize);
+ eicOpsSha256Final(&sha256, sessionTranscriptSha256);
+ if (eicCryptoMemCmp(sessionTranscriptSha256, session->sessionTranscriptSha256,
+ EIC_SHA256_DIGEST_SIZE) != 0) {
+ eicDebug("SessionTranscript mismatch");
+ return false;
+ }
+ readerEphemeralPublicKey = session->readerEphemeralPublicKey;
+ readerEphemeralPublicKeySize = session->readerEphemeralPublicKeySize;
+ }
+
+ // Stash the decrypted DeviceKey in context since we'll need it later in
+ // eicPresentationFinishRetrievalWithSignature()
+ if (!eicOpsDecryptAes128Gcm(ctx->storageKey, signingKeyBlob, 60, (const uint8_t*)docType,
+ docTypeLength, ctx->deviceKeyPriv)) {
+ eicDebug("Error decrypting signingKeyBlob");
+ return false;
+ }
+
+ // We can only do MACing if EReaderKey has been set... it might not have been set if for
+ // example mdoc session encryption isn't in use. In that case we can still do ECDSA
+ if (readerEphemeralPublicKeySize > 0) {
+ if (readerEphemeralPublicKeySize != EIC_P256_PUB_KEY_SIZE) {
+ eicDebug("Unexpected size %zd for readerEphemeralPublicKeySize",
+ readerEphemeralPublicKeySize);
+ return false;
+ }
+
+ uint8_t sharedSecret[EIC_P256_COORDINATE_SIZE];
+ if (!eicOpsEcdh(readerEphemeralPublicKey, ctx->deviceKeyPriv, sharedSecret)) {
+ eicDebug("ECDH failed");
+ return false;
+ }
+
+ EicCbor cbor;
+ eicCborInit(&cbor, NULL, 0);
+ eicCborAppendSemantic(&cbor, EIC_CBOR_SEMANTIC_TAG_ENCODED_CBOR);
+ eicCborAppendByteString(&cbor, sessionTranscript, sessionTranscriptSize);
+ uint8_t salt[EIC_SHA256_DIGEST_SIZE];
+ eicCborFinal(&cbor, salt);
+
+ const uint8_t info[7] = {'E', 'M', 'a', 'c', 'K', 'e', 'y'};
+ uint8_t derivedKey[32];
+ if (!eicOpsHkdf(sharedSecret, EIC_P256_COORDINATE_SIZE, salt, sizeof(salt), info,
+ sizeof(info), derivedKey, sizeof(derivedKey))) {
+ eicDebug("HKDF failed");
+ return false;
+ }
+
+ eicCborInitHmacSha256(&ctx->cbor, NULL, 0, derivedKey, sizeof(derivedKey));
+
+ // What we're going to calculate the HMAC-SHA256 is the COSE ToBeMaced
+ // structure which looks like the following:
+ //
+ // MAC_structure = [
+ // context : "MAC" / "MAC0",
+ // protected : empty_or_serialized_map,
+ // external_aad : bstr,
+ // payload : bstr
+ // ]
+ //
+ eicCborAppendArray(&ctx->cbor, 4);
+ eicCborAppendStringZ(&ctx->cbor, "MAC0");
+
+ // The COSE Encoded protected headers is just a single field with
+ // COSE_LABEL_ALG (1) -> COSE_ALG_HMAC_256_256 (5). For simplicitly we just
+ // hard-code the CBOR encoding:
+ static const uint8_t coseEncodedProtectedHeaders[] = {0xa1, 0x01, 0x05};
+ eicCborAppendByteString(&ctx->cbor, coseEncodedProtectedHeaders,
+ sizeof(coseEncodedProtectedHeaders));
+
+ // We currently don't support Externally Supplied Data (RFC 8152 section 4.3)
+ // so external_aad is the empty bstr
+ static const uint8_t externalAad[0] = {};
+ eicCborAppendByteString(&ctx->cbor, externalAad, sizeof(externalAad));
+
+ // Append DeviceAuthentication prelude and open the DeviceSigned map...
+ ctx->expectedCborSizeAtEnd =
+ appendDeviceAuthentication(&ctx->cbor, sessionTranscript, sessionTranscriptSize,
+ docType, docTypeLength, expectedDeviceNamespacesSize);
+ eicCborAppendMap(&ctx->cbor, numNamespacesWithValues);
+ ctx->buildCbor = true;
+ }
+
+ // Now do the same for ECDSA signatures...
+ //
+ eicCborInit(&ctx->cborEcdsa, NULL, 0);
+ eicCborAppendArray(&ctx->cborEcdsa, 4);
+ eicCborAppendStringZ(&ctx->cborEcdsa, "Signature1");
+ static const uint8_t coseEncodedProtectedHeadersEcdsa[] = {0xa1, 0x01, 0x26};
+ eicCborAppendByteString(&ctx->cborEcdsa, coseEncodedProtectedHeadersEcdsa,
+ sizeof(coseEncodedProtectedHeadersEcdsa));
+ static const uint8_t externalAadEcdsa[0] = {};
+ eicCborAppendByteString(&ctx->cborEcdsa, externalAadEcdsa, sizeof(externalAadEcdsa));
+
+ // Append DeviceAuthentication prelude and open the DeviceSigned map...
+ ctx->expectedCborEcdsaSizeAtEnd =
+ appendDeviceAuthentication(&ctx->cborEcdsa, sessionTranscript, sessionTranscriptSize,
+ docType, docTypeLength, expectedDeviceNamespacesSize);
+ eicCborAppendMap(&ctx->cborEcdsa, numNamespacesWithValues);
+ ctx->buildCborEcdsa = true;
+
return true;
}
@@ -702,6 +748,7 @@
// state objects here.
ctx->requestMessageValidated = false;
ctx->buildCbor = false;
+ ctx->buildCborEcdsa = false;
ctx->accessControlProfileMaskValidated = 0;
ctx->accessControlProfileMaskUsesReaderAuth = 0;
ctx->accessControlProfileMaskFailedReaderAuth = 0;
@@ -724,6 +771,9 @@
if (newNamespaceNumEntries > 0) {
eicCborAppendString(&ctx->cbor, nameSpace, nameSpaceLength);
eicCborAppendMap(&ctx->cbor, newNamespaceNumEntries);
+
+ eicCborAppendString(&ctx->cborEcdsa, nameSpace, nameSpaceLength);
+ eicCborAppendMap(&ctx->cborEcdsa, newNamespaceNumEntries);
}
// We'll need to calc and store a digest of additionalData to check that it's the same
@@ -778,6 +828,7 @@
if (result == EIC_ACCESS_CHECK_RESULT_OK) {
eicCborAppendString(&ctx->cbor, name, nameLength);
+ eicCborAppendString(&ctx->cborEcdsa, name, nameLength);
ctx->accessCheckOk = true;
}
return result;
@@ -821,6 +872,7 @@
}
eicCborAppend(&ctx->cbor, content, encryptedContentSize - 28);
+ eicCborAppend(&ctx->cborEcdsa, content, encryptedContentSize - 28);
return true;
}
@@ -842,6 +894,40 @@
return false;
}
eicCborFinal(&ctx->cbor, digestToBeMaced);
+
+ return true;
+}
+
+bool eicPresentationFinishRetrievalWithSignature(EicPresentation* ctx, uint8_t* digestToBeMaced,
+ size_t* digestToBeMacedSize,
+ uint8_t* signatureOfToBeSigned,
+ size_t* signatureOfToBeSignedSize) {
+ if (!eicPresentationFinishRetrieval(ctx, digestToBeMaced, digestToBeMacedSize)) {
+ return false;
+ }
+
+ if (!ctx->buildCborEcdsa) {
+ *signatureOfToBeSignedSize = 0;
+ return true;
+ }
+ if (*signatureOfToBeSignedSize != EIC_ECDSA_P256_SIGNATURE_SIZE) {
+ return false;
+ }
+
+ // This verifies that the correct expectedDeviceNamespacesSize value was
+ // passed in at eicPresentationCalcMacKey() time.
+ if (ctx->cborEcdsa.size != ctx->expectedCborEcdsaSizeAtEnd) {
+ eicDebug("CBOR ECDSA size is %zd, was expecting %zd", ctx->cborEcdsa.size,
+ ctx->expectedCborEcdsaSizeAtEnd);
+ return false;
+ }
+ uint8_t cborSha256[EIC_SHA256_DIGEST_SIZE];
+ eicCborFinal(&ctx->cborEcdsa, cborSha256);
+ if (!eicOpsEcDsa(ctx->deviceKeyPriv, cborSha256, signatureOfToBeSigned)) {
+ eicDebug("Error signing DeviceAuthentication");
+ return false;
+ }
+ eicDebug("set the signature");
return true;
}
diff --git a/identity/aidl/default/libeic/EicPresentation.h b/identity/aidl/default/libeic/EicPresentation.h
index a031890..cd3162a 100644
--- a/identity/aidl/default/libeic/EicPresentation.h
+++ b/identity/aidl/default/libeic/EicPresentation.h
@@ -76,6 +76,7 @@
// aren't.
bool requestMessageValidated;
bool buildCbor;
+ bool buildCborEcdsa;
// Set to true initialized as a test credential.
bool testCredential;
@@ -101,6 +102,12 @@
size_t expectedCborSizeAtEnd;
EicCbor cbor;
+
+ // The selected DeviceKey / AuthKey
+ uint8_t deviceKeyPriv[EIC_P256_PRIV_KEY_SIZE];
+
+ EicCbor cborEcdsa;
+ size_t expectedCborEcdsaSizeAtEnd;
} EicPresentation;
// If sessionId is zero (EIC_PRESENTATION_ID_UNSET), the presentation object is not associated
@@ -214,14 +221,13 @@
EIC_ACCESS_CHECK_RESULT_READER_AUTHENTICATION_FAILED,
} EicAccessCheckResult;
-// Passes enough information to calculate the MACing key
+// Passes enough information to calculate the MACing key and/or prepare ECDSA signing
//
-bool eicPresentationCalcMacKey(EicPresentation* ctx, const uint8_t* sessionTranscript,
- size_t sessionTranscriptSize,
- const uint8_t readerEphemeralPublicKey[EIC_P256_PUB_KEY_SIZE],
- const uint8_t signingKeyBlob[60], const char* docType,
- size_t docTypeLength, unsigned int numNamespacesWithValues,
- size_t expectedDeviceNamespacesSize);
+bool eicPresentationPrepareDeviceAuthentication(
+ EicPresentation* ctx, const uint8_t* sessionTranscript, size_t sessionTranscriptSize,
+ const uint8_t* readerEphemeralPublicKey, size_t readerEphemeralPublicKeySize,
+ const uint8_t signingKeyBlob[60], const char* docType, size_t docTypeLength,
+ unsigned int numNamespacesWithValues, size_t expectedDeviceNamespacesSize);
// The scratchSpace should be set to a buffer at least 512 bytes (ideally 1024
// bytes, the bigger the better). It's done this way to avoid allocating stack
@@ -253,6 +259,13 @@
bool eicPresentationFinishRetrieval(EicPresentation* ctx, uint8_t* digestToBeMaced,
size_t* digestToBeMacedSize);
+// Like eicPresentationFinishRetrieval() but also returns an ECDSA signature.
+//
+bool eicPresentationFinishRetrievalWithSignature(EicPresentation* ctx, uint8_t* digestToBeMaced,
+ size_t* digestToBeMacedSize,
+ uint8_t* signatureOfToBeSigned,
+ size_t* signatureOfToBeSignedSize);
+
// The data returned in |signatureOfToBeSigned| contains the ECDSA signature of
// the ToBeSigned CBOR from RFC 8051 "4.4. Signing and Verification Process"
// where content is set to the ProofOfDeletion CBOR.
diff --git a/identity/aidl/default/libeic/EicSession.c b/identity/aidl/default/libeic/EicSession.c
index d0c7a0d..e44fa68 100644
--- a/identity/aidl/default/libeic/EicSession.c
+++ b/identity/aidl/default/libeic/EicSession.c
@@ -84,30 +84,35 @@
bool eicSessionGetEphemeralKeyPair(EicSession* ctx,
uint8_t ephemeralPrivateKey[EIC_P256_PRIV_KEY_SIZE]) {
eicMemCpy(ephemeralPrivateKey, ctx->ephemeralPrivateKey, EIC_P256_PRIV_KEY_SIZE);
+ ctx->getEphemeralKeyPairCalled = true;
return true;
}
bool eicSessionSetReaderEphemeralPublicKey(
EicSession* ctx, const uint8_t readerEphemeralPublicKey[EIC_P256_PUB_KEY_SIZE]) {
eicMemCpy(ctx->readerEphemeralPublicKey, readerEphemeralPublicKey, EIC_P256_PUB_KEY_SIZE);
+ ctx->readerEphemeralPublicKeySize = EIC_P256_PUB_KEY_SIZE;
return true;
}
bool eicSessionSetSessionTranscript(EicSession* ctx, const uint8_t* sessionTranscript,
size_t sessionTranscriptSize) {
- // Only accept the SessionTranscript if X and Y from the ephemeral key
- // we created is somewhere in SessionTranscript...
+ // If mdoc session encryption is in use, only accept the
+ // SessionTranscript if X and Y from the ephemeral key we created
+ // is somewhere in SessionTranscript...
//
- if (eicMemMem(sessionTranscript, sessionTranscriptSize, ctx->ephemeralPublicKey,
- EIC_P256_PUB_KEY_SIZE / 2) == NULL) {
- eicDebug("Error finding X from ephemeralPublicKey in sessionTranscript");
- return false;
- }
- if (eicMemMem(sessionTranscript, sessionTranscriptSize,
- ctx->ephemeralPublicKey + EIC_P256_PUB_KEY_SIZE / 2,
- EIC_P256_PUB_KEY_SIZE / 2) == NULL) {
- eicDebug("Error finding Y from ephemeralPublicKey in sessionTranscript");
- return false;
+ if (ctx->getEphemeralKeyPairCalled) {
+ if (eicMemMem(sessionTranscript, sessionTranscriptSize, ctx->ephemeralPublicKey,
+ EIC_P256_PUB_KEY_SIZE / 2) == NULL) {
+ eicDebug("Error finding X from ephemeralPublicKey in sessionTranscript");
+ return false;
+ }
+ if (eicMemMem(sessionTranscript, sessionTranscriptSize,
+ ctx->ephemeralPublicKey + EIC_P256_PUB_KEY_SIZE / 2,
+ EIC_P256_PUB_KEY_SIZE / 2) == NULL) {
+ eicDebug("Error finding Y from ephemeralPublicKey in sessionTranscript");
+ return false;
+ }
}
// To save space we only store the SHA-256 of SessionTranscript
diff --git a/identity/aidl/default/libeic/EicSession.h b/identity/aidl/default/libeic/EicSession.h
index 0303dae..ae9babf 100644
--- a/identity/aidl/default/libeic/EicSession.h
+++ b/identity/aidl/default/libeic/EicSession.h
@@ -31,6 +31,9 @@
// A non-zero number unique for this EicSession instance
uint32_t id;
+ // Set to true iff eicSessionGetEphemeralKeyPair() has been called.
+ bool getEphemeralKeyPairCalled;
+
// The challenge generated at construction time by eicSessionInit().
uint64_t authChallenge;
@@ -41,6 +44,7 @@
uint8_t sessionTranscriptSha256[EIC_SHA256_DIGEST_SIZE];
+ size_t readerEphemeralPublicKeySize;
} EicSession;
bool eicSessionInit(EicSession* ctx);
diff --git a/identity/aidl/vts/EndToEndTests.cpp b/identity/aidl/vts/EndToEndTests.cpp
index 67db915..ae9035b 100644
--- a/identity/aidl/vts/EndToEndTests.cpp
+++ b/identity/aidl/vts/EndToEndTests.cpp
@@ -441,8 +441,18 @@
}
vector<uint8_t> mac;
+ vector<uint8_t> ecdsaSignature;
vector<uint8_t> deviceNameSpacesEncoded;
- ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesEncoded).isOk());
+ // API version 5 (feature version 202301) returns both MAC and ECDSA signature.
+ if (halApiVersion_ >= 5) {
+ ASSERT_TRUE(credential
+ ->finishRetrievalWithSignature(&mac, &deviceNameSpacesEncoded,
+ &ecdsaSignature)
+ .isOk());
+ ASSERT_GT(ecdsaSignature.size(), 0);
+ } else {
+ ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesEncoded).isOk());
+ }
cborPretty = cppbor::prettyPrint(deviceNameSpacesEncoded, 32, {});
ASSERT_EQ(
"{\n"
@@ -475,6 +485,21 @@
ASSERT_TRUE(calculatedMac);
EXPECT_EQ(mac, calculatedMac);
+ if (ecdsaSignature.size() > 0) {
+ vector<uint8_t> encodedDeviceAuthentication =
+ cppbor::Array()
+ .add("DeviceAuthentication")
+ .add(sessionTranscript.clone())
+ .add(docType)
+ .add(cppbor::SemanticTag(24, deviceNameSpacesEncoded))
+ .encode();
+ vector<uint8_t> deviceAuthenticationBytes =
+ cppbor::SemanticTag(24, encodedDeviceAuthentication).encode();
+ EXPECT_TRUE(support::coseCheckEcDsaSignature(ecdsaSignature,
+ deviceAuthenticationBytes, // Detached content
+ signingPubKey.value()));
+ }
+
// Also perform an additional empty request. This is what mDL applications
// are envisioned to do - one call to get the data elements, another to get
// an empty DeviceSignedItems and corresponding MAC.
@@ -486,7 +511,16 @@
signingKeyBlob, sessionTranscriptEncoded, {}, // readerSignature,
testEntriesEntryCounts)
.isOk());
- ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesEncoded).isOk());
+ // API version 5 (feature version 202301) returns both MAC and ECDSA signature.
+ if (halApiVersion_ >= 5) {
+ ASSERT_TRUE(credential
+ ->finishRetrievalWithSignature(&mac, &deviceNameSpacesEncoded,
+ &ecdsaSignature)
+ .isOk());
+ ASSERT_GT(ecdsaSignature.size(), 0);
+ } else {
+ ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesEncoded).isOk());
+ }
cborPretty = cppbor::prettyPrint(deviceNameSpacesEncoded, 32, {});
ASSERT_EQ("{}", cborPretty);
// Calculate DeviceAuthentication and MAC (MACing key hasn't changed)
@@ -497,6 +531,21 @@
ASSERT_TRUE(calculatedMac);
EXPECT_EQ(mac, calculatedMac);
+ if (ecdsaSignature.size() > 0) {
+ vector<uint8_t> encodedDeviceAuthentication =
+ cppbor::Array()
+ .add("DeviceAuthentication")
+ .add(sessionTranscript.clone())
+ .add(docType)
+ .add(cppbor::SemanticTag(24, deviceNameSpacesEncoded))
+ .encode();
+ vector<uint8_t> deviceAuthenticationBytes =
+ cppbor::SemanticTag(24, encodedDeviceAuthentication).encode();
+ EXPECT_TRUE(support::coseCheckEcDsaSignature(ecdsaSignature,
+ deviceAuthenticationBytes, // Detached content
+ signingPubKey.value()));
+ }
+
// Some mDL apps might send a request but with a single empty
// namespace. Check that too.
RequestNamespace emptyRequestNS;
@@ -508,7 +557,16 @@
signingKeyBlob, sessionTranscriptEncoded, {}, // readerSignature,
testEntriesEntryCounts)
.isOk());
- ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesEncoded).isOk());
+ // API version 5 (feature version 202301) returns both MAC and ECDSA signature.
+ if (halApiVersion_ >= 5) {
+ ASSERT_TRUE(credential
+ ->finishRetrievalWithSignature(&mac, &deviceNameSpacesEncoded,
+ &ecdsaSignature)
+ .isOk());
+ ASSERT_GT(ecdsaSignature.size(), 0);
+ } else {
+ ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesEncoded).isOk());
+ }
cborPretty = cppbor::prettyPrint(deviceNameSpacesEncoded, 32, {});
ASSERT_EQ("{}", cborPretty);
// Calculate DeviceAuthentication and MAC (MACing key hasn't changed)
@@ -518,6 +576,248 @@
eMacKey.value()); // EMacKey
ASSERT_TRUE(calculatedMac);
EXPECT_EQ(mac, calculatedMac);
+
+ if (ecdsaSignature.size() > 0) {
+ vector<uint8_t> encodedDeviceAuthentication =
+ cppbor::Array()
+ .add("DeviceAuthentication")
+ .add(sessionTranscript.clone())
+ .add(docType)
+ .add(cppbor::SemanticTag(24, deviceNameSpacesEncoded))
+ .encode();
+ vector<uint8_t> deviceAuthenticationBytes =
+ cppbor::SemanticTag(24, encodedDeviceAuthentication).encode();
+ EXPECT_TRUE(support::coseCheckEcDsaSignature(ecdsaSignature,
+ deviceAuthenticationBytes, // Detached content
+ signingPubKey.value()));
+ }
+}
+
+TEST_P(EndToEndTests, noSessionEncryption) {
+ if (halApiVersion_ < 5) {
+ GTEST_SKIP() << "Need HAL API version 5, have " << halApiVersion_;
+ }
+
+ const vector<test_utils::TestProfile> testProfiles = {// Profile 0 (no authentication)
+ {0, {}, false, 0}};
+
+ HardwareAuthToken authToken;
+ VerificationToken verificationToken;
+ authToken.challenge = 0;
+ authToken.userId = 0;
+ authToken.authenticatorId = 0;
+ authToken.authenticatorType = ::android::hardware::keymaster::HardwareAuthenticatorType::NONE;
+ authToken.timestamp.milliSeconds = 0;
+ authToken.mac.clear();
+ verificationToken.challenge = 0;
+ verificationToken.timestamp.milliSeconds = 0;
+ verificationToken.securityLevel = ::android::hardware::keymaster::SecurityLevel::SOFTWARE;
+ verificationToken.mac.clear();
+
+ // Here's the actual test data:
+ const vector<test_utils::TestEntryData> testEntries = {
+ {"PersonalData", "Last name", string("Turing"), vector<int32_t>{0}},
+ {"PersonalData", "Birth date", string("19120623"), vector<int32_t>{0}},
+ {"PersonalData", "First name", string("Alan"), vector<int32_t>{0}},
+ };
+ const vector<int32_t> testEntriesEntryCounts = {3};
+ HardwareInformation hwInfo;
+ ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
+
+ string cborPretty;
+ sp<IWritableIdentityCredential> writableCredential;
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+ true /* testCredential */));
+
+ string challenge = "attestationChallenge";
+ test_utils::AttestationData attData(writableCredential, challenge,
+ {1} /* atteestationApplicationId */);
+ ASSERT_TRUE(attData.result.isOk())
+ << attData.result.exceptionCode() << "; " << attData.result.exceptionMessage() << endl;
+
+ // This is kinda of a hack but we need to give the size of
+ // ProofOfProvisioning that we'll expect to receive.
+ const int32_t expectedProofOfProvisioningSize = 230;
+ // OK to fail, not available in v1 HAL
+ writableCredential->setExpectedProofOfProvisioningSize(expectedProofOfProvisioningSize);
+ ASSERT_TRUE(
+ writableCredential->startPersonalization(testProfiles.size(), testEntriesEntryCounts)
+ .isOk());
+
+ optional<vector<SecureAccessControlProfile>> secureProfiles =
+ test_utils::addAccessControlProfiles(writableCredential, testProfiles);
+ ASSERT_TRUE(secureProfiles);
+
+ // Uses TestEntryData* pointer as key and values are the encrypted blobs. This
+ // is a little hacky but it works well enough.
+ map<const test_utils::TestEntryData*, vector<vector<uint8_t>>> encryptedBlobs;
+
+ for (const auto& entry : testEntries) {
+ ASSERT_TRUE(test_utils::addEntry(writableCredential, entry, hwInfo.dataChunkSize,
+ encryptedBlobs, true));
+ }
+
+ vector<uint8_t> credentialData;
+ vector<uint8_t> proofOfProvisioningSignature;
+ ASSERT_TRUE(
+ writableCredential->finishAddingEntries(&credentialData, &proofOfProvisioningSignature)
+ .isOk());
+
+ // Validate the proofOfProvisioning which was returned
+ optional<vector<uint8_t>> proofOfProvisioning =
+ support::coseSignGetPayload(proofOfProvisioningSignature);
+ ASSERT_TRUE(proofOfProvisioning);
+ cborPretty = cppbor::prettyPrint(proofOfProvisioning.value(), 32, {"readerCertificate"});
+ EXPECT_EQ(
+ "[\n"
+ " 'ProofOfProvisioning',\n"
+ " 'org.iso.18013-5.2019.mdl',\n"
+ " [\n"
+ " {\n"
+ " 'id' : 0,\n"
+ " },\n"
+ " ],\n"
+ " {\n"
+ " 'PersonalData' : [\n"
+ " {\n"
+ " 'name' : 'Last name',\n"
+ " 'value' : 'Turing',\n"
+ " 'accessControlProfiles' : [0, ],\n"
+ " },\n"
+ " {\n"
+ " 'name' : 'Birth date',\n"
+ " 'value' : '19120623',\n"
+ " 'accessControlProfiles' : [0, ],\n"
+ " },\n"
+ " {\n"
+ " 'name' : 'First name',\n"
+ " 'value' : 'Alan',\n"
+ " 'accessControlProfiles' : [0, ],\n"
+ " },\n"
+ " ],\n"
+ " },\n"
+ " true,\n"
+ "]",
+ cborPretty);
+
+ optional<vector<uint8_t>> credentialPubKey = support::certificateChainGetTopMostKey(
+ attData.attestationCertificate[0].encodedCertificate);
+ ASSERT_TRUE(credentialPubKey);
+ EXPECT_TRUE(support::coseCheckEcDsaSignature(proofOfProvisioningSignature,
+ {}, // Additional data
+ credentialPubKey.value()));
+ writableCredential = nullptr;
+
+ // Extract doctype, storage key, and credentialPrivKey from credentialData... this works
+ // only because we asked for a test-credential meaning that the HBK is all zeroes.
+ auto [exSuccess, exDocType, exStorageKey, exCredentialPrivKey, exSha256Pop] =
+ extractFromTestCredentialData(credentialData);
+
+ ASSERT_TRUE(exSuccess);
+ ASSERT_EQ(exDocType, "org.iso.18013-5.2019.mdl");
+ // ... check that the public key derived from the private key matches what was
+ // in the certificate.
+ optional<vector<uint8_t>> exCredentialKeyPair =
+ support::ecPrivateKeyToKeyPair(exCredentialPrivKey);
+ ASSERT_TRUE(exCredentialKeyPair);
+ optional<vector<uint8_t>> exCredentialPubKey =
+ support::ecKeyPairGetPublicKey(exCredentialKeyPair.value());
+ ASSERT_TRUE(exCredentialPubKey);
+ ASSERT_EQ(exCredentialPubKey.value(), credentialPubKey.value());
+
+ sp<IIdentityCredential> credential;
+ ASSERT_TRUE(credentialStore_
+ ->getCredential(
+ CipherSuite::CIPHERSUITE_ECDHE_HKDF_ECDSA_WITH_AES_256_GCM_SHA256,
+ credentialData, &credential)
+ .isOk());
+ ASSERT_NE(credential, nullptr);
+
+ // Calculate sessionTranscript, make something that resembles what you'd use for
+ // an over-the-Internet presentation not using mdoc session encryption.
+ cppbor::Array sessionTranscript =
+ cppbor::Array()
+ .add(cppbor::Null()) // DeviceEngagementBytes isn't used.
+ .add(cppbor::Null()) // EReaderKeyBytes isn't used.
+ .add(cppbor::Array() // Proprietary handover structure follows.
+ .add(cppbor::Tstr("TestHandover"))
+ .add(cppbor::Bstr(vector<uint8_t>{1, 2, 3}))
+ .add(cppbor::Bstr(vector<uint8_t>{9, 8, 7, 6})));
+ vector<uint8_t> sessionTranscriptEncoded = sessionTranscript.encode();
+
+ // Generate the key that will be used to sign AuthenticatedData.
+ vector<uint8_t> signingKeyBlob;
+ Certificate signingKeyCertificate;
+ ASSERT_TRUE(credential->generateSigningKeyPair(&signingKeyBlob, &signingKeyCertificate).isOk());
+ optional<vector<uint8_t>> signingPubKey =
+ support::certificateChainGetTopMostKey(signingKeyCertificate.encodedCertificate);
+ EXPECT_TRUE(signingPubKey);
+ test_utils::verifyAuthKeyCertificate(signingKeyCertificate.encodedCertificate);
+
+ vector<RequestNamespace> requestedNamespaces = test_utils::buildRequestNamespaces(testEntries);
+ ASSERT_TRUE(credential->setRequestedNamespaces(requestedNamespaces).isOk());
+ ASSERT_TRUE(credential->setVerificationToken(verificationToken).isOk());
+ Status status = credential->startRetrieval(
+ secureProfiles.value(), authToken, {} /* itemsRequestBytes*/, signingKeyBlob,
+ sessionTranscriptEncoded, {} /* readerSignature */, testEntriesEntryCounts);
+ ASSERT_TRUE(status.isOk()) << status.exceptionCode() << ": " << status.exceptionMessage();
+
+ for (const auto& entry : testEntries) {
+ ASSERT_TRUE(credential
+ ->startRetrieveEntryValue(entry.nameSpace, entry.name,
+ entry.valueCbor.size(), entry.profileIds)
+ .isOk());
+
+ auto it = encryptedBlobs.find(&entry);
+ ASSERT_NE(it, encryptedBlobs.end());
+ const vector<vector<uint8_t>>& encryptedChunks = it->second;
+
+ vector<uint8_t> content;
+ for (const auto& encryptedChunk : encryptedChunks) {
+ vector<uint8_t> chunk;
+ ASSERT_TRUE(credential->retrieveEntryValue(encryptedChunk, &chunk).isOk());
+ content.insert(content.end(), chunk.begin(), chunk.end());
+ }
+ EXPECT_EQ(content, entry.valueCbor);
+ }
+
+ vector<uint8_t> mac;
+ vector<uint8_t> ecdsaSignature;
+ vector<uint8_t> deviceNameSpacesEncoded;
+ status = credential->finishRetrievalWithSignature(&mac, &deviceNameSpacesEncoded,
+ &ecdsaSignature);
+ ASSERT_TRUE(status.isOk()) << status.exceptionCode() << ": " << status.exceptionMessage();
+ // MACing should NOT work since we're not using session encryption
+ ASSERT_EQ(0, mac.size());
+
+ // ECDSA signatures should work, however. Check this.
+ ASSERT_GT(ecdsaSignature.size(), 0);
+
+ cborPretty = cppbor::prettyPrint(deviceNameSpacesEncoded, 32, {});
+ ASSERT_EQ(
+ "{\n"
+ " 'PersonalData' : {\n"
+ " 'Last name' : 'Turing',\n"
+ " 'Birth date' : '19120623',\n"
+ " 'First name' : 'Alan',\n"
+ " },\n"
+ "}",
+ cborPretty);
+
+ string docType = "org.iso.18013-5.2019.mdl";
+
+ vector<uint8_t> encodedDeviceAuthentication =
+ cppbor::Array()
+ .add("DeviceAuthentication")
+ .add(sessionTranscript.clone())
+ .add(docType)
+ .add(cppbor::SemanticTag(24, deviceNameSpacesEncoded))
+ .encode();
+ vector<uint8_t> deviceAuthenticationBytes =
+ cppbor::SemanticTag(24, encodedDeviceAuthentication).encode();
+ EXPECT_TRUE(support::coseCheckEcDsaSignature(ecdsaSignature,
+ deviceAuthenticationBytes, // Detached content
+ signingPubKey.value()));
}
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EndToEndTests);
diff --git a/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/EnergyConsumerType.aidl b/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/EnergyConsumerType.aidl
index ce3e1f5..28bd59e 100644
--- a/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/EnergyConsumerType.aidl
+++ b/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/EnergyConsumerType.aidl
@@ -40,4 +40,5 @@
GNSS = 4,
MOBILE_RADIO = 5,
WIFI = 6,
+ CAMERA = 7,
}
diff --git a/power/stats/aidl/android/hardware/power/stats/EnergyConsumerType.aidl b/power/stats/aidl/android/hardware/power/stats/EnergyConsumerType.aidl
index d871ced..ea70785 100644
--- a/power/stats/aidl/android/hardware/power/stats/EnergyConsumerType.aidl
+++ b/power/stats/aidl/android/hardware/power/stats/EnergyConsumerType.aidl
@@ -26,4 +26,5 @@
GNSS,
MOBILE_RADIO,
WIFI,
+ CAMERA,
}
diff --git a/radio/aidl/Android.bp b/radio/aidl/Android.bp
index 9dbe09a..930b6d4 100644
--- a/radio/aidl/Android.bp
+++ b/radio/aidl/Android.bp
@@ -12,6 +12,7 @@
vendor_available: true,
host_supported: true,
srcs: ["android/hardware/radio/*.aidl"],
+ frozen: false,
stability: "vintf",
backend: {
cpp: {
@@ -35,6 +36,7 @@
vendor_available: true,
host_supported: true,
srcs: ["android/hardware/radio/config/*.aidl"],
+ frozen: false,
stability: "vintf",
imports: ["android.hardware.radio-V2"],
backend: {
diff --git a/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/SimSlotStatus.aidl b/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/SimSlotStatus.aidl
index da894cd..c264dfd 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/SimSlotStatus.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/SimSlotStatus.aidl
@@ -38,5 +38,5 @@
String atr;
String eid;
android.hardware.radio.config.SimPortInfo[] portInfo;
- android.hardware.radio.config.MultipleEnabledProfilesMode supportedMepMode;
+ android.hardware.radio.config.MultipleEnabledProfilesMode supportedMepMode = android.hardware.radio.config.MultipleEnabledProfilesMode.NONE;
}
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 5aed024..be06c47 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
@@ -78,6 +78,7 @@
oneway void cancelEmergencyNetworkScan(int serial, boolean resetScan);
oneway void exitEmergencyMode(in int serial);
oneway void setNullCipherAndIntegrityEnabled(in int serial, in boolean enabled);
+ 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);
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 ccdfde6..009fdd3 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
@@ -77,6 +77,7 @@
oneway void exitEmergencyModeResponse(in android.hardware.radio.RadioResponseInfo info);
oneway void cancelEmergencyNetworkScanResponse(in android.hardware.radio.RadioResponseInfo info);
oneway void setNullCipherAndIntegrityEnabledResponse(in android.hardware.radio.RadioResponseInfo info);
+ 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);
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/CardStatus.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/CardStatus.aidl
index 9000d43..46cb7be 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/CardStatus.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/CardStatus.aidl
@@ -44,6 +44,7 @@
String iccid;
String eid;
android.hardware.radio.config.SlotPortMapping slotMap;
+ android.hardware.radio.config.MultipleEnabledProfilesMode supportedMepMode = android.hardware.radio.config.MultipleEnabledProfilesMode.NONE;
const int STATE_ABSENT = 0;
const int STATE_PRESENT = 1;
const int STATE_ERROR = 2;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/SimApdu.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/SimApdu.aidl
index 2f2e07b..c391e5a 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/SimApdu.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/SimApdu.aidl
@@ -41,5 +41,5 @@
int p2;
int p3;
String data;
- boolean isEs10;
+ boolean isEs10 = false;
}
diff --git a/radio/aidl/android/hardware/radio/config/SimSlotStatus.aidl b/radio/aidl/android/hardware/radio/config/SimSlotStatus.aidl
index 73f2954..6a36d5e 100644
--- a/radio/aidl/android/hardware/radio/config/SimSlotStatus.aidl
+++ b/radio/aidl/android/hardware/radio/config/SimSlotStatus.aidl
@@ -54,7 +54,8 @@
*/
SimPortInfo[] portInfo;
/**
- * Jointly supported Multiple Enabled Profiles(MEP) mode as per SGP.22 V3.0
+ * Jointly supported Multiple Enabled Profiles(MEP) mode as per SGP.22 V3.0. Should always
+ * report proper MEP mode irrespective of whether the slot is active or inactive.
*/
- MultipleEnabledProfilesMode supportedMepMode;
+ MultipleEnabledProfilesMode supportedMepMode = MultipleEnabledProfilesMode.NONE;
}
diff --git a/radio/aidl/android/hardware/radio/network/IRadioNetwork.aidl b/radio/aidl/android/hardware/radio/network/IRadioNetwork.aidl
index 70427f8..38772cd 100644
--- a/radio/aidl/android/hardware/radio/network/IRadioNetwork.aidl
+++ b/radio/aidl/android/hardware/radio/network/IRadioNetwork.aidl
@@ -510,6 +510,21 @@
void setNullCipherAndIntegrityEnabled(in int serial, in boolean enabled);
/**
+ * Get whether null encryption and integrity modes are enabled.
+ *
+ * Null ciphering and integrity modes include, (but are not limited to):
+ * 2G: A5/0, GAE0 (no integrity algorithm supported)
+ * 3G: UEA0 and UIA0
+ * 4G: EEA0 and EIA
+ * 5G: NEA0 and NIA0
+ *
+ * @param serial Serial number of the request.
+ *
+ * Response callback is IRadioNetworkResponse.isNullCipherAndIntegrityEnabledResponse()
+ */
+ void isNullCipherAndIntegrityEnabled(in int serial);
+
+ /**
* Checks whether N1 mode (access to 5G core network) is enabled or not.
*
* @param serial Serial number of request.
diff --git a/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl b/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl
index 3fa6521..399dbb7 100644
--- a/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl
+++ b/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl
@@ -626,6 +626,17 @@
void setNullCipherAndIntegrityEnabledResponse(in RadioResponseInfo info);
/**
+ * @param info Response info struct containing response type, serial no. and error
+ * @param enabled the last known state of null ciphering and integrity algorithms
+ *
+ * Valid errors returned:
+ * RadioError:NONE
+ * RadioError:RADIO_NOT_AVAILABLE
+ * RadioError:MODEM_ERR
+ */
+ void isNullCipherAndIntegrityEnabledResponse(in RadioResponseInfo info, in boolean isEnabled);
+
+ /**
* Response of isN1ModeEnabled.
* This is an optional API.
*
diff --git a/radio/aidl/android/hardware/radio/sim/CardStatus.aidl b/radio/aidl/android/hardware/radio/sim/CardStatus.aidl
index a14cf7d..1419c51 100644
--- a/radio/aidl/android/hardware/radio/sim/CardStatus.aidl
+++ b/radio/aidl/android/hardware/radio/sim/CardStatus.aidl
@@ -16,6 +16,7 @@
package android.hardware.radio.sim;
+import android.hardware.radio.config.MultipleEnabledProfilesMode;
import android.hardware.radio.config.SlotPortMapping;
import android.hardware.radio.sim.AppStatus;
import android.hardware.radio.sim.PinState;
@@ -93,4 +94,8 @@
* PortId is the id (enumerated value) for the associated port available on the SIM.
*/
SlotPortMapping slotMap;
+ /**
+ * Jointly supported Multiple Enabled Profiles(MEP) mode as per SGP.22 V3.0
+ */
+ MultipleEnabledProfilesMode supportedMepMode = MultipleEnabledProfilesMode.NONE;
}
diff --git a/radio/aidl/android/hardware/radio/sim/SimApdu.aidl b/radio/aidl/android/hardware/radio/sim/SimApdu.aidl
index 4759e2e..9799f2b 100644
--- a/radio/aidl/android/hardware/radio/sim/SimApdu.aidl
+++ b/radio/aidl/android/hardware/radio/sim/SimApdu.aidl
@@ -53,5 +53,5 @@
* isEs10 indicates that the current streaming APDU contains an ES10 command or it is a regular
* APDU. (As per spec SGP.22 V3.0, ES10 commands needs to be sent over command port of MEP-A1)
*/
- boolean isEs10;
+ boolean isEs10 = false;
}
diff --git a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioNetwork.h b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioNetwork.h
index b446103..45c1645 100644
--- a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioNetwork.h
+++ b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioNetwork.h
@@ -103,6 +103,7 @@
::ndk::ScopedAStatus setN1ModeEnabled(int32_t serial, bool enable) override;
::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;
diff --git a/radio/aidl/compat/libradiocompat/network/RadioNetwork.cpp b/radio/aidl/compat/libradiocompat/network/RadioNetwork.cpp
index 730b5dd..5e44fff 100644
--- a/radio/aidl/compat/libradiocompat/network/RadioNetwork.cpp
+++ b/radio/aidl/compat/libradiocompat/network/RadioNetwork.cpp
@@ -347,6 +347,13 @@
return ok();
}
+ScopedAStatus RadioNetwork::isNullCipherAndIntegrityEnabled(int32_t serial) {
+ LOG_CALL << serial;
+ LOG(ERROR) << " isNullCipherAndIntegrityEnabled is unsupported by HIDL HALs";
+ respond()->isNullCipherAndIntegrityEnabledResponse(notSupported(serial), true);
+ return ok();
+}
+
ScopedAStatus RadioNetwork::isN1ModeEnabled(int32_t serial) {
LOG_CALL << serial;
LOG(ERROR) << " isN1ModeEnabled is unsupported by HIDL HALs";
diff --git a/radio/aidl/vts/radio_network_response.cpp b/radio/aidl/vts/radio_network_response.cpp
index 4f0e4f3..35e4202 100644
--- a/radio/aidl/vts/radio_network_response.cpp
+++ b/radio/aidl/vts/radio_network_response.cpp
@@ -301,6 +301,13 @@
return ndk::ScopedAStatus::ok();
}
+ndk::ScopedAStatus RadioNetworkResponse::isNullCipherAndIntegrityEnabledResponse(
+ const RadioResponseInfo& info, bool /*isEnabled*/) {
+ rspInfo = info;
+ parent_network.notify(info.serial);
+ return ndk::ScopedAStatus::ok();
+}
+
ndk::ScopedAStatus RadioNetworkResponse::isN1ModeEnabledResponse(
const RadioResponseInfo& info, bool /*isEnabled*/) {
rspInfo = info;
diff --git a/radio/aidl/vts/radio_network_test.cpp b/radio/aidl/vts/radio_network_test.cpp
index e7a48bc..43a4737 100644
--- a/radio/aidl/vts/radio_network_test.cpp
+++ b/radio/aidl/vts/radio_network_test.cpp
@@ -1979,3 +1979,23 @@
{RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::MODEM_ERR}));
LOG(DEBUG) << "setNullCipherAndIntegrityEnabled finished";
}
+
+/**
+ * Test IRadioNetwork.isNullCipherAndIntegrityEnabled() for the response returned.
+ */
+TEST_P(RadioNetworkTest, isNullCipherAndIntegrityEnabled) {
+ LOG(DEBUG) << "isNullCipherAndIntegrityEnabled";
+ serial = GetRandomSerialNumber();
+
+ ndk::ScopedAStatus res = radio_network->isNullCipherAndIntegrityEnabled(serial);
+ ASSERT_OK(res);
+
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
+ EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
+
+ ASSERT_TRUE(CheckAnyOfErrors(
+ radioRsp_network->rspInfo.error,
+ {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::MODEM_ERR}));
+ LOG(DEBUG) << "isNullCipherAndIntegrityEnabled finished";
+}
diff --git a/radio/aidl/vts/radio_network_utils.h b/radio/aidl/vts/radio_network_utils.h
index 92dcb1f..496ec03 100644
--- a/radio/aidl/vts/radio_network_utils.h
+++ b/radio/aidl/vts/radio_network_utils.h
@@ -162,6 +162,9 @@
virtual ndk::ScopedAStatus setNullCipherAndIntegrityEnabledResponse(
const RadioResponseInfo& info) override;
+ virtual ndk::ScopedAStatus isNullCipherAndIntegrityEnabledResponse(
+ const RadioResponseInfo& info, const bool isEnabled) override;
+
virtual ndk::ScopedAStatus isN1ModeEnabledResponse(
const RadioResponseInfo& info, bool isEnabled) override;
diff --git a/security/keymint/aidl/default/android.hardware.hardware_keystore.xml b/security/keymint/aidl/default/android.hardware.hardware_keystore.xml
index 2ebf1fe..4c75596 100644
--- a/security/keymint/aidl/default/android.hardware.hardware_keystore.xml
+++ b/security/keymint/aidl/default/android.hardware.hardware_keystore.xml
@@ -14,5 +14,5 @@
limitations under the License.
-->
<permissions>
- <feature name="android.hardware.hardware_keystore" version="200" />
+ <feature name="android.hardware.hardware_keystore" version="300" />
</permissions>
diff --git a/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/ISensors.aidl b/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/ISensors.aidl
index f60f5bb..b26040b 100644
--- a/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/ISensors.aidl
+++ b/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/ISensors.aidl
@@ -58,6 +58,8 @@
const int DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_DATA = 24;
const int DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_RESERVED = 88;
const int DIRECT_REPORT_SENSOR_EVENT_TOTAL_LENGTH = 104;
+ const int RUNTIME_SENSORS_HANDLE_BASE = 1593835520;
+ const int RUNTIME_SENSORS_HANDLE_END = 1610612735;
@Backing(type="int") @VintfStability
enum RateLevel {
STOP = 0,
diff --git a/sensors/aidl/android/hardware/sensors/ISensors.aidl b/sensors/aidl/android/hardware/sensors/ISensors.aidl
index 2c68489..5e276dd 100644
--- a/sensors/aidl/android/hardware/sensors/ISensors.aidl
+++ b/sensors/aidl/android/hardware/sensors/ISensors.aidl
@@ -371,4 +371,13 @@
const int DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_DATA = 0x18;
const int DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_RESERVED = 0x58;
const int DIRECT_REPORT_SENSOR_EVENT_TOTAL_LENGTH = 104;
+
+ /**
+ * Constants related to reserved sensor handle ranges.
+ *
+ * The following range (inclusive) is reserved for usage by the system for
+ * runtime sensors.
+ */
+ const int RUNTIME_SENSORS_HANDLE_BASE = 0x5F000000;
+ const int RUNTIME_SENSORS_HANDLE_END = 0x5FFFFFFF;
}
diff --git a/sensors/aidl/convert/Android.bp b/sensors/aidl/convert/Android.bp
index 0b31597..53060b9 100644
--- a/sensors/aidl/convert/Android.bp
+++ b/sensors/aidl/convert/Android.bp
@@ -35,7 +35,7 @@
"libhardware",
"libbase",
"libutils",
- "android.hardware.sensors-V1-ndk",
+ "android.hardware.sensors-V2-ndk",
],
whole_static_libs: [
"sensors_common_convert",
diff --git a/sensors/aidl/default/Android.bp b/sensors/aidl/default/Android.bp
index 3c66744..16b4d35 100644
--- a/sensors/aidl/default/Android.bp
+++ b/sensors/aidl/default/Android.bp
@@ -41,7 +41,7 @@
"libfmq",
"libpower",
"libbinder_ndk",
- "android.hardware.sensors-V1-ndk",
+ "android.hardware.sensors-V2-ndk",
],
export_include_dirs: ["include"],
srcs: [
@@ -68,7 +68,7 @@
"libcutils",
"liblog",
"libutils",
- "android.hardware.sensors-V1-ndk",
+ "android.hardware.sensors-V2-ndk",
],
static_libs: [
"libsensorsexampleimpl",
diff --git a/sensors/aidl/default/multihal/Android.bp b/sensors/aidl/default/multihal/Android.bp
index eee1062..a20d6d7 100644
--- a/sensors/aidl/default/multihal/Android.bp
+++ b/sensors/aidl/default/multihal/Android.bp
@@ -38,7 +38,7 @@
"android.hardware.sensors@1.0",
"android.hardware.sensors@2.0",
"android.hardware.sensors@2.1",
- "android.hardware.sensors-V1-ndk",
+ "android.hardware.sensors-V2-ndk",
],
export_include_dirs: ["include"],
srcs: [
diff --git a/sensors/aidl/default/sensors-default.xml b/sensors/aidl/default/sensors-default.xml
index 7898a6b..36b28ed 100644
--- a/sensors/aidl/default/sensors-default.xml
+++ b/sensors/aidl/default/sensors-default.xml
@@ -1,7 +1,7 @@
<manifest version="1.0" type="device">
<hal format="aidl">
<name>android.hardware.sensors</name>
- <version>1</version>
+ <version>2</version>
<fqname>ISensors/default</fqname>
</hal>
</manifest>
diff --git a/sensors/aidl/multihal/Android.bp b/sensors/aidl/multihal/Android.bp
index 6d35daf..522d305 100644
--- a/sensors/aidl/multihal/Android.bp
+++ b/sensors/aidl/multihal/Android.bp
@@ -40,7 +40,7 @@
"android.hardware.sensors@2.0-ScopedWakelock",
"android.hardware.sensors@2.0",
"android.hardware.sensors@2.1",
- "android.hardware.sensors-V1-ndk",
+ "android.hardware.sensors-V2-ndk",
"libbase",
"libcutils",
"libfmq",
diff --git a/sensors/aidl/multihal/android.hardware.sensors-multihal.xml b/sensors/aidl/multihal/android.hardware.sensors-multihal.xml
index d78edff..5da4fbd 100644
--- a/sensors/aidl/multihal/android.hardware.sensors-multihal.xml
+++ b/sensors/aidl/multihal/android.hardware.sensors-multihal.xml
@@ -17,7 +17,7 @@
<manifest version="1.0" type="device">
<hal format="aidl">
<name>android.hardware.sensors</name>
- <version>1</version>
+ <version>2</version>
<fqname>ISensors/default</fqname>
</hal>
</manifest>
diff --git a/sensors/aidl/vts/Android.bp b/sensors/aidl/vts/Android.bp
index f3972ec..c17a558 100644
--- a/sensors/aidl/vts/Android.bp
+++ b/sensors/aidl/vts/Android.bp
@@ -41,7 +41,7 @@
"android.hardware.common.fmq-V1-ndk",
],
static_libs: [
- "android.hardware.sensors-V1-ndk",
+ "android.hardware.sensors-V2-ndk",
"VtsHalSensorsTargetTestUtils",
"libaidlcommonsupport",
],
diff --git a/sensors/aidl/vts/VtsAidlHalSensorsTargetTest.cpp b/sensors/aidl/vts/VtsAidlHalSensorsTargetTest.cpp
index d536e29..ad58e21 100644
--- a/sensors/aidl/vts/VtsAidlHalSensorsTargetTest.cpp
+++ b/sensors/aidl/vts/VtsAidlHalSensorsTargetTest.cpp
@@ -560,10 +560,15 @@
EXPECT_NO_FATAL_FAILURE(assertTypeMatchStringType(info.type, info.typeAsString));
}
- // Test if all sensor has name and vendor
+ // Test if all sensors have name and vendor
EXPECT_FALSE(info.name.empty());
EXPECT_FALSE(info.vendor.empty());
+ // Make sure that the sensor handle is not within the reserved range for runtime
+ // sensors.
+ EXPECT_FALSE(ISensors::RUNTIME_SENSORS_HANDLE_BASE <= info.sensorHandle &&
+ info.sensorHandle <= ISensors::RUNTIME_SENSORS_HANDLE_END);
+
// Make sure that sensors of the same type have a unique name.
std::vector<std::string>& v = sensorTypeNameMap[static_cast<int32_t>(info.type)];
bool isUniqueName = std::find(v.begin(), v.end(), info.name) == v.end();
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 647891f..f800e8f 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
@@ -59,6 +59,7 @@
@PropagateAllowBlocking android.hardware.wifi.IWifiStaIface getStaIface(in String ifname);
String[] getStaIfaceNames();
android.hardware.wifi.WifiRadioCombinationMatrix getSupportedRadioCombinationsMatrix();
+ android.hardware.wifi.WifiChipCapabilities getWifiChipCapabilities();
android.hardware.wifi.WifiUsableChannel[] getUsableChannels(in android.hardware.wifi.WifiBand band, in android.hardware.wifi.WifiIfaceMode ifaceModeMask, in android.hardware.wifi.IWifiChip.UsableChannelFilter filterMask);
void registerEventCallback(in android.hardware.wifi.IWifiChipEventCallback callback);
void removeApIface(in String ifname);
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiStaIface.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiStaIface.aidl
index 2f0dfa1..ac5b93b 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiStaIface.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiStaIface.aidl
@@ -61,6 +61,7 @@
void stopBackgroundScan(in int cmdId);
void stopRssiMonitoring(in int cmdId);
void stopSendingKeepAlivePackets(in int cmdId);
+ void setDtimMultiplier(in int multiplier);
@Backing(type="int") @VintfStability
enum StaIfaceCapabilityMask {
APF = 1,
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiChipCapabilities.aidl
similarity index 75%
copy from audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
copy to wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiChipCapabilities.aidl
index 8ad4848..48dc8e0 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiChipCapabilities.aidl
@@ -31,27 +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.audio.effect;
+package android.hardware.wifi;
@VintfStability
-union Reverb {
- android.hardware.audio.effect.VendorExtension vendor;
- int roomLevelMb;
- int roomHfLevelMb;
- int decayTimeMs;
- int decayHfRatioPm;
- int levelMb;
- int delayMs;
- int diffusionPm;
- int densityPm;
- boolean bypass;
- @VintfStability
- union Id {
- int vendorExtensionTag;
- android.hardware.audio.effect.Reverb.Tag commonTag;
- }
- @VintfStability
- parcelable Capability {
- android.hardware.audio.effect.VendorExtension extension;
- int maxDecayTimeMs;
- }
+parcelable WifiChipCapabilities {
+ int maxMloLinkCount;
+ int maxConcurrentTdlsSessionCount;
}
diff --git a/wifi/aidl/android/hardware/wifi/IWifiChip.aidl b/wifi/aidl/android/hardware/wifi/IWifiChip.aidl
index fe9a6f3..64692af 100644
--- a/wifi/aidl/android/hardware/wifi/IWifiChip.aidl
+++ b/wifi/aidl/android/hardware/wifi/IWifiChip.aidl
@@ -25,6 +25,7 @@
import android.hardware.wifi.IfaceConcurrencyType;
import android.hardware.wifi.IfaceType;
import android.hardware.wifi.WifiBand;
+import android.hardware.wifi.WifiChipCapabilities;
import android.hardware.wifi.WifiDebugHostWakeReasonStats;
import android.hardware.wifi.WifiDebugRingBufferStatus;
import android.hardware.wifi.WifiDebugRingBufferVerboseLevel;
@@ -785,6 +786,18 @@
WifiRadioCombinationMatrix getSupportedRadioCombinationsMatrix();
/**
+ * Get capabilities supported by this chip.
+ *
+ * @return Chip capabilities represented by |WifiChipCapabilities|.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.FAILURE_UNKNOWN|
+ *
+ */
+ WifiChipCapabilities getWifiChipCapabilities();
+
+ /**
* Retrieve a list of usable Wifi channels for the specified band &
* operational modes.
*
diff --git a/wifi/aidl/android/hardware/wifi/IWifiStaIface.aidl b/wifi/aidl/android/hardware/wifi/IWifiStaIface.aidl
index 2dd57b2..e6218e6 100644
--- a/wifi/aidl/android/hardware/wifi/IWifiStaIface.aidl
+++ b/wifi/aidl/android/hardware/wifi/IWifiStaIface.aidl
@@ -552,4 +552,20 @@
* |WifiStatusCode.ERROR_UNKNOWN|
*/
void stopSendingKeepAlivePackets(in int cmdId);
+
+ /**
+ * Set DTIM multiplier used when the system is in the suspended mode.
+ * When STA is in the power saving mode and system is suspended,
+ * the wake up interval will be set to:
+ * 1) multiplier * DTIM period if multiplier > 0.
+ * 2) the driver default value if multiplier <= 0.
+ * Some implementations may apply an additional cap to wake up interval in the case of 1).
+ *
+ * @param multiplier integer DTIM multiplier value to set.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ void setDtimMultiplier(in int multiplier);
}
diff --git a/wifi/aidl/android/hardware/wifi/WifiChipCapabilities.aidl b/wifi/aidl/android/hardware/wifi/WifiChipCapabilities.aidl
new file mode 100644
index 0000000..f65d49a
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/WifiChipCapabilities.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * WifiChipCapabilities captures various Wifi chip capability params.
+ */
+@VintfStability
+parcelable WifiChipCapabilities {
+ /**
+ * Maximum number of links used in Multi-Link Operation. The maximum
+ * number of links used for MLO can be different from the number of
+ * radios supported by the chip.
+ *
+ * This is a static configuration of the chip.
+ */
+ int maxMloLinkCount;
+ /**
+ * Maximum number of concurrent TDLS sessions that can be enabled
+ * by framework via ISupplicantStaIface#initiateTdlsSetup().
+ */
+ int maxConcurrentTdlsSessionCount;
+}
diff --git a/wifi/aidl/default/aidl_struct_util.cpp b/wifi/aidl/default/aidl_struct_util.cpp
index 07612b6..ec8b396 100644
--- a/wifi/aidl/default/aidl_struct_util.cpp
+++ b/wifi/aidl/default/aidl_struct_util.cpp
@@ -2768,6 +2768,15 @@
return true;
}
+bool convertLegacyWifiChipCapabilitiesToAidl(
+ const legacy_hal::wifi_chip_capabilities& legacy_chip_capabilities,
+ WifiChipCapabilities& aidl_chip_capabilities) {
+ aidl_chip_capabilities.maxMloLinkCount = legacy_chip_capabilities.max_mlo_link_count;
+ aidl_chip_capabilities.maxConcurrentTdlsSessionCount =
+ legacy_chip_capabilities.max_concurrent_tdls_session_count;
+ return true;
+}
+
} // namespace aidl_struct_util
} // namespace wifi
} // namespace hardware
diff --git a/wifi/aidl/default/aidl_struct_util.h b/wifi/aidl/default/aidl_struct_util.h
index 4ebfc10..d8e1fd4 100644
--- a/wifi/aidl/default/aidl_struct_util.h
+++ b/wifi/aidl/default/aidl_struct_util.h
@@ -171,6 +171,9 @@
StaPeerInfo* aidl_peer_info_stats);
bool convertLegacyWifiRateInfoToAidl(const legacy_hal::wifi_rate& legacy_rate,
WifiRateInfo* aidl_rate);
+bool convertLegacyWifiChipCapabilitiesToAidl(
+ const legacy_hal::wifi_chip_capabilities& legacy_chip_capabilities,
+ WifiChipCapabilities& aidl_chip_capabilities);
} // 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 076f351..4061699 100644
--- a/wifi/aidl/default/wifi_chip.cpp
+++ b/wifi/aidl/default/wifi_chip.cpp
@@ -680,6 +680,11 @@
&WifiChip::getSupportedRadioCombinationsMatrixInternal, _aidl_return);
}
+ndk::ScopedAStatus WifiChip::getWifiChipCapabilities(WifiChipCapabilities* _aidl_return) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::getWifiChipCapabilitiesInternal, _aidl_return);
+}
+
void WifiChip::invalidateAndRemoveAllIfaces() {
invalidateAndClearBridgedApAll();
invalidateAndClearAll(ap_ifaces_);
@@ -1403,6 +1408,26 @@
return {aidl_matrix, ndk::ScopedAStatus::ok()};
}
+std::pair<WifiChipCapabilities, ndk::ScopedAStatus> WifiChip::getWifiChipCapabilitiesInternal() {
+ legacy_hal::wifi_error legacy_status;
+ legacy_hal::wifi_chip_capabilities legacy_chip_capabilities;
+ std::tie(legacy_status, legacy_chip_capabilities) =
+ legacy_hal_.lock()->getWifiChipCapabilities();
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ LOG(ERROR) << "Failed to get chip capabilities from legacy HAL: "
+ << legacyErrorToString(legacy_status);
+ return {WifiChipCapabilities(), createWifiStatusFromLegacyError(legacy_status)};
+ }
+ WifiChipCapabilities aidl_chip_capabilities;
+ if (!aidl_struct_util::convertLegacyWifiChipCapabilitiesToAidl(legacy_chip_capabilities,
+ aidl_chip_capabilities)) {
+ LOG(ERROR) << "Failed convertLegacyWifiChipCapabilitiesToAidl() ";
+ return {WifiChipCapabilities(), createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS)};
+ }
+
+ return {aidl_chip_capabilities, ndk::ScopedAStatus::ok()};
+}
+
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 59eaa4a..7b04e85 100644
--- a/wifi/aidl/default/wifi_chip.h
+++ b/wifi/aidl/default/wifi_chip.h
@@ -144,6 +144,7 @@
ndk::ScopedAStatus triggerSubsystemRestart() override;
ndk::ScopedAStatus getSupportedRadioCombinationsMatrix(
WifiRadioCombinationMatrix* _aidl_return) override;
+ ndk::ScopedAStatus getWifiChipCapabilities(WifiChipCapabilities* _aidl_return) override;
binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
private:
@@ -250,6 +251,7 @@
ndk::ScopedAStatus triggerSubsystemRestartInternal();
std::pair<WifiRadioCombinationMatrix, ndk::ScopedAStatus>
getSupportedRadioCombinationsMatrixInternal();
+ std::pair<WifiChipCapabilities, ndk::ScopedAStatus> getWifiChipCapabilitiesInternal();
void setWeakPtr(std::weak_ptr<WifiChip> ptr);
int32_t chip_id_;
diff --git a/wifi/aidl/default/wifi_legacy_hal.cpp b/wifi/aidl/default/wifi_legacy_hal.cpp
index 43e73ca..e4883d1 100644
--- a/wifi/aidl/default/wifi_legacy_hal.cpp
+++ b/wifi/aidl/default/wifi_legacy_hal.cpp
@@ -1609,6 +1609,13 @@
return status;
}
+std::pair<wifi_error, wifi_chip_capabilities> WifiLegacyHal::getWifiChipCapabilities() {
+ wifi_chip_capabilities chip_capabilities;
+ wifi_error status =
+ global_func_table_.wifi_get_chip_capabilities(global_handle_, &chip_capabilities);
+ return {status, chip_capabilities};
+}
+
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 cd8c0b1..33ed359 100644
--- a/wifi/aidl/default/wifi_legacy_hal.h
+++ b/wifi/aidl/default/wifi_legacy_hal.h
@@ -232,6 +232,7 @@
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_DUAL_STA_NON_TRANSIENT_UNBIASED;
@@ -693,6 +694,7 @@
wifi_error enableWifiTxPowerLimits(const std::string& iface_name, bool enable);
wifi_error getWifiCachedScanResults(const std::string& iface_name,
const CachedScanResultsCallbackHandlers& handler);
+ std::pair<wifi_error, wifi_chip_capabilities> getWifiChipCapabilities();
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 cff7f69..7777894 100644
--- a/wifi/aidl/default/wifi_legacy_hal_stubs.cpp
+++ b/wifi/aidl/default/wifi_legacy_hal_stubs.cpp
@@ -167,6 +167,7 @@
populateStubFor(&hal_fn->wifi_chre_register_handler);
populateStubFor(&hal_fn->wifi_enable_tx_power_limits);
populateStubFor(&hal_fn->wifi_get_cached_scan_results);
+ populateStubFor(&hal_fn->wifi_get_chip_capabilities);
return true;
}
diff --git a/wifi/aidl/default/wifi_sta_iface.cpp b/wifi/aidl/default/wifi_sta_iface.cpp
index ce90349..57384bf 100644
--- a/wifi/aidl/default/wifi_sta_iface.cpp
+++ b/wifi/aidl/default/wifi_sta_iface.cpp
@@ -222,6 +222,11 @@
&WifiStaIface::setScanModeInternal, in_enable);
}
+ndk::ScopedAStatus WifiStaIface::setDtimMultiplier(int32_t in_multiplier) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::setDtimMultiplierInternal, in_multiplier);
+}
+
std::pair<std::string, ndk::ScopedAStatus> WifiStaIface::getNameInternal() {
return {ifname_, ndk::ScopedAStatus::ok()};
}
@@ -552,6 +557,11 @@
return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
}
+ndk::ScopedAStatus WifiStaIface::setDtimMultiplierInternal(const int multiplier) {
+ legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->setDtimConfig(ifname_, multiplier);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/aidl/default/wifi_sta_iface.h b/wifi/aidl/default/wifi_sta_iface.h
index 8ac3470..2e4403a 100644
--- a/wifi/aidl/default/wifi_sta_iface.h
+++ b/wifi/aidl/default/wifi_sta_iface.h
@@ -92,6 +92,7 @@
ndk::ScopedAStatus setMacAddress(const std::array<uint8_t, 6>& in_mac) override;
ndk::ScopedAStatus getFactoryMacAddress(std::array<uint8_t, 6>* _aidl_return) override;
ndk::ScopedAStatus setScanMode(bool in_enable) override;
+ ndk::ScopedAStatus setDtimMultiplier(int32_t in_multiplier) override;
private:
// Corresponding worker functions for the AIDL methods.
@@ -133,6 +134,7 @@
ndk::ScopedAStatus setMacAddressInternal(const std::array<uint8_t, 6>& mac);
std::pair<std::array<uint8_t, 6>, ndk::ScopedAStatus> getFactoryMacAddressInternal();
ndk::ScopedAStatus setScanModeInternal(bool enable);
+ ndk::ScopedAStatus setDtimMultiplierInternal(const int multiplier);
void setWeakPtr(std::weak_ptr<WifiStaIface> ptr);
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaNetworkCallback.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaNetworkCallback.aidl
index 6276a35..f9a078b 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaNetworkCallback.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaNetworkCallback.aidl
@@ -39,4 +39,5 @@
oneway void onNetworkEapSimUmtsAuthRequest(in android.hardware.wifi.supplicant.NetworkRequestEapSimUmtsAuthParams params);
oneway void onTransitionDisable(in android.hardware.wifi.supplicant.TransitionDisableIndication ind);
oneway void onServerCertificateAvailable(in int depth, in byte[] subject, in byte[] certHash, in byte[] certBlob);
+ oneway void onPermanentIdReqDenied();
}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaNetworkCallback.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaNetworkCallback.aidl
index de7b675..4f892be 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaNetworkCallback.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaNetworkCallback.aidl
@@ -71,4 +71,11 @@
*/
void onServerCertificateAvailable(
in int depth, in byte[] subject, in byte[] certHash, in byte[] certBlob);
+
+ /**
+ * Used to notify the AT_PERMANENT_ID_REQ denied event.
+ *
+ * In strict conservative mode, AT_PERMANENT_ID_REQ is denied from eap_peer side.
+ */
+ void onPermanentIdReqDenied();
}
diff --git a/wifi/supplicant/aidl/vts/functional/supplicant_sta_network_aidl_test.cpp b/wifi/supplicant/aidl/vts/functional/supplicant_sta_network_aidl_test.cpp
index 6ff64a5..0aebe6d 100644
--- a/wifi/supplicant/aidl/vts/functional/supplicant_sta_network_aidl_test.cpp
+++ b/wifi/supplicant/aidl/vts/functional/supplicant_sta_network_aidl_test.cpp
@@ -100,6 +100,7 @@
const std::vector<uint8_t>& /* certBlob */) override {
return ndk::ScopedAStatus::ok();
}
+ ::ndk::ScopedAStatus onPermanentIdReqDenied() override { return ndk::ScopedAStatus::ok(); }
};
class SupplicantStaNetworkAidlTest