Merge "Change min/max values to match config array in DefaultProperties.json"
diff --git a/audio/aidl/Android.bp b/audio/aidl/Android.bp
index 92d7d54..7d474b2 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",
],
@@ -113,18 +114,25 @@
"android/hardware/audio/core/AudioRoute.aidl",
"android/hardware/audio/core/IConfig.aidl",
"android/hardware/audio/core/IModule.aidl",
+ "android/hardware/audio/core/ISoundDose.aidl",
+ "android/hardware/audio/core/IStreamCallback.aidl",
+ "android/hardware/audio/core/IStreamCommon.aidl",
"android/hardware/audio/core/IStreamIn.aidl",
"android/hardware/audio/core/IStreamOut.aidl",
"android/hardware/audio/core/ITelephony.aidl",
+ "android/hardware/audio/core/MicrophoneDynamicInfo.aidl",
+ "android/hardware/audio/core/MicrophoneInfo.aidl",
"android/hardware/audio/core/MmapBufferDescriptor.aidl",
"android/hardware/audio/core/ModuleDebug.aidl",
"android/hardware/audio/core/StreamDescriptor.aidl",
"android/hardware/audio/core/SurroundSoundConfig.aidl",
+ "android/hardware/audio/core/VendorParameter.aidl",
],
imports: [
"android.hardware.common-V2",
"android.hardware.common.fmq-V1",
"android.hardware.audio.common-V1",
+ "android.hardware.audio.effect-V1",
"android.media.audio.common.types-V2",
],
backend: {
@@ -162,6 +170,53 @@
],
}
+// Used for the standalone sounddose HAL
+aidl_interface {
+ name: "android.hardware.audio.core.sounddose",
+ defaults: [
+ "android.hardware.audio_defaults",
+ ],
+ srcs: [
+ "android/hardware/audio/core/ISoundDose.aidl",
+ ],
+ imports: [
+ "android.media.audio.common.types-V2",
+ ],
+ backend: {
+ // The C++ backend is disabled transitively due to use of FMQ by the core HAL.
+ cpp: {
+ enabled: false,
+ },
+ java: {
+ sdk_version: "module_current",
+ },
+ },
+ versions_with_info: [
+ // IMPORTANT: Update latest_android_hardware_audio_core_sounddose every time you
+ // add the latest frozen version to versions_with_info
+ ],
+}
+
+// Note: This should always be one version ahead of the last frozen version
+latest_android_hardware_audio_core_sounddose = "android.hardware.audio.core.sounddose-V1"
+
+// Modules that depend on android.hardware.audio.core.sounddose directly can include
+// the following cc_defaults to avoid explicitly managing dependency versions
+// across many scattered files.
+cc_defaults {
+ name: "latest_android_hardware_audio_core_sounddose_ndk_shared",
+ shared_libs: [
+ latest_android_hardware_audio_core_sounddose + "-ndk",
+ ],
+}
+
+cc_defaults {
+ name: "latest_android_hardware_audio_core_sounddose_ndk_static",
+ static_libs: [
+ latest_android_hardware_audio_core_sounddose + "-ndk",
+ ],
+}
+
aidl_interface {
name: "android.hardware.audio.effect",
defaults: [
@@ -174,6 +229,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",
@@ -181,8 +237,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
new file mode 100644
index 0000000..3c58324
--- /dev/null
+++ b/audio/aidl/TEST_MAPPING
@@ -0,0 +1,28 @@
+{
+ "presubmit": [
+ {
+ "name": "VtsHalAudioCoreTargetTest"
+ },
+ {
+ "name": "VtsHalAudioEffectFactoryTargetTest"
+ },
+ {
+ "name": "VtsHalAudioEffectTargetTest"
+ },
+ {
+ "name": "VtsHalDownmixTargetTest"
+ },
+ {
+ "name": "VtsHalEqualizerTargetTest"
+ },
+ {
+ "name": "VtsHalHapticGeneratorTargetTest"
+ },
+ {
+ "name": "VtsHalLoudnessEnhancerTargetTest"
+ },
+ {
+ "name": "VtsHalVisualizerTargetTest"
+ }
+ ]
+}
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.core.sounddose/current/android/hardware/audio/core/ISoundDose.aidl
similarity index 70%
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.core.sounddose/current/android/hardware/audio/core/ISoundDose.aidl
index 8ad4848..bc010ca 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.core.sounddose/current/android/hardware/audio/core/ISoundDose.aidl
@@ -31,27 +31,22 @@
// with such a backward incompatible 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.audio.core;
@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;
+interface ISoundDose {
+ void setOutputRs2(float rs2ValueDbA);
+ float getOutputRs2();
+ void registerSoundDoseCallback(in android.hardware.audio.core.ISoundDose.IHalSoundDoseCallback callback);
+ const int DEFAULT_MAX_RS2 = 100;
+ const int MIN_RS2 = 80;
@VintfStability
- union Id {
- int vendorExtensionTag;
- android.hardware.audio.effect.Reverb.Tag commonTag;
- }
- @VintfStability
- parcelable Capability {
- android.hardware.audio.effect.VendorExtension extension;
- int maxDecayTimeMs;
+ interface IHalSoundDoseCallback {
+ oneway void onMomentaryExposureWarning(float currentDbA, in android.media.audio.common.AudioDevice audioDevice);
+ oneway void onNewMelValues(in android.hardware.audio.core.ISoundDose.IHalSoundDoseCallback.MelRecord melRecord, in android.media.audio.common.AudioDevice audioDevice);
+ @VintfStability
+ parcelable MelRecord {
+ float[] melValues;
+ long timestamp;
+ }
}
}
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.core/current/android/hardware/audio/core/IModule.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IModule.aidl
index be382c5..dd2279d 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IModule.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IModule.aidl
@@ -56,9 +56,16 @@
void setMasterVolume(float volume);
boolean getMicMute();
void setMicMute(boolean mute);
+ android.hardware.audio.core.MicrophoneInfo[] getMicrophones();
void updateAudioMode(android.hardware.audio.core.AudioMode mode);
void updateScreenRotation(android.hardware.audio.core.IModule.ScreenRotation rotation);
void updateScreenState(boolean isTurnedOn);
+ @nullable android.hardware.audio.core.ISoundDose getSoundDose();
+ int generateHwAvSyncId();
+ android.hardware.audio.core.VendorParameter[] getVendorParameters(in @utf8InCpp String[] ids);
+ void setVendorParameters(in android.hardware.audio.core.VendorParameter[] parameters, boolean async);
+ void addDeviceEffect(int portConfigId, in android.hardware.audio.effect.IEffect effect);
+ void removeDeviceEffect(int portConfigId, in android.hardware.audio.effect.IEffect effect);
@VintfStability
parcelable OpenInputStreamArguments {
int portConfigId;
@@ -76,6 +83,7 @@
android.hardware.audio.common.SourceMetadata sourceMetadata;
@nullable android.media.audio.common.AudioOffloadInfo offloadInfo;
long bufferSizeFrames;
+ @nullable android.hardware.audio.core.IStreamCallback callback;
}
@VintfStability
parcelable OpenOutputStreamReturn {
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.core/current/android/hardware/audio/core/ISoundDose.aidl
similarity index 70%
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.core/current/android/hardware/audio/core/ISoundDose.aidl
index 8ad4848..bc010ca 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.core/current/android/hardware/audio/core/ISoundDose.aidl
@@ -31,27 +31,22 @@
// with such a backward incompatible 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.audio.core;
@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;
+interface ISoundDose {
+ void setOutputRs2(float rs2ValueDbA);
+ float getOutputRs2();
+ void registerSoundDoseCallback(in android.hardware.audio.core.ISoundDose.IHalSoundDoseCallback callback);
+ const int DEFAULT_MAX_RS2 = 100;
+ const int MIN_RS2 = 80;
@VintfStability
- union Id {
- int vendorExtensionTag;
- android.hardware.audio.effect.Reverb.Tag commonTag;
- }
- @VintfStability
- parcelable Capability {
- android.hardware.audio.effect.VendorExtension extension;
- int maxDecayTimeMs;
+ interface IHalSoundDoseCallback {
+ oneway void onMomentaryExposureWarning(float currentDbA, in android.media.audio.common.AudioDevice audioDevice);
+ oneway void onNewMelValues(in android.hardware.audio.core.ISoundDose.IHalSoundDoseCallback.MelRecord melRecord, in android.media.audio.common.AudioDevice audioDevice);
+ @VintfStability
+ parcelable MelRecord {
+ float[] melValues;
+ long timestamp;
+ }
}
}
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.core/current/android/hardware/audio/core/IStreamCallback.aidl
similarity index 76%
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.core/current/android/hardware/audio/core/IStreamCallback.aidl
index 8ad4848..5a2ab78 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.core/current/android/hardware/audio/core/IStreamCallback.aidl
@@ -31,27 +31,10 @@
// with such a backward incompatible 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.audio.core;
@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 IStreamCallback {
+ oneway void onTransferReady();
+ oneway void onError();
+ oneway void onDrainReady();
}
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.core/current/android/hardware/audio/core/IStreamCommon.aidl
similarity index 76%
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.core/current/android/hardware/audio/core/IStreamCommon.aidl
index 8ad4848..f0bf100 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.core/current/android/hardware/audio/core/IStreamCommon.aidl
@@ -31,27 +31,13 @@
// with such a backward incompatible 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.audio.core;
@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 IStreamCommon {
+ void close();
+ void updateHwAvSyncId(int hwAvSyncId);
+ android.hardware.audio.core.VendorParameter[] getVendorParameters(in @utf8InCpp String[] ids);
+ void setVendorParameters(in android.hardware.audio.core.VendorParameter[] parameters, boolean async);
+ void addEffect(in android.hardware.audio.effect.IEffect effect);
+ void removeEffect(in android.hardware.audio.effect.IEffect effect);
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamIn.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamIn.aidl
index d5ab3e8..68f1ff3 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamIn.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamIn.aidl
@@ -34,6 +34,25 @@
package android.hardware.audio.core;
@VintfStability
interface IStreamIn {
- void close();
+ android.hardware.audio.core.IStreamCommon getStreamCommon();
+ android.hardware.audio.core.MicrophoneDynamicInfo[] getActiveMicrophones();
+ android.hardware.audio.core.IStreamIn.MicrophoneDirection getMicrophoneDirection();
+ void setMicrophoneDirection(android.hardware.audio.core.IStreamIn.MicrophoneDirection direction);
+ float getMicrophoneFieldDimension();
+ void setMicrophoneFieldDimension(float zoom);
void updateMetadata(in android.hardware.audio.common.SinkMetadata sinkMetadata);
+ float[] getHwGain();
+ void setHwGain(in float[] channelGains);
+ const int MIC_FIELD_DIMENSION_WIDE_ANGLE = -1;
+ const int MIC_FIELD_DIMENSION_NO_ZOOM = 0;
+ const int MIC_FIELD_DIMENSION_MAX_ZOOM = 1;
+ const int HW_GAIN_MIN = 0;
+ const int HW_GAIN_MAX = 1;
+ @Backing(type="int") @VintfStability
+ enum MicrophoneDirection {
+ UNSPECIFIED = 0,
+ FRONT = 1,
+ BACK = 2,
+ EXTERNAL = 3,
+ }
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamOut.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamOut.aidl
index 3021d94..092b801 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamOut.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamOut.aidl
@@ -34,6 +34,10 @@
package android.hardware.audio.core;
@VintfStability
interface IStreamOut {
- void close();
+ android.hardware.audio.core.IStreamCommon getStreamCommon();
void updateMetadata(in android.hardware.audio.common.SourceMetadata sourceMetadata);
+ float[] getHwVolume();
+ void setHwVolume(in float[] channelVolumes);
+ const int HW_VOLUME_MIN = 0;
+ const int HW_VOLUME_MAX = 1;
}
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.core/current/android/hardware/audio/core/MicrophoneDynamicInfo.aidl
similarity index 75%
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.core/current/android/hardware/audio/core/MicrophoneDynamicInfo.aidl
index 8ad4848..50a5528 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.core/current/android/hardware/audio/core/MicrophoneDynamicInfo.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.audio.core;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable MicrophoneDynamicInfo {
+ @utf8InCpp String id;
+ android.hardware.audio.core.MicrophoneDynamicInfo.ChannelMapping[] channelMapping;
+ @Backing(type="int") @VintfStability
+ enum ChannelMapping {
+ UNUSED = 0,
+ DIRECT = 1,
+ PROCESSED = 2,
}
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/MicrophoneInfo.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/MicrophoneInfo.aidl
new file mode 100644
index 0000000..68c7f88
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/MicrophoneInfo.aidl
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.audio.core;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable MicrophoneInfo {
+ @utf8InCpp String id;
+ android.media.audio.common.AudioDevice device;
+ android.hardware.audio.core.MicrophoneInfo.Location location = android.hardware.audio.core.MicrophoneInfo.Location.UNKNOWN;
+ int group = -1;
+ int indexInTheGroup = -1;
+ @nullable android.hardware.audio.core.MicrophoneInfo.Sensitivity sensitivity;
+ android.hardware.audio.core.MicrophoneInfo.Directionality directionality = android.hardware.audio.core.MicrophoneInfo.Directionality.UNKNOWN;
+ android.hardware.audio.core.MicrophoneInfo.FrequencyResponsePoint[] frequencyResponse;
+ @nullable android.hardware.audio.core.MicrophoneInfo.Coordinate position;
+ @nullable android.hardware.audio.core.MicrophoneInfo.Coordinate orientation;
+ const int GROUP_UNKNOWN = -1;
+ const int INDEX_IN_THE_GROUP_UNKNOWN = -1;
+ @Backing(type="int") @VintfStability
+ enum Location {
+ UNKNOWN = 0,
+ MAINBODY = 1,
+ MAINBODY_MOVABLE = 2,
+ PERIPHERAL = 3,
+ }
+ @VintfStability
+ parcelable Sensitivity {
+ float leveldBFS;
+ float maxSpldB;
+ float minSpldB;
+ }
+ @Backing(type="int") @VintfStability
+ enum Directionality {
+ UNKNOWN = 0,
+ OMNI = 1,
+ BI_DIRECTIONAL = 2,
+ CARDIOID = 3,
+ HYPER_CARDIOID = 4,
+ SUPER_CARDIOID = 5,
+ }
+ @VintfStability
+ parcelable FrequencyResponsePoint {
+ float frequencyHz;
+ float leveldB;
+ }
+ @VintfStability
+ parcelable Coordinate {
+ float x;
+ float y;
+ float z;
+ }
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ModuleDebug.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ModuleDebug.aidl
index 80ee185..467d37b 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ModuleDebug.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ModuleDebug.aidl
@@ -35,4 +35,5 @@
@JavaDerive(equals=true, toString=true) @VintfStability
parcelable ModuleDebug {
boolean simulateDeviceConnections;
+ int streamTransientStateDelayMs;
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/StreamDescriptor.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/StreamDescriptor.aidl
index 3a77ad1..3a4271b 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/StreamDescriptor.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/StreamDescriptor.aidl
@@ -42,8 +42,9 @@
const int LATENCY_UNKNOWN = -1;
@FixedSize @VintfStability
parcelable Position {
- long frames;
- long timeNs;
+ long frames = -1;
+ long timeNs = -1;
+ const long UNKNOWN = -1;
}
@Backing(type="int") @VintfStability
enum State {
@@ -53,14 +54,23 @@
PAUSED = 4,
DRAINING = 5,
DRAIN_PAUSED = 6,
+ TRANSFERRING = 7,
+ TRANSFER_PAUSED = 8,
ERROR = 100,
}
+ @Backing(type="byte") @VintfStability
+ enum DrainMode {
+ DRAIN_UNSPECIFIED = 0,
+ DRAIN_ALL = 1,
+ DRAIN_EARLY_NOTIFY = 2,
+ }
@FixedSize @VintfStability
union Command {
- int hal_reserved_exit;
+ int halReservedExit;
+ android.media.audio.common.Void getStatus;
android.media.audio.common.Void start;
int burst;
- android.media.audio.common.Void drain;
+ android.hardware.audio.core.StreamDescriptor.DrainMode drain;
android.media.audio.common.Void standby;
android.media.audio.common.Void pause;
android.media.audio.common.Void flush;
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.core/current/android/hardware/audio/core/VendorParameter.aidl
similarity index 75%
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.core/current/android/hardware/audio/core/VendorParameter.aidl
index 8ad4848..bfe33ee 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.core/current/android/hardware/audio/core/VendorParameter.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;
-@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.audio.core;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable VendorParameter {
+ @utf8InCpp String id;
+ ParcelableHolder ext;
}
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/core/IModule.aidl b/audio/aidl/android/hardware/audio/core/IModule.aidl
index be40051..b278ac4 100644
--- a/audio/aidl/android/hardware/audio/core/IModule.aidl
+++ b/audio/aidl/android/hardware/audio/core/IModule.aidl
@@ -21,11 +21,16 @@
import android.hardware.audio.core.AudioMode;
import android.hardware.audio.core.AudioPatch;
import android.hardware.audio.core.AudioRoute;
+import android.hardware.audio.core.ISoundDose;
+import android.hardware.audio.core.IStreamCallback;
import android.hardware.audio.core.IStreamIn;
import android.hardware.audio.core.IStreamOut;
import android.hardware.audio.core.ITelephony;
+import android.hardware.audio.core.MicrophoneInfo;
import android.hardware.audio.core.ModuleDebug;
import android.hardware.audio.core.StreamDescriptor;
+import android.hardware.audio.core.VendorParameter;
+import android.hardware.audio.effect.IEffect;
import android.media.audio.common.AudioOffloadInfo;
import android.media.audio.common.AudioPort;
import android.media.audio.common.AudioPortConfig;
@@ -53,9 +58,13 @@
* the HAL module behavior that would otherwise require human intervention.
*
* The HAL module must throw an error if there is an attempt to change
- * the debug behavior for the aspect which is currently in use.
+ * the debug behavior for the aspect which is currently in use, or when
+ * the value of any of the debug flags is invalid. See 'ModuleDebug' for
+ * the full list of constraints.
*
* @param debug The debug options.
+ * @throws EX_ILLEGAL_ARGUMENT If some of the configuration parameters are
+ * invalid.
* @throws EX_ILLEGAL_STATE If the flag(s) being changed affect functionality
* which is currently in use.
*/
@@ -316,9 +325,13 @@
* 'setAudioPortConfig' method. Existence of an audio patch involving this
* port configuration is not required for successful opening of a stream.
*
- * If the port configuration has 'COMPRESS_OFFLOAD' output flag set,
- * the framework must provide additional information about the encoded
- * audio stream in 'offloadInfo' argument.
+ * If the port configuration has the 'COMPRESS_OFFLOAD' output flag set,
+ * the client must provide additional information about the encoded
+ * audio stream in the 'offloadInfo' argument.
+ *
+ * If the port configuration has the 'NON_BLOCKING' output flag set,
+ * the client must provide a callback for asynchronous notifications
+ * in the 'callback' argument.
*
* The requested buffer size is expressed in frames, thus the actual size
* in bytes depends on the audio port configuration. Also, the HAL module
@@ -354,6 +367,8 @@
* - If the offload info is not provided for an offload
* port configuration.
* - If a buffer of the requested size can not be provided.
+ * - If the callback is not provided for a non-blocking
+ * port configuration.
* @throws EX_ILLEGAL_STATE In the following cases:
* - If the port config already has a stream opened on it.
* - If the limit on the open stream count for the port has
@@ -372,6 +387,8 @@
@nullable AudioOffloadInfo offloadInfo;
/** Requested audio I/O buffer minimum size, in frames. */
long bufferSizeFrames;
+ /** Client callback interface for the non-blocking output mode. */
+ @nullable IStreamCallback callback;
}
@VintfStability
parcelable OpenOutputStreamReturn {
@@ -499,7 +516,8 @@
* @throws EX_ILLEGAL_ARGUMENT If the port config can not be found by the ID.
* @throws EX_ILLEGAL_STATE In the following cases:
* - If the port config has a stream opened on it;
- * - If the port config is used by a patch.
+ * - If the port config is used by a patch;
+ * - If the port config has an audio effect on it.
*/
void resetAudioPortConfig(int portConfigId);
@@ -592,6 +610,22 @@
void setMicMute(boolean mute);
/**
+ * Provide information describing built-in microphones of the HAL module.
+ *
+ * If there are no built-in microphones in the HAL module, it must return an
+ * empty vector. If there are microphones, but the HAL module does not
+ * possess the required information about them, EX_UNSUPPORTED_OPERATION
+ * must be thrown.
+ *
+ * If this method is supported by the HAL module, it must also support
+ * 'IStreamIn.getActiveMicrophones' method.
+ *
+ * @return The vector with information about each microphone.
+ * @throws EX_UNSUPPORTED_OPERATION If the information is unavailable.
+ */
+ MicrophoneInfo[] getMicrophones();
+
+ /**
* Notify the HAL module on the change of the current audio mode.
*
* The current audio mode is always controlled by the client. This is an
@@ -638,4 +672,92 @@
* @param isTurnedOn True if the screen is turned on.
*/
void updateScreenState(boolean isTurnedOn);
+
+ /**
+ * Retrieve the sound dose interface.
+ *
+ * If a device must comply to IEC62368-1 3rd edition audio safety requirements and is
+ * implementing audio offload decoding or other direct playback paths where volume control
+ * happens below the audio HAL, it must return an instance of the ISoundDose interface.
+ * The same instance must be returned during the lifetime of the HAL module.
+ * If the HAL module does not support sound dose, null must be returned, without throwing
+ * any errors.
+ *
+ * @return An instance of the ISoundDose interface implementation.
+ * @throws EX_ILLEGAL_STATE If there was an error creating an instance.
+ */
+ @nullable ISoundDose getSoundDose();
+
+ /**
+ * Generate a HW AV Sync identifier for a new audio session.
+ *
+ * Creates a new unique identifier which can be further used by the client
+ * for tagging input / output streams that belong to the same audio
+ * session and thus must use the same HW AV Sync timestamps sequence.
+ *
+ * HW AV Sync timestamps are used for "tunneled" I/O modes and thus
+ * are not mandatory.
+ *
+ * @throws EX_ILLEGAL_STATE If the identifier can not be provided at the moment.
+ * @throws EX_UNSUPPORTED_OPERATION If synchronization with HW AV Sync markers
+ * is not supported.
+ */
+ int generateHwAvSyncId();
+
+ /**
+ * Get current values of vendor parameters.
+ *
+ * Return current values for the parameters corresponding to the provided ids.
+ *
+ * @param ids Ids of the parameters to retrieve values of.
+ * @return Current values of parameters, one per each id.
+ * @throws EX_ILLEGAL_ARGUMENT If the module does not recognize provided ids.
+ * @throws EX_ILLEGAL_STATE If parameter values can not be retrieved at the moment.
+ * @throws EX_UNSUPPORTED_OPERATION If the module does not support vendor parameters.
+ */
+ VendorParameter[] getVendorParameters(in @utf8InCpp String[] ids);
+ /**
+ * Set vendor parameters.
+ *
+ * Update values for provided vendor parameters. If the 'async' parameter
+ * is set to 'true', the implementation must return the control back without
+ * waiting for the application of parameters to complete.
+ *
+ * @param parameters Ids and values of parameters to set.
+ * @param async Whether to return from the method as early as possible.
+ * @throws EX_ILLEGAL_ARGUMENT If the module does not recognize provided parameters.
+ * @throws EX_ILLEGAL_STATE If parameters can not be set at the moment.
+ * @throws EX_UNSUPPORTED_OPERATION If the module does not support vendor parameters.
+ */
+ void setVendorParameters(in VendorParameter[] parameters, boolean async);
+
+ /**
+ * Apply an audio effect to a device port.
+ *
+ * The audio effect applies to all audio input or output on the specific
+ * configuration of the device audio port. The effect is inserted according
+ * to its insertion preference specified by the 'flags.insert' field of the
+ * EffectDescriptor.
+ *
+ * @param portConfigId The ID of the audio port config.
+ * @param effect The effect instance.
+ * @throws EX_ILLEGAL_ARGUMENT If the device port config can not be found by the ID,
+ * or the effect reference is invalid.
+ * @throws EX_UNSUPPORTED_OPERATION If the module does not support device port effects.
+ */
+ void addDeviceEffect(int portConfigId, in IEffect effect);
+
+ /**
+ * Stop applying an audio effect to a device port.
+ *
+ * Undo the action of the 'addDeviceEffect' method.
+ *
+ * @param portConfigId The ID of the audio port config.
+ * @param effect The effect instance.
+ * @throws EX_ILLEGAL_ARGUMENT If the device port config can not be found by the ID,
+ * or the effect reference is invalid, or the effect is
+ * not currently applied to the port config.
+ * @throws EX_UNSUPPORTED_OPERATION If the module does not support device port effects.
+ */
+ void removeDeviceEffect(int portConfigId, in IEffect effect);
}
diff --git a/audio/aidl/android/hardware/audio/core/ISoundDose.aidl b/audio/aidl/android/hardware/audio/core/ISoundDose.aidl
new file mode 100644
index 0000000..89fd69b
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/ISoundDose.aidl
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.core;
+
+import android.media.audio.common.AudioDevice;
+
+/**
+ * This interface provides functions related to sound exposure control required for compliance to
+ * EN/IEC 62368-1 3rd edition. Implementing this interface is mandatory for devices for which
+ * compliance to this standard is mandated and implementing audio offload decoding or other direct
+ * playback paths where volume control happens below the audio HAL.
+ */
+@VintfStability
+interface ISoundDose {
+ /**
+ * Max value in dBA used for momentary exposure warnings as defined by IEC62368-1
+ * 3rd edition. This value represents the default RS2 value.
+ */
+ const int DEFAULT_MAX_RS2 = 100;
+ /** Min value of the RS2 threshold in dBA as defined by IEC62368-1 3rd edition. */
+ const int MIN_RS2 = 80;
+
+ /**
+ * Sets the RS2 value used for momentary exposure warnings. Default value is
+ * DEFAULT_MAX_RS2 as specified in IEC62368-1 3rd edition.
+ *
+ * @param rs2ValueDbA custom RS2 value to use. Must not be higher than DEFAULT_MAX_RS2
+ * @throws EX_ILLEGAL_ARGUMENT if rs2ValueDbA is greater than DEFAULT_MAX_RS2 or lower
+ * than 80dBA
+ */
+ void setOutputRs2(float rs2ValueDbA);
+
+ /**
+ * Gets the RS2 value used for momentary exposure warnings.
+ *
+ * @return the RS2 value in dBA
+ */
+ float getOutputRs2();
+
+ /**
+ * Registers the HAL callback for sound dose computation. If sound dose is supported
+ * the MEL values and exposure notifications will be received through this callback
+ * only. The internal framework MEL computation will be disabled.
+ * It is not possible to unregister the callback. The HAL is responsible to provide
+ * the MEL values throughout its lifecycle.
+ * This method should only be called once (no updates allowed) with a valid callback.
+ *
+ * @param callback to use when new updates are available for sound dose
+ * @throws EX_ILLEGAL_STATE if the method is called more than once
+ * @throws EX_ILLEGAL_ARGUMENT if the passed callback is null
+ */
+ void registerSoundDoseCallback(in IHalSoundDoseCallback callback);
+
+ @VintfStability
+ oneway interface IHalSoundDoseCallback {
+ /**
+ * Called whenever the current MEL value exceeds the set RS2 value.
+ *
+ * @param currentDbA the current MEL value which exceeds the RS2 value
+ * @param audioDevice the audio device where the MEL exposure warning was recorded
+ */
+ void onMomentaryExposureWarning(float currentDbA, in AudioDevice audioDevice);
+
+ @VintfStability
+ parcelable MelRecord {
+ /**
+ * Array of continuously recorded MEL values >= RS1 (1 per second).
+ * First value in the array was recorded at 'timestamp'.
+ */
+ float[] melValues;
+ /**
+ * Corresponds to the time in seconds when the first MEL entry in melValues
+ * was recorded. The timestamp values have to be consistent throughout all
+ * audio ports, equal timestamp values will be aggregated.
+ */
+ long timestamp;
+ }
+
+ /**
+ * Provides a MelRecord containing continuous MEL values sorted by timestamp.
+ * Note that all the MEL values originate from the audio device specified by audioDevice.
+ * In case values from multiple devices need to be reported, the caller should execute
+ * this callback once for every device.
+ *
+ * @param melRecord contains the MEL values used for CSD
+ * @param audioDevice the audio device where the MEL values were recorded
+ */
+ void onNewMelValues(in MelRecord melRecord, in AudioDevice audioDevice);
+ }
+}
diff --git a/audio/aidl/android/hardware/audio/core/IStreamCallback.aidl b/audio/aidl/android/hardware/audio/core/IStreamCallback.aidl
new file mode 100644
index 0000000..440ab25
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/IStreamCallback.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.core;
+
+/**
+ * This interface is used to indicate completion of asynchronous operations.
+ * See the state machines referenced by StreamDescriptor for details.
+ */
+@VintfStability
+oneway interface IStreamCallback {
+ /**
+ * Indicate that the stream is ready for next data exchange.
+ */
+ void onTransferReady();
+ /**
+ * Indicate that an irrecoverable error has occurred during the last I/O
+ * operation. After sending this callback, the stream enters the 'ERROR'
+ * state.
+ */
+ void onError();
+ /**
+ * Indicate that the stream has finished draining. This is only used
+ * for output streams because for input streams draining is performed
+ * by the client.
+ */
+ void onDrainReady();
+}
diff --git a/audio/aidl/android/hardware/audio/core/IStreamCommon.aidl b/audio/aidl/android/hardware/audio/core/IStreamCommon.aidl
new file mode 100644
index 0000000..533ef67
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/IStreamCommon.aidl
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.core;
+
+import android.hardware.audio.core.VendorParameter;
+import android.hardware.audio.effect.IEffect;
+
+/**
+ * This interface contains operations that are common to input and output
+ * streams (IStreamIn and IStreamOut). The lifetime of the server-side
+ * implementation object is the same as of the "parent" IStreamIn/Out object.
+ * The client must release all references to this object together with
+ * references to the "parent" object.
+ */
+@VintfStability
+interface IStreamCommon {
+ /**
+ * Close the stream.
+ *
+ * Releases any resources allocated for this stream on the HAL module side.
+ * This includes the fast message queues and shared memories returned via
+ * the StreamDescriptor. Thus, the stream can not be operated anymore after
+ * it has been closed. The client needs to release the audio data I/O
+ * objects after the call to this method returns.
+ *
+ * Methods of IStream* interfaces throw EX_ILLEGAL_STATE for a closed stream.
+ *
+ * @throws EX_ILLEGAL_STATE If the stream has already been closed.
+ */
+ void close();
+
+ /**
+ * Update the HW AV Sync identifier for the stream.
+ *
+ * The argument to this method must be one of the identifiers previously
+ * returned by the 'IModule.generateHwAvSyncId' method. By tagging streams
+ * with the same identifier, the client indicates to the HAL that they all
+ * use the same HW AV Sync timestamps sequence.
+ *
+ * HW AV Sync timestamps are used for "tunneled" I/O modes and thus
+ * are not mandatory.
+ *
+ * @throws EX_ILLEGAL_ARGUMENT If the provided ID is unknown to the HAL module.
+ * @throws EX_ILLEGAL_STATE If the stream is closed.
+ * @throws EX_UNSUPPORTED_OPERATION If synchronization with HW AV Sync markers
+ * is not supported.
+ */
+ void updateHwAvSyncId(int hwAvSyncId);
+
+ /**
+ * Get current values of vendor parameters.
+ *
+ * Return current values for the parameters corresponding to the provided ids.
+ *
+ * @param ids Ids of the parameters to retrieve values of.
+ * @return Current values of parameters.
+ * @throws EX_ILLEGAL_ARGUMENT If the stream does not recognize provided ids.
+ * @throws EX_ILLEGAL_STATE If parameter values can not be retrieved at the moment.
+ * @throws EX_UNSUPPORTED_OPERATION If the stream does not support vendor parameters.
+ */
+ VendorParameter[] getVendorParameters(in @utf8InCpp String[] ids);
+ /**
+ * Set vendor parameters.
+ *
+ * Update values for provided vendor parameters. If the 'async' parameter
+ * is set to 'true', the implementation must return the control back without
+ * waiting for the application of parameters to complete.
+ *
+ * @param parameters Ids and values of parameters to set.
+ * @param async Whether to return from the method as early as possible.
+ * @throws EX_ILLEGAL_ARGUMENT If the stream does not recognize provided parameters.
+ * @throws EX_ILLEGAL_STATE If parameters can not be set at the moment.
+ * @throws EX_UNSUPPORTED_OPERATION If the stream does not support vendor parameters.
+ */
+ void setVendorParameters(in VendorParameter[] parameters, boolean async);
+
+ /**
+ * Apply an audio effect to the stream.
+ *
+ * This method is intended for the cases when the effect has an offload
+ * implementation, since software effects can be applied at the client side.
+ *
+ * @param effect The effect instance.
+ * @throws EX_ILLEGAL_ARGUMENT If the effect reference is invalid.
+ * @throws EX_ILLEGAL_STATE If the stream is closed.
+ * @throws EX_UNSUPPORTED_OPERATION If the module does not support audio effects.
+ */
+ void addEffect(in IEffect effect);
+
+ /**
+ * Stop applying an audio effect to the stream.
+ *
+ * Undo the action of the 'addEffect' method.
+ *
+ * @param effect The effect instance.
+ * @throws EX_ILLEGAL_ARGUMENT If the effect reference is invalid, or the effect is
+ * not currently applied to the stream.
+ * @throws EX_ILLEGAL_STATE If the stream is closed.
+ * @throws EX_UNSUPPORTED_OPERATION If the module does not support audio effects.
+ */
+ void removeEffect(in IEffect effect);
+}
diff --git a/audio/aidl/android/hardware/audio/core/IStreamIn.aidl b/audio/aidl/android/hardware/audio/core/IStreamIn.aidl
index 0c3e3d1..c2b3633 100644
--- a/audio/aidl/android/hardware/audio/core/IStreamIn.aidl
+++ b/audio/aidl/android/hardware/audio/core/IStreamIn.aidl
@@ -17,6 +17,8 @@
package android.hardware.audio.core;
import android.hardware.audio.common.SinkMetadata;
+import android.hardware.audio.core.IStreamCommon;
+import android.hardware.audio.core.MicrophoneDynamicInfo;
/**
* This interface provides means for receiving audio data from input devices.
@@ -24,19 +26,101 @@
@VintfStability
interface IStreamIn {
/**
- * Close the stream.
+ * Return the interface for common stream operations.
*
- * Releases any resources allocated for this stream on the HAL module side.
- * This includes the fast message queues and shared memories returned via
- * the StreamDescriptor. Thus, the stream can not be operated anymore after
- * it has been closed. The client needs to release the audio data I/O
- * objects after the call to this method returns.
+ * This method must always succeed. The implementation must
+ * return the same instance object for all subsequent calls to
+ * this method.
*
- * Methods of this interface throw EX_ILLEGAL_STATE for a closed stream.
+ * @return The interface for common operations.
+ */
+ IStreamCommon getStreamCommon();
+
+ /**
+ * Provides information on the microphones that are active for this stream.
+ *
+ * The returned array contains dynamic information on the microphones which
+ * are active for this stream. Each entry in the returned array must have a
+ * corresponding entry (matched by the 'MicrophoneInfo.id' field value) in
+ * the list of all available microphones which is provided by the
+ * 'IModule.getMicrophones' method.
+ *
+ * This method must be supported by the HAL module if
+ * 'IModule.getMicrophones' is supported.
+ *
+ * @return The vector with dynamic information on the microphones.
+ * @throws EX_ILLEGAL_STATE If the stream has already been closed.
+ * @throws EX_UNSUPPORTED_OPERATION If the information is unavailable.
+ */
+ MicrophoneDynamicInfo[] getActiveMicrophones();
+
+ @VintfStability
+ @Backing(type="int")
+ enum MicrophoneDirection {
+ /**
+ * Don't do any directionality processing of the activated microphone(s).
+ */
+ UNSPECIFIED = 0,
+ /**
+ * Optimize capture for audio coming from the screen-side of the device.
+ */
+ FRONT = 1,
+ /**
+ * Optimize capture for audio coming from the side of the device opposite the screen.
+ */
+ BACK = 2,
+ /**
+ * Optimize capture for audio coming from an off-device microphone.
+ */
+ EXTERNAL = 3,
+ }
+ /**
+ * Get the current logical microphone direction.
+ *
+ * @return The current logical microphone direction.
+ * @throws EX_ILLEGAL_STATE If the stream has already been closed.
+ * @throws EX_UNSUPPORTED_OPERATION If the information is unavailable.
+ */
+ MicrophoneDirection getMicrophoneDirection();
+ /**
+ * Set the current logical microphone direction.
+ *
+ * The client sets this parameter in order to specify its preference for
+ * optimizing the direction of capture when multiple microphones are in use.
+ *
+ * @param direction The preferred capture direction.
+ * @throws EX_ILLEGAL_STATE If the stream has already been closed.
+ * @throws EX_UNSUPPORTED_OPERATION If the operation is not supported.
+ */
+ void setMicrophoneDirection(MicrophoneDirection direction);
+
+ const int MIC_FIELD_DIMENSION_WIDE_ANGLE = -1;
+ const int MIC_FIELD_DIMENSION_NO_ZOOM = 0;
+ const int MIC_FIELD_DIMENSION_MAX_ZOOM = 1;
+ /**
+ * Get the "zoom factor" for the logical microphone.
+ *
+ * The returned value must be within the range of [-1.0, 1.0] (see
+ * MIC_FIELD_DIMENSION_* constants).
*
* @throws EX_ILLEGAL_STATE If the stream has already been closed.
+ * @throws EX_UNSUPPORTED_OPERATION If the information is unavailable.
*/
- void close();
+ float getMicrophoneFieldDimension();
+ /**
+ * Set the "zoom factor" for the logical microphone.
+ *
+ * If multiple microphones are in use, the provided zoom factor must be
+ * treated as a preference for their combined field dimension. The zoom
+ * factor must be within the range of [-1.0, 1.0] (see MIC_FIELD_DIMENSION_*
+ * constants).
+ *
+ * @param zoom The preferred field dimension of the microphone capture.
+ * @throws EX_ILLEGAL_ARGUMENT If the dimension value is outside of the range.
+ * @throws EX_ILLEGAL_STATE If the stream has already been closed.
+ * @throws EX_UNSUPPORTED_OPERATION If the operation is not supported.
+ */
+ void setMicrophoneFieldDimension(float zoom);
/**
* Update stream metadata.
@@ -47,4 +131,38 @@
* @throws EX_ILLEGAL_STATE If the stream is closed.
*/
void updateMetadata(in SinkMetadata sinkMetadata);
+
+ const int HW_GAIN_MIN = 0;
+ const int HW_GAIN_MAX = 1;
+ /**
+ * Retrieve current gain applied in hardware.
+ *
+ * In case when the HAL module has a gain controller, this method returns
+ * the current value of its gain for each input channel.
+ *
+ * The valid range for gain is [0.0f, 1.0f], where 1.0f corresponds to unity
+ * gain, 0.0f corresponds to full mute (see HW_GAIN_* constants).
+ *
+ * @return Current gain values for each input channel.
+ * @throws EX_ILLEGAL_STATE If the stream is closed.
+ * @throws EX_UNSUPPORTED_OPERATION If hardware gain control is not supported.
+ */
+ float[] getHwGain();
+ /**
+ * Set gain applied in hardware.
+ *
+ * In case when the HAL module has a gain controller, this method sets the
+ * current value of its gain for each input channel.
+ *
+ * The valid range for gain is [0.0f, 1.0f], where 1.0f corresponds to unity
+ * gain, 0.0f corresponds to full mute (see HW_GAIN_* constants).
+ *
+ * @param gain Gain values for each input channel.
+ * @throws EX_ILLEGAL_ARGUMENT If the number of elements in the provided
+ * array does not match the channel count, or
+ * gain values are out of range.
+ * @throws EX_ILLEGAL_STATE If the stream is closed.
+ * @throws EX_UNSUPPORTED_OPERATION If hardware gain control is not supported.
+ */
+ void setHwGain(in float[] channelGains);
}
diff --git a/audio/aidl/android/hardware/audio/core/IStreamOut.aidl b/audio/aidl/android/hardware/audio/core/IStreamOut.aidl
index 9fdb37d..85da00d 100644
--- a/audio/aidl/android/hardware/audio/core/IStreamOut.aidl
+++ b/audio/aidl/android/hardware/audio/core/IStreamOut.aidl
@@ -17,6 +17,7 @@
package android.hardware.audio.core;
import android.hardware.audio.common.SourceMetadata;
+import android.hardware.audio.core.IStreamCommon;
/**
* This interface provides means for sending audio data to output devices.
@@ -24,19 +25,15 @@
@VintfStability
interface IStreamOut {
/**
- * Close the stream.
+ * Return the interface for common stream operations.
*
- * Releases any resources allocated for this stream on the HAL module side.
- * This includes the fast message queues and shared memories returned via
- * the StreamDescriptor. Thus, the stream can not be operated anymore after
- * it has been closed. The client needs to release the audio data I/O
- * objects after the call to this method returns.
+ * This method must always succeed. The implementation must
+ * return the same instance object for all subsequent calls to
+ * this method.
*
- * Methods of this interface throw EX_ILLEGAL_STATE for a closed stream.
- *
- * @throws EX_ILLEGAL_STATE If the stream has already been closed.
+ * @return The interface for common operations.
*/
- void close();
+ IStreamCommon getStreamCommon();
/**
* Update stream metadata.
@@ -47,4 +44,46 @@
* @throws EX_ILLEGAL_STATE If the stream is closed.
*/
void updateMetadata(in SourceMetadata sourceMetadata);
+
+ const int HW_VOLUME_MIN = 0;
+ const int HW_VOLUME_MAX = 1;
+ /**
+ * Retrieve current attenuation applied in hardware.
+ *
+ * Hardware attenuation can be used in cases when the client can not, or is
+ * not allowed to modify the audio stream, for example because the stream is
+ * encoded.
+ *
+ * The valid range for attenuation is [0.0f, 1.0f], where 1.0f corresponds
+ * to unity gain, 0.0f corresponds to full mute (see HW_VOLUME_*
+ * constants). The returned array specifies attenuation for each output
+ * channel of the stream.
+ *
+ * Support of hardware volume control is optional.
+ *
+ * @return Current attenuation values for each output channel.
+ * @throws EX_ILLEGAL_STATE If the stream is closed.
+ * @throws EX_UNSUPPORTED_OPERATION If hardware volume control is not supported.
+ */
+ float[] getHwVolume();
+ /**
+ * Set attenuation applied in hardware.
+ *
+ * Hardware attenuation can be used in cases when the client can not, or is
+ * not allowed to modify the audio stream, for example because the stream is
+ * encoded.
+ *
+ * The valid range for attenuation is [0.0f, 1.0f], where 1.0f corresponds
+ * to unity gain, 0.0f corresponds to full mute (see HW_VOLUME_* constants).
+ *
+ * Support of hardware volume control is optional.
+ *
+ * @param channelVolumes Attenuation values for each output channel.
+ * @throws EX_ILLEGAL_ARGUMENT If the number of elements in the provided
+ * array does not match the channel count, or
+ * attenuation values are out of range.
+ * @throws EX_ILLEGAL_STATE If the stream is closed.
+ * @throws EX_UNSUPPORTED_OPERATION If hardware volume control is not supported.
+ */
+ void setHwVolume(in float[] channelVolumes);
}
diff --git a/audio/aidl/android/hardware/audio/core/MicrophoneDynamicInfo.aidl b/audio/aidl/android/hardware/audio/core/MicrophoneDynamicInfo.aidl
new file mode 100644
index 0000000..36cc51f
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/MicrophoneDynamicInfo.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.core;
+
+/**
+ * Structure providing dynamic information on a microphone. This information
+ * changes between recording sessions.
+ */
+@JavaDerive(equals=true, toString=true)
+@VintfStability
+parcelable MicrophoneDynamicInfo {
+ /**
+ * Unique alphanumeric id for the microphone. It must match the id of one of
+ * the 'MicrophoneInfo' entries returned by 'IModule.getMicrophones'.
+ */
+ @utf8InCpp String id;
+
+ @VintfStability
+ @Backing(type="int")
+ enum ChannelMapping {
+ /** Channel not used. */
+ UNUSED = 0,
+ /** Channel is used and the signal is not processed. */
+ DIRECT = 1,
+ /** Channel is used and the signal has some processing. */
+ PROCESSED = 2,
+ }
+ /**
+ * The vector is indexes by zero-based channels of the microphone, thus the
+ * element '0' corresponds to the first channel, '1' is the second, etc. The
+ * vector must contain at least 1 element.
+ */
+ ChannelMapping[] channelMapping;
+}
diff --git a/audio/aidl/android/hardware/audio/core/MicrophoneInfo.aidl b/audio/aidl/android/hardware/audio/core/MicrophoneInfo.aidl
new file mode 100644
index 0000000..3b8c7f3
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/MicrophoneInfo.aidl
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.core;
+
+import android.media.audio.common.AudioDevice;
+
+/**
+ * Structure providing static information on a microphone. This information
+ * never changes during the lifetime of the IModule which owns the microphone.
+ * The information presented in this structure indicates the location and
+ * orientation of the microphone on the device as well as useful information
+ * like frequency response and sensitivity.
+ */
+@JavaDerive(equals=true, toString=true)
+@VintfStability
+parcelable MicrophoneInfo {
+ /**
+ * Unique alphanumeric id for the microphone. It must remain the same across
+ * device reboots. The client must never attempt to parse the value of this
+ * field.
+ */
+ @utf8InCpp String id;
+ /**
+ * Describes the location of the microphone in terms of managed audio devices.
+ */
+ AudioDevice device;
+
+ @VintfStability
+ @Backing(type="int")
+ enum Location {
+ /** Microphone location is unknown. */
+ UNKNOWN = 0,
+ /** The microphone is located on the main body of the device. */
+ MAINBODY = 1,
+ /** The microphone is located on a movable main body of the device. */
+ MAINBODY_MOVABLE = 2,
+ /** The microphone is located on a peripheral. */
+ PERIPHERAL = 3,
+ }
+ /** Location of the microphone in regard to the body of the device */
+ Location location = Location.UNKNOWN;
+
+ /**
+ * This value is used when the group of the microphone is unknown.
+ */
+ const int GROUP_UNKNOWN = -1;
+ /**
+ * An identifier to group related microphones together, for example,
+ * microphones of a microphone array should all belong to the same group.
+ * Note that microphones assigned to 'GROUP_UNKNOWN' do not form a group.
+ */
+ int group = GROUP_UNKNOWN;
+ /**
+ * This value is used when the index in the group of the microphone is
+ * unknown.
+ */
+ const int INDEX_IN_THE_GROUP_UNKNOWN = -1;
+ /**
+ * Index of this microphone within the group. The pair (group, index) must
+ * be unique within the same HAL module, except the pair
+ * (GROUP_UNKNOWN, INDEX_IN_THE_GROUP_UNKNOWN).
+ */
+ int indexInTheGroup = INDEX_IN_THE_GROUP_UNKNOWN;
+
+ @VintfStability
+ parcelable Sensitivity {
+ /** Level in dBFS produced by a 1000 Hz tone at 94 dB SPL. */
+ float leveldBFS;
+ /** Level in dB of the max SPL supported at 1000 Hz */
+ float maxSpldB;
+ /** Level in dB of the min SPL supported at 1000 Hz */
+ float minSpldB;
+ }
+ /**
+ * If provided, must describe acceptable sound pressure levels (SPL)
+ * for a 1 kHz sine wave, and the resulting level in dBFS.
+ */
+ @nullable Sensitivity sensitivity;
+
+ @VintfStability
+ @Backing(type="int")
+ enum Directionality {
+ UNKNOWN = 0,
+ OMNI = 1,
+ BI_DIRECTIONAL = 2,
+ CARDIOID = 3,
+ HYPER_CARDIOID = 4,
+ SUPER_CARDIOID = 5,
+ }
+ /**
+ * The standard polar pattern of the microphone.
+ */
+ Directionality directionality = Directionality.UNKNOWN;
+
+ /**
+ * A (frequency, level) pair. Used to represent frequency response.
+ */
+ @VintfStability
+ parcelable FrequencyResponsePoint {
+ float frequencyHz;
+ float leveldB;
+ }
+ /**
+ * Vector with ordered frequency responses (from low to high frequencies)
+ * with the frequency response of the microphone. Levels are in dB,
+ * relative to level at 1000 Hz.
+ */
+ FrequencyResponsePoint[] frequencyResponse;
+
+ /**
+ * A 3D point used to represent position or orientation of a microphone.
+ */
+ @VintfStability
+ parcelable Coordinate {
+ float x;
+ float y;
+ float z;
+ }
+ /**
+ * If provided, must specify distances of the microphone's capsule, in
+ * meters, from the bottom-left-back corner of the bounding box of device in
+ * its natural orientation (PORTRAIT for phones, LANDSCAPE for tablets, TVs,
+ * etc).
+ */
+ @nullable Coordinate position;
+ /**
+ * If provided, describes the normalized point which defines the main
+ * orientation of the microphone's capsule.
+ * Magnitude = sqrt(x^2 + y^2 + z^2) = 1.
+ */
+ @nullable Coordinate orientation;
+}
diff --git a/audio/aidl/android/hardware/audio/core/ModuleDebug.aidl b/audio/aidl/android/hardware/audio/core/ModuleDebug.aidl
index 858a9bd..871a5c9 100644
--- a/audio/aidl/android/hardware/audio/core/ModuleDebug.aidl
+++ b/audio/aidl/android/hardware/audio/core/ModuleDebug.aidl
@@ -35,4 +35,19 @@
* profiles.
*/
boolean simulateDeviceConnections;
+ /**
+ * Must be non-negative. When set to non-zero, HAL module must delay
+ * transition from "transient" stream states (see StreamDescriptor.aidl)
+ * by the specified amount of milliseconds. The purpose of this delay
+ * is to allow VTS to test sending of stream commands while the stream is
+ * in a transient state. The delay must apply to newly created streams,
+ * it is not required to apply the delay to already opened streams.
+ *
+ * Note: the drawback of enabling this delay for asynchronous (non-blocking)
+ * modes is that sending of callbacks will also be delayed, because
+ * callbacks are sent once the stream state machine exits a transient
+ * state. Thus, it's not recommended to use it with tests that require
+ * waiting for an async callback.
+ */
+ int streamTransientStateDelayMs;
}
diff --git a/audio/aidl/android/hardware/audio/core/StreamDescriptor.aidl b/audio/aidl/android/hardware/audio/core/StreamDescriptor.aidl
index 2b1fc99..65ea9ef 100644
--- a/audio/aidl/android/hardware/audio/core/StreamDescriptor.aidl
+++ b/audio/aidl/android/hardware/audio/core/StreamDescriptor.aidl
@@ -84,13 +84,13 @@
* are different.
*
* State machines of both input and output streams start from the 'STANDBY'
- * state. Transitions between states happen naturally with changes in the
+ * state. Transitions between states happen naturally with changes in the
* states of the model elements. For simplicity, we restrict the change to one
* element only, for example, in the 'STANDBY' state, either the producer or the
* consumer can become active, but not both at the same time. States 'STANDBY',
* 'IDLE', 'READY', and '*PAUSED' are "stable"—they require an external event,
* whereas a change from the 'DRAINING' state can happen with time as the buffer
- * gets empty.
+ * gets empty, thus it's a "transient" state.
*
* The state machine for input streams is defined in the `stream-in-sm.gv` file,
* for output streams—in the `stream-out-sm.gv` file. State machines define how
@@ -100,6 +100,28 @@
* client can never observe a stream with a functioning command queue in this
* state. The 'ERROR' state is a special state which the state machine enters
* when an unrecoverable hardware error is detected by the HAL module.
+ *
+ * Non-blocking (asynchronous) modes introduce a new 'TRANSFERRING' state, which
+ * the state machine can enter after replying to the 'burst' command, instead of
+ * staying in the 'ACTIVE' state. In this case the client gets unblocked
+ * earlier, while the actual audio delivery to / from the observer is not
+ * complete yet. Once the HAL module is ready for the next transfer, it notifies
+ * the client via a oneway callback, and the machine switches to 'ACTIVE'
+ * state. The 'TRANSFERRING' state is thus "transient", similar to the
+ * 'DRAINING' state. For output streams, asynchronous transfer can be paused,
+ * and it's another new state: 'TRANSFER_PAUSED'. It differs from 'PAUSED' by
+ * the fact that no new writes are allowed. Please see 'stream-in-async-sm.gv'
+ * and 'stream-out-async-sm.gv' files for details. Below is the table summary
+ * for asynchronous only-states:
+ *
+ * Producer | Buffer state | Consumer | Applies | State
+ * active? | | active? | to |
+ * ==========|==============|==========|=========|==============================
+ * Yes | Not empty | Yes | Both | TRANSFERRING, s/w x-runs counted
+ * ----------|--------------|----------|---------|-----------------------------
+ * Yes | Not empty | No | Output | TRANSFER_PAUSED,
+ * | | | | h/w emits silence.
+ *
*/
@JavaDerive(equals=true, toString=true)
@VintfStability
@@ -116,10 +138,15 @@
@VintfStability
@FixedSize
parcelable Position {
+ /**
+ * The value used when the position can not be reported by the HAL
+ * module.
+ */
+ const long UNKNOWN = -1;
/** Frame count. */
- long frames;
+ long frames = UNKNOWN;
/** Timestamp in nanoseconds. */
- long timeNs;
+ long timeNs = UNKNOWN;
}
@VintfStability
@@ -166,11 +193,24 @@
/**
* Used for output streams only, pauses draining. This state is similar
* to the 'PAUSED' state, except that the client is not adding any
- * new data. If it emits a 'BURST' command, this brings the stream
+ * new data. If it emits a 'burst' command, this brings the stream
* into the regular 'PAUSED' state.
*/
DRAIN_PAUSED = 6,
/**
+ * Used only for streams in asynchronous mode. The stream enters this
+ * state after receiving a 'burst' command and returning control back
+ * to the client, thus unblocking it.
+ */
+ TRANSFERRING = 7,
+ /**
+ * Used only for output streams in asynchronous mode only. The stream
+ * enters this state after receiving a 'pause' command while being in
+ * the 'TRANSFERRING' state. Unlike 'PAUSED' state, this state does not
+ * accept new writes.
+ */
+ TRANSFER_PAUSED = 8,
+ /**
* The ERROR state is entered when the stream has encountered an
* irrecoverable error from the lower layer. After entering it, the
* stream can only be closed.
@@ -178,6 +218,29 @@
ERROR = 100,
}
+ @VintfStability
+ @Backing(type="byte")
+ enum DrainMode {
+ /**
+ * Unspecified—used with input streams only, because the client controls
+ * draining.
+ */
+ DRAIN_UNSPECIFIED = 0,
+ /**
+ * Used with output streams only, the HAL module indicates drain
+ * completion when all remaining audio data has been consumed.
+ */
+ DRAIN_ALL = 1,
+ /**
+ * Used with output streams only, the HAL module indicates drain
+ * completion shortly before all audio data has been consumed in order
+ * to give the client an opportunity to provide data for the next track
+ * for gapless playback. The exact amount of provided time is specific
+ * to the HAL implementation.
+ */
+ DRAIN_EARLY_NOTIFY = 2,
+ }
+
/**
* Used for sending commands to the HAL module. The client writes into
* the queue, the HAL module reads. The queue can only contain a single
@@ -198,7 +261,14 @@
* implementation must pass a random cookie as the command argument,
* which is only known to the implementation.
*/
- int hal_reserved_exit;
+ int halReservedExit;
+ /**
+ * Retrieve the current state of the stream. This command must be
+ * processed by the stream in any state. The stream must provide current
+ * positions, counters, and its state in the reply. This command must be
+ * handled by the HAL module without any observable side effects.
+ */
+ Void getStatus;
/**
* See the state machines on the applicability of this command to
* different states.
@@ -215,15 +285,14 @@
* read from the hardware into the 'audio.fmq' queue.
*
* In both cases it is allowed for this field to contain any
- * non-negative number. The value 0 can be used if the client only needs
- * to retrieve current positions and latency. Any sufficiently big value
- * which exceeds the size of the queue's area which is currently
- * available for reading or writing by the HAL module must be trimmed by
- * the HAL module to the available size. Note that the HAL module is
- * allowed to consume or provide less data than requested, and it must
- * return the amount of actually read or written data via the
- * 'Reply.fmqByteCount' field. Thus, only attempts to pass a negative
- * number must be constituted as a client's error.
+ * non-negative number. Any sufficiently big value which exceeds the
+ * size of the queue's area which is currently available for reading or
+ * writing by the HAL module must be trimmed by the HAL module to the
+ * available size. Note that the HAL module is allowed to consume or
+ * provide less data than requested, and it must return the amount of
+ * actually read or written data via the 'Reply.fmqByteCount'
+ * field. Thus, only attempts to pass a negative number must be
+ * constituted as a client's error.
*
* Differences for the MMap No IRQ mode:
*
@@ -233,13 +302,16 @@
* with sending of this command.
*
* - the value must always be set to 0.
+ *
+ * See the state machines on the applicability of this command to
+ * different states.
*/
int burst;
/**
* See the state machines on the applicability of this command to
* different states.
*/
- Void drain;
+ DrainMode drain;
/**
* See the state machines on the applicability of this command to
* different states.
@@ -286,10 +358,6 @@
* - STATUS_INVALID_OPERATION: the command is not applicable in the
* current state of the stream, or to this
* type of the stream;
- * - STATUS_NO_INIT: positions can not be reported because the mix port
- * is not connected to any producer or consumer, or
- * because the HAL module does not support positions
- * reporting for this AudioSource (on input streams).
* - STATUS_NOT_ENOUGH_DATA: a read or write error has
* occurred for the 'audio.fmq' queue;
*/
@@ -307,9 +375,11 @@
*/
int fmqByteCount;
/**
- * It is recommended to report the current position for any command.
- * If the position can not be reported, the 'status' field must be
- * set to 'NO_INIT'.
+ * It is recommended to report the current position for any command. If
+ * the position can not be reported, for example because the mix port is
+ * not connected to any producer or consumer, or because the HAL module
+ * does not support positions reporting for this AudioSource (on input
+ * streams), the 'Position::UNKNOWN' value must be used.
*
* For output streams: the moment when the specified stream position
* was presented to an external observer (i.e. presentation position).
@@ -401,6 +471,10 @@
* into 'reply' queue, and hangs on waiting on a read from
* the 'command' queue.
* 6. The client wakes up due to 5. and reads the reply.
+ * Note: in non-blocking mode, when the HAL module goes to
+ * the 'TRANSFERRING' state (as indicated by the 'reply.state'
+ * field), the client must wait for the 'IStreamCallback.onTransferReady'
+ * notification to arrive before starting the next burst.
*
* For input streams the following sequence of operations is used:
* 1. The client writes the BURST command into the 'command' queue,
@@ -415,6 +489,10 @@
* 5. The client wakes up due to 4.
* 6. The client reads the reply and audio data. The client must
* always read from the FMQ all the data it contains.
+ * Note: in non-blocking mode, when the HAL module goes to
+ * the 'TRANSFERRING' state (as indicated by the 'reply.state'
+ * field) the client must wait for the 'IStreamCallback.onTransferReady'
+ * notification to arrive before starting the next burst.
*
*/
MQDescriptor<byte, SynchronizedReadWrite> fmq;
diff --git a/audio/aidl/android/hardware/audio/core/VendorParameter.aidl b/audio/aidl/android/hardware/audio/core/VendorParameter.aidl
new file mode 100644
index 0000000..206bd9d
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/VendorParameter.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.core;
+
+/**
+ * Vendor parameters are used as a lightweight way to pass vendor-specific
+ * configuration data back and forth between the HAL and vendor's extension
+ * to the Android framework, without the need to extend audio interfaces
+ * from AOSP.
+ */
+@JavaDerive(equals=true, toString=true)
+@VintfStability
+parcelable VendorParameter {
+ /**
+ * Vendor-generated unique ID of the parameter. In order to avoid
+ * collisions, vendors must use a vendor-specific prefix for parameter
+ * ids. The Android framework always passes ids as-is, without any attempt
+ * to parse their content.
+ */
+ @utf8InCpp String id;
+ /**
+ * The payload of the parameter.
+ */
+ ParcelableHolder ext;
+}
diff --git a/audio/aidl/android/hardware/audio/core/stream-in-async-sm.gv b/audio/aidl/android/hardware/audio/core/stream-in-async-sm.gv
new file mode 100644
index 0000000..818b18e
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/stream-in-async-sm.gv
@@ -0,0 +1,47 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// To render: dot -Tpng stream-in-async-sm.gv -o stream-in-async-sm.png
+digraph stream_in_async_state_machine {
+ node [shape=doublecircle style=filled fillcolor=black width=0.5] I;
+ node [shape=point width=0.5] F;
+ node [shape=oval width=1];
+ node [fillcolor=lightgreen] STANDBY; // buffer is empty
+ node [fillcolor=tomato] CLOSED;
+ node [fillcolor=tomato] ERROR;
+ node [style=dashed] ANY_STATE;
+ node [fillcolor=lightblue style=filled];
+ // Note that when the producer (h/w) is passive, "burst" operations
+ // complete synchronously, bypassing the TRANSFERRING state.
+ I -> STANDBY;
+ STANDBY -> IDLE [label="start"]; // producer -> active
+ IDLE -> STANDBY [label="standby"]; // producer -> passive, buffer is cleared
+ IDLE -> TRANSFERRING [label="burst"]; // consumer -> active
+ ACTIVE -> PAUSED [label="pause"]; // consumer -> passive
+ ACTIVE -> DRAINING [label="drain"]; // producer -> passive
+ ACTIVE -> TRANSFERRING [label="burst"];
+ TRANSFERRING -> ACTIVE [label="←IStreamCallback.onTransferReady"];
+ TRANSFERRING -> PAUSED [label="pause"]; // consumer -> passive
+ TRANSFERRING -> DRAINING [label="drain"]; // producer -> passive
+ PAUSED -> TRANSFERRING [label="burst"]; // consumer -> active
+ PAUSED -> STANDBY [label="flush"]; // producer -> passive, buffer is cleared
+ DRAINING -> DRAINING [label="burst"];
+ DRAINING -> ACTIVE [label="start"]; // producer -> active
+ DRAINING -> STANDBY [label="<empty buffer>"]; // consumer deactivates
+ IDLE -> ERROR [label="←IStreamCallback.onError"];
+ PAUSED -> ERROR [label="←IStreamCallback.onError"];
+ TRANSFERRING -> ERROR [label="←IStreamCallback.onError"];
+ ANY_STATE -> CLOSED [label="→IStream*.close"];
+ CLOSED -> F;
+}
diff --git a/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv b/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv
new file mode 100644
index 0000000..e25b15a
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv
@@ -0,0 +1,57 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// To render: dot -Tpng stream-out-async-sm.gv -o stream-out-async-sm.png
+digraph stream_out_async_state_machine {
+ node [shape=doublecircle style=filled fillcolor=black width=0.5] I;
+ node [shape=point width=0.5] F;
+ node [shape=oval width=1];
+ node [fillcolor=lightgreen] STANDBY; // buffer is empty
+ node [fillcolor=lightgreen] IDLE; // buffer is empty
+ node [fillcolor=tomato] CLOSED;
+ node [fillcolor=tomato] ERROR;
+ node [style=dashed] ANY_STATE;
+ node [fillcolor=lightblue style=filled];
+ // Note that when the consumer (h/w) is passive, "burst" operations
+ // complete synchronously, bypassing the TRANSFERRING state.
+ I -> STANDBY;
+ STANDBY -> IDLE [label="start"]; // consumer -> active
+ STANDBY -> PAUSED [label="burst"]; // producer -> active
+ IDLE -> STANDBY [label="standby"]; // consumer -> passive
+ IDLE -> TRANSFERRING [label="burst"]; // producer -> active
+ ACTIVE -> PAUSED [label="pause"]; // consumer -> passive (not consuming)
+ ACTIVE -> DRAINING [label="drain"]; // producer -> passive
+ ACTIVE -> TRANSFERRING [label="burst"]; // early unblocking
+ ACTIVE -> ACTIVE [label="burst"]; // full write
+ TRANSFERRING -> ACTIVE [label="←IStreamCallback.onTransferReady"];
+ TRANSFERRING -> TRANSFER_PAUSED [label="pause"]; // consumer -> passive (not consuming)
+ TRANSFERRING -> DRAINING [label="drain"]; // producer -> passive
+ TRANSFER_PAUSED -> TRANSFERRING [label="start"]; // consumer -> active
+ TRANSFER_PAUSED -> DRAIN_PAUSED [label="drain"]; // producer -> passive
+ TRANSFER_PAUSED -> IDLE [label="flush"]; // buffer is cleared
+ PAUSED -> PAUSED [label="burst"];
+ PAUSED -> ACTIVE [label="start"]; // consumer -> active
+ PAUSED -> IDLE [label="flush"]; // producer -> passive, buffer is cleared
+ DRAINING -> IDLE [label="←IStreamCallback.onDrainReady"];
+ DRAINING -> TRANSFERRING [label="burst"]; // producer -> active
+ DRAINING -> DRAIN_PAUSED [label="pause"]; // consumer -> passive (not consuming)
+ DRAIN_PAUSED -> DRAINING [label="start"]; // consumer -> active
+ DRAIN_PAUSED -> TRANSFER_PAUSED [label="burst"]; // producer -> active
+ DRAIN_PAUSED -> IDLE [label="flush"]; // buffer is cleared
+ IDLE -> ERROR [label="←IStreamCallback.onError"];
+ DRAINING -> ERROR [label="←IStreamCallback.onError"];
+ TRANSFERRING -> ERROR [label="←IStreamCallback.onError"];
+ ANY_STATE -> CLOSED [label="→IStream*.close"];
+ CLOSED -> F;
+}
diff --git a/audio/aidl/android/hardware/audio/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/StreamWorker.cpp b/audio/aidl/common/StreamWorker.cpp
index dda0e4a..0d2121c 100644
--- a/audio/aidl/common/StreamWorker.cpp
+++ b/audio/aidl/common/StreamWorker.cpp
@@ -25,15 +25,20 @@
bool ThreadController::start(const std::string& name, int priority) {
mThreadName = name;
mThreadPriority = priority;
- mWorker = std::thread(&ThreadController::workerThread, this);
+ if (kTestSingleThread != name) {
+ mWorker = std::thread(&ThreadController::workerThread, this);
+ } else {
+ // Simulate the case when the workerThread completes prior
+ // to the moment when we being waiting for its start.
+ workerThread();
+ }
std::unique_lock<std::mutex> lock(mWorkerLock);
android::base::ScopedLockAssertion lock_assertion(mWorkerLock);
mWorkerCv.wait(lock, [&]() {
android::base::ScopedLockAssertion lock_assertion(mWorkerLock);
- return mWorkerState == WorkerState::RUNNING || !mError.empty();
+ return mWorkerState != WorkerState::INITIAL || !mError.empty();
});
- mWorkerStateChangeRequest = false;
- return mWorkerState == WorkerState::RUNNING;
+ return mError.empty();
}
void ThreadController::stop() {
@@ -81,8 +86,8 @@
void ThreadController::workerThread() {
using Status = StreamLogic::Status;
- std::string error = mLogic->init();
- if (error.empty() && !mThreadName.empty()) {
+ std::string error;
+ if (!mThreadName.empty()) {
std::string compliantName(mThreadName.substr(0, 15));
if (int errCode = pthread_setname_np(pthread_self(), compliantName.c_str()); errCode != 0) {
error.append("Failed to set thread name: ").append(strerror(errCode));
@@ -94,6 +99,9 @@
error.append("Failed to set thread priority: ").append(strerror(errCode));
}
}
+ if (error.empty()) {
+ error.append(mLogic->init());
+ }
{
std::lock_guard<std::mutex> lock(mWorkerLock);
mWorkerState = error.empty() ? WorkerState::RUNNING : WorkerState::STOPPED;
diff --git a/audio/aidl/common/include/StreamWorker.h b/audio/aidl/common/include/StreamWorker.h
index ab2ec26..e9c1070 100644
--- a/audio/aidl/common/include/StreamWorker.h
+++ b/audio/aidl/common/include/StreamWorker.h
@@ -32,7 +32,7 @@
namespace internal {
class ThreadController {
- enum class WorkerState { STOPPED, RUNNING, PAUSE_REQUESTED, PAUSED, RESUME_REQUESTED };
+ enum class WorkerState { INITIAL, STOPPED, RUNNING, PAUSE_REQUESTED, PAUSED, RESUME_REQUESTED };
public:
explicit ThreadController(StreamLogic* logic) : mLogic(logic) {}
@@ -76,7 +76,7 @@
std::thread mWorker;
std::mutex mWorkerLock;
std::condition_variable mWorkerCv;
- WorkerState mWorkerState GUARDED_BY(mWorkerLock) = WorkerState::STOPPED;
+ WorkerState mWorkerState GUARDED_BY(mWorkerLock) = WorkerState::INITIAL;
std::string mError GUARDED_BY(mWorkerLock);
// The atomic lock-free variable is used to prevent priority inversions
// that can occur when a high priority worker tries to acquire the lock
@@ -90,6 +90,9 @@
std::atomic<bool> mWorkerStateChangeRequest GUARDED_BY(mWorkerLock) = false;
};
+// A special thread name used in tests only.
+static const std::string kTestSingleThread = "__testST__";
+
} // namespace internal
class StreamLogic {
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/common/tests/streamworker_tests.cpp b/audio/aidl/common/tests/streamworker_tests.cpp
index 8ea8424..f7a30b9 100644
--- a/audio/aidl/common/tests/streamworker_tests.cpp
+++ b/audio/aidl/common/tests/streamworker_tests.cpp
@@ -283,4 +283,16 @@
EXPECT_EQ(priority, worker.getPriority());
}
+TEST_P(StreamWorkerTest, DeferredStartCheckNoError) {
+ stream.setStopStatus();
+ EXPECT_TRUE(worker.start(android::hardware::audio::common::internal::kTestSingleThread));
+ EXPECT_FALSE(worker.hasError());
+}
+
+TEST_P(StreamWorkerTest, DeferredStartCheckWithError) {
+ stream.setErrorStatus();
+ EXPECT_FALSE(worker.start(android::hardware::audio::common::internal::kTestSingleThread));
+ EXPECT_TRUE(worker.hasError());
+}
+
INSTANTIATE_TEST_SUITE_P(StreamWorker, StreamWorkerTest, testing::Bool());
diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp
index 2b9ed5b..a938551 100644
--- a/audio/aidl/default/Android.bp
+++ b/audio/aidl/default/Android.bp
@@ -18,11 +18,37 @@
"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",
+ ],
+}
+
+cc_library {
+ name: "libaudioservicesounddoseimpl",
+ vendor: true,
+ defaults: [
+ "latest_android_media_audio_common_types_ndk_shared",
+ "latest_android_hardware_audio_core_sounddose_ndk_shared",
+ "latest_android_hardware_audio_sounddose_ndk_shared",
+ ],
+ export_include_dirs: ["include"],
+ srcs: [
+ "SoundDose.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "libcutils",
+ "libutils",
+ ],
+ visibility: [
+ "//hardware/interfaces/audio/aidl/sounddose/default",
],
}
@@ -35,12 +61,27 @@
],
export_include_dirs: ["include"],
srcs: [
+ "AudioPolicyConfigXmlConverter.cpp",
"Config.cpp",
"Configuration.cpp",
+ "EngineConfigXmlConverter.cpp",
"Module.cpp",
+ "SoundDose.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__",
],
@@ -110,11 +151,12 @@
shared_libs: [
"libbassboostsw",
"libbundleaidl",
+ "libdownmixaidl",
"libdynamicsprocessingsw",
"libenvreverbsw",
"libequalizersw",
"libhapticgeneratorsw",
- "libloudnessenhancersw",
+ "libloudnessenhanceraidl",
"libpresetreverbsw",
"libtinyxml2",
"libvirtualizersw",
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 a3e5ff7..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,35 +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)));
-
AudioPort primaryInMix =
createPort(c.nextPortId++, "primary input", 0, true, createPortMixExt(2, 2));
primaryInMix.profiles.push_back(
@@ -257,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 820b447..3b40ae0 100644
--- a/audio/aidl/default/EffectFactory.cpp
+++ b/audio/aidl/default/EffectFactory.cpp
@@ -14,11 +14,18 @@
* limitations under the License.
*/
+#include <iterator>
+#include <memory>
+#include <tuple>
+#include "include/effect-impl/EffectTypes.h"
#define LOG_TAG "AHAL_EffectFactory"
-#include <android-base/logging.h>
#include <dlfcn.h>
#include <unordered_set>
+#include <android-base/logging.h>
+#include <android/binder_ibinder_platform.h>
+#include <system/thread_defs.h>
+
#include "effect-impl/EffectTypes.h"
#include "effect-impl/EffectUUID.h"
#include "effectFactory-impl/EffectFactory.h"
@@ -33,12 +40,13 @@
}
Factory::~Factory() {
- if (auto count = mEffectUuidMap.size()) {
+ if (auto count = mEffectMap.size()) {
LOG(ERROR) << __func__ << " remaining " << count
<< " effect instances not destroyed indicating resource leak!";
- for (const auto& it : mEffectUuidMap) {
+ for (const auto& it : mEffectMap) {
if (auto spEffect = it.first.lock()) {
- LOG(ERROR) << __func__ << " erase remaining instance UUID " << it.second.toString();
+ LOG(ERROR) << __func__ << " erase remaining instance UUID "
+ << it.second.first.toString();
destroyEffectImpl(spEffect);
}
}
@@ -48,15 +56,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();
}
@@ -71,37 +93,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) {
@@ -109,7 +110,10 @@
return ndk::ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
}
*_aidl_return = effectSp;
- mEffectUuidMap[std::weak_ptr<IEffect>(effectSp)] = in_impl_uuid;
+ ndk::SpAIBinder effectBinder = effectSp->asBinder();
+ AIBinder_setMinSchedulerPolicy(effectBinder.get(), SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
+ mEffectMap[std::weak_ptr<IEffect>(effectSp)] =
+ std::make_pair(in_impl_uuid, std::move(effectBinder));
LOG(DEBUG) << __func__ << ": instance " << effectSp.get() << " created successfully";
return ndk::ScopedAStatus::ok();
} else {
@@ -121,19 +125,20 @@
ndk::ScopedAStatus Factory::destroyEffectImpl(const std::shared_ptr<IEffect>& in_handle) {
std::weak_ptr<IEffect> wpHandle(in_handle);
- // find UUID with key (std::weak_ptr<IEffect>)
- if (auto uuidIt = mEffectUuidMap.find(wpHandle); uuidIt != mEffectUuidMap.end()) {
- auto& uuid = uuidIt->second;
+ // find the effect entry with key (std::weak_ptr<IEffect>)
+ if (auto effectIt = mEffectMap.find(wpHandle); effectIt != mEffectMap.end()) {
+ auto& uuid = effectIt->second.first;
// 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);
}
- mEffectUuidMap.erase(uuidIt);
+ mEffectMap.erase(effectIt);
return ndk::ScopedAStatus::ok();
} else {
LOG(ERROR) << __func__ << ": instance " << in_handle << " does not exist!";
@@ -143,9 +148,9 @@
// go over the map and cleanup all expired weak_ptrs.
void Factory::cleanupEffectMap() {
- for (auto it = mEffectUuidMap.begin(); it != mEffectUuidMap.end();) {
+ for (auto it = mEffectMap.begin(); it != mEffectMap.end();) {
if (nullptr == it->first.lock()) {
- it = mEffectUuidMap.erase(it);
+ it = mEffectMap.erase(it);
} else {
++it;
}
@@ -174,9 +179,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,
@@ -221,4 +230,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..5f17d71
--- /dev/null
+++ b/audio/aidl/default/EngineConfigXmlConverter.cpp
@@ -0,0 +1,305 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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/AudioFlag.h>
+#include <aidl/android/media/audio/common/AudioHalEngineConfig.h>
+#include <aidl/android/media/audio/common/AudioProductStrategyType.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 6863fe3..4a424bd 100644
--- a/audio/aidl/default/Module.cpp
+++ b/audio/aidl/default/Module.cpp
@@ -19,18 +19,21 @@
#define LOG_TAG "AHAL_Module"
#include <android-base/logging.h>
+#include <android/binder_ibinder_platform.h>
#include <Utils.h>
#include <aidl/android/media/audio/common/AudioInputFlags.h>
#include <aidl/android/media/audio/common/AudioOutputFlags.h>
#include "core-impl/Module.h"
+#include "core-impl/SoundDose.h"
#include "core-impl/Telephony.h"
#include "core-impl/utils.h"
using aidl::android::hardware::audio::common::SinkMetadata;
using aidl::android::hardware::audio::common::SourceMetadata;
using aidl::android::media::audio::common::AudioChannelLayout;
+using aidl::android::media::audio::common::AudioDevice;
using aidl::android::media::audio::common::AudioFormatDescription;
using aidl::android::media::audio::common::AudioFormatType;
using aidl::android::media::audio::common::AudioInputFlags;
@@ -97,6 +100,7 @@
}
ndk::ScopedAStatus Module::createStreamContext(int32_t in_portConfigId, int64_t in_bufferSizeFrames,
+ std::shared_ptr<IStreamCallback> asyncCallback,
StreamContext* out_context) {
if (in_bufferSizeFrames <= 0) {
LOG(ERROR) << __func__ << ": non-positive buffer size " << in_bufferSizeFrames;
@@ -135,8 +139,9 @@
StreamContext temp(
std::make_unique<StreamContext::CommandMQ>(1, true /*configureEventFlagWord*/),
std::make_unique<StreamContext::ReplyMQ>(1, true /*configureEventFlagWord*/),
- frameSize,
- std::make_unique<StreamContext::DataMQ>(frameSize * in_bufferSizeFrames));
+ portConfigIt->format.value(), portConfigIt->channelMask.value(),
+ std::make_unique<StreamContext::DataMQ>(frameSize * in_bufferSizeFrames),
+ asyncCallback, mDebug.streamTransientStateDelayMs);
if (temp.isValid()) {
*out_context = std::move(temp);
} else {
@@ -148,6 +153,39 @@
return ndk::ScopedAStatus::ok();
}
+std::vector<AudioDevice> Module::findConnectedDevices(int32_t portConfigId) {
+ std::vector<AudioDevice> result;
+ auto& ports = getConfig().ports;
+ auto portIds = portIdsFromPortConfigIds(findConnectedPortConfigIds(portConfigId));
+ for (auto it = portIds.begin(); it != portIds.end(); ++it) {
+ auto portIt = findById<AudioPort>(ports, *it);
+ if (portIt != ports.end() && portIt->ext.getTag() == AudioPortExt::Tag::device) {
+ result.push_back(portIt->ext.template get<AudioPortExt::Tag::device>().device);
+ }
+ }
+ return result;
+}
+
+std::set<int32_t> Module::findConnectedPortConfigIds(int32_t portConfigId) {
+ std::set<int32_t> result;
+ auto patchIdsRange = mPatches.equal_range(portConfigId);
+ auto& patches = getConfig().patches;
+ for (auto it = patchIdsRange.first; it != patchIdsRange.second; ++it) {
+ auto patchIt = findById<AudioPatch>(patches, it->second);
+ if (patchIt == patches.end()) {
+ LOG(FATAL) << __func__ << ": patch with id " << it->second << " taken from mPatches "
+ << "not found in the configuration";
+ }
+ if (std::find(patchIt->sourcePortConfigIds.begin(), patchIt->sourcePortConfigIds.end(),
+ portConfigId) != patchIt->sourcePortConfigIds.end()) {
+ result.insert(patchIt->sinkPortConfigIds.begin(), patchIt->sinkPortConfigIds.end());
+ } else {
+ result.insert(patchIt->sourcePortConfigIds.begin(), patchIt->sourcePortConfigIds.end());
+ }
+ }
+ return result;
+}
+
ndk::ScopedAStatus Module::findPortIdForNewStream(int32_t in_portConfigId, AudioPort** port) {
auto& configs = getConfig().portConfigs;
auto portConfigIt = findById<AudioPortConfig>(configs, in_portConfigId);
@@ -186,9 +224,29 @@
return ndk::ScopedAStatus::ok();
}
+template <typename C>
+std::set<int32_t> Module::portIdsFromPortConfigIds(C portConfigIds) {
+ std::set<int32_t> result;
+ auto& portConfigs = getConfig().portConfigs;
+ for (auto it = portConfigIds.begin(); it != portConfigIds.end(); ++it) {
+ auto portConfigIt = findById<AudioPortConfig>(portConfigs, *it);
+ if (portConfigIt != portConfigs.end()) {
+ result.insert(portConfigIt->portId);
+ }
+ }
+ return result;
+}
+
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;
}
@@ -222,12 +280,16 @@
idsToConnect.insert(newPatch.sinkPortConfigIds.begin(), newPatch.sinkPortConfigIds.end());
std::for_each(idsToDisconnect.begin(), idsToDisconnect.end(), [&](const auto& portConfigId) {
if (idsToConnect.count(portConfigId) == 0) {
- mStreams.setStreamIsConnected(portConfigId, false);
+ LOG(DEBUG) << "The stream on port config id " << portConfigId << " is not connected";
+ mStreams.setStreamIsConnected(portConfigId, {});
}
});
std::for_each(idsToConnect.begin(), idsToConnect.end(), [&](const auto& portConfigId) {
if (idsToDisconnect.count(portConfigId) == 0) {
- mStreams.setStreamIsConnected(portConfigId, true);
+ const auto connectedDevices = findConnectedDevices(portConfigId);
+ LOG(DEBUG) << "The stream on port config id " << portConfigId
+ << " is connected to: " << ::android::internal::ToString(connectedDevices);
+ mStreams.setStreamIsConnected(portConfigId, connectedDevices);
}
});
}
@@ -242,6 +304,11 @@
<< "while having external devices connected";
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}
+ if (in_debug.streamTransientStateDelayMs < 0) {
+ LOG(ERROR) << __func__ << ": streamTransientStateDelayMs is negative: "
+ << in_debug.streamTransientStateDelayMs;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
mDebug = in_debug;
return ndk::ScopedAStatus::ok();
}
@@ -249,6 +316,9 @@
ndk::ScopedAStatus Module::getTelephony(std::shared_ptr<ITelephony>* _aidl_return) {
if (mTelephony == nullptr) {
mTelephony = ndk::SharedRefBase::make<Telephony>();
+ mTelephonyBinder = mTelephony->asBinder();
+ AIBinder_setMinSchedulerPolicy(mTelephonyBinder.get(), SCHED_NORMAL,
+ ANDROID_PRIORITY_AUDIO);
}
*_aidl_return = mTelephony;
LOG(DEBUG) << __func__ << ": returning instance of ITelephony: " << _aidl_return->get();
@@ -456,19 +526,24 @@
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
StreamContext context;
- if (auto status = createStreamContext(in_args.portConfigId, in_args.bufferSizeFrames, &context);
+ if (auto status = createStreamContext(in_args.portConfigId, in_args.bufferSizeFrames, nullptr,
+ &context);
!status.isOk()) {
return status;
}
context.fillDescriptor(&_aidl_return->desc);
- auto stream = ndk::SharedRefBase::make<StreamIn>(in_args.sinkMetadata, std::move(context));
- if (auto status = stream->init(); !status.isOk()) {
+ std::shared_ptr<StreamIn> stream;
+ if (auto status = StreamIn::createInstance(in_args.sinkMetadata, std::move(context),
+ mConfig->microphones, &stream);
+ !status.isOk()) {
return status;
}
StreamWrapper streamWrapper(stream);
+ AIBinder_setMinSchedulerPolicy(streamWrapper.getBinder().get(), SCHED_NORMAL,
+ ANDROID_PRIORITY_AUDIO);
auto patchIt = mPatches.find(in_args.portConfigId);
if (patchIt != mPatches.end()) {
- streamWrapper.setStreamIsConnected(true);
+ streamWrapper.setStreamIsConnected(findConnectedDevices(in_args.portConfigId));
}
mStreams.insert(port->id, in_args.portConfigId, std::move(streamWrapper));
_aidl_return->stream = std::move(stream);
@@ -496,21 +571,32 @@
<< " has COMPRESS_OFFLOAD flag set, requires offload info";
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
+ const bool isNonBlocking = isBitPositionFlagSet(port->flags.get<AudioIoFlags::Tag::output>(),
+ AudioOutputFlags::NON_BLOCKING);
+ if (isNonBlocking && in_args.callback == nullptr) {
+ LOG(ERROR) << __func__ << ": port id " << port->id
+ << " has NON_BLOCKING flag set, requires async callback";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
StreamContext context;
- if (auto status = createStreamContext(in_args.portConfigId, in_args.bufferSizeFrames, &context);
+ if (auto status = createStreamContext(in_args.portConfigId, in_args.bufferSizeFrames,
+ isNonBlocking ? in_args.callback : nullptr, &context);
!status.isOk()) {
return status;
}
context.fillDescriptor(&_aidl_return->desc);
- auto stream = ndk::SharedRefBase::make<StreamOut>(in_args.sourceMetadata, std::move(context),
- in_args.offloadInfo);
- if (auto status = stream->init(); !status.isOk()) {
+ std::shared_ptr<StreamOut> stream;
+ if (auto status = StreamOut::createInstance(in_args.sourceMetadata, std::move(context),
+ in_args.offloadInfo, &stream);
+ !status.isOk()) {
return status;
}
StreamWrapper streamWrapper(stream);
+ AIBinder_setMinSchedulerPolicy(streamWrapper.getBinder().get(), SCHED_NORMAL,
+ ANDROID_PRIORITY_AUDIO);
auto patchIt = mPatches.find(in_args.portConfigId);
if (patchIt != mPatches.end()) {
- streamWrapper.setStreamIsConnected(true);
+ streamWrapper.setStreamIsConnected(findConnectedDevices(in_args.portConfigId));
}
mStreams.insert(port->id, in_args.portConfigId, std::move(streamWrapper));
_aidl_return->stream = std::move(stream);
@@ -829,6 +915,12 @@
return ndk::ScopedAStatus::ok();
}
+ndk::ScopedAStatus Module::getMicrophones(std::vector<MicrophoneInfo>* _aidl_return) {
+ *_aidl_return = mConfig->microphones;
+ LOG(DEBUG) << __func__ << ": returning " << ::android::internal::ToString(*_aidl_return);
+ return ndk::ScopedAStatus::ok();
+}
+
ndk::ScopedAStatus Module::updateAudioMode(AudioMode in_mode) {
// No checks for supported audio modes here, it's an informative notification.
LOG(DEBUG) << __func__ << ": " << toString(in_mode);
@@ -845,4 +937,60 @@
return ndk::ScopedAStatus::ok();
}
+ndk::ScopedAStatus Module::getSoundDose(std::shared_ptr<ISoundDose>* _aidl_return) {
+ if (mSoundDose == nullptr) {
+ mSoundDose = ndk::SharedRefBase::make<SoundDose>();
+ mSoundDoseBinder = mSoundDose->asBinder();
+ AIBinder_setMinSchedulerPolicy(mSoundDoseBinder.get(), SCHED_NORMAL,
+ ANDROID_PRIORITY_AUDIO);
+ }
+ *_aidl_return = mSoundDose;
+ LOG(DEBUG) << __func__ << ": returning instance of ISoundDose: " << _aidl_return->get();
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::generateHwAvSyncId(int32_t* _aidl_return) {
+ LOG(DEBUG) << __func__;
+ (void)_aidl_return;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus Module::getVendorParameters(const std::vector<std::string>& in_ids,
+ std::vector<VendorParameter>* _aidl_return) {
+ LOG(DEBUG) << __func__ << ": id count: " << in_ids.size();
+ (void)_aidl_return;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus Module::setVendorParameters(const std::vector<VendorParameter>& in_parameters,
+ bool in_async) {
+ LOG(DEBUG) << __func__ << ": parameter count " << in_parameters.size()
+ << ", async: " << in_async;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus Module::addDeviceEffect(
+ int32_t in_portConfigId,
+ const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect) {
+ if (in_effect == nullptr) {
+ LOG(DEBUG) << __func__ << ": port id " << in_portConfigId << ", null effect";
+ } else {
+ LOG(DEBUG) << __func__ << ": port id " << in_portConfigId << ", effect Binder "
+ << in_effect->asBinder().get();
+ }
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus Module::removeDeviceEffect(
+ int32_t in_portConfigId,
+ const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect) {
+ if (in_effect == nullptr) {
+ LOG(DEBUG) << __func__ << ": port id " << in_portConfigId << ", null effect";
+ } else {
+ LOG(DEBUG) << __func__ << ": port id " << in_portConfigId << ", effect Binder "
+ << in_effect->asBinder().get();
+ }
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/SoundDose.cpp b/audio/aidl/default/SoundDose.cpp
new file mode 100644
index 0000000..3d222a8
--- /dev/null
+++ b/audio/aidl/default/SoundDose.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AHAL_SoundDose"
+
+#include "core-impl/SoundDose.h"
+
+#include <android-base/logging.h>
+
+namespace aidl::android::hardware::audio::core {
+
+ndk::ScopedAStatus SoundDose::setOutputRs2(float in_rs2ValueDbA) {
+ if (in_rs2ValueDbA < MIN_RS2 || in_rs2ValueDbA > DEFAULT_MAX_RS2) {
+ LOG(ERROR) << __func__ << ": RS2 value is invalid: " << in_rs2ValueDbA;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+
+ mRs2Value = in_rs2ValueDbA;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus SoundDose::getOutputRs2(float* _aidl_return) {
+ *_aidl_return = mRs2Value;
+ LOG(DEBUG) << __func__ << ": returning " << *_aidl_return;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus SoundDose::registerSoundDoseCallback(
+ const std::shared_ptr<ISoundDose::IHalSoundDoseCallback>& in_callback) {
+ if (in_callback.get() == nullptr) {
+ LOG(ERROR) << __func__ << ": Callback is nullptr";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ if (mCallback != nullptr) {
+ LOG(ERROR) << __func__ << ": Sound dose callback was already registered";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
+
+ mCallback = in_callback;
+ LOG(DEBUG) << __func__ << ": Registered sound dose callback ";
+ return ndk::ScopedAStatus::ok();
+}
+
+} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp
index 21dc4b6..bb123a2 100644
--- a/audio/aidl/default/Stream.cpp
+++ b/audio/aidl/default/Stream.cpp
@@ -16,14 +16,20 @@
#define LOG_TAG "AHAL_Stream"
#include <android-base/logging.h>
+#include <android/binder_ibinder_platform.h>
#include <utils/SystemClock.h>
+#include <Utils.h>
+
#include "core-impl/Module.h"
#include "core-impl/Stream.h"
using aidl::android::hardware::audio::common::SinkMetadata;
using aidl::android::hardware::audio::common::SourceMetadata;
+using aidl::android::media::audio::common::AudioDevice;
using aidl::android::media::audio::common::AudioOffloadInfo;
+using android::hardware::audio::common::getChannelCount;
+using android::hardware::audio::common::getFrameSizeInBytes;
namespace aidl::android::hardware::audio::core {
@@ -35,13 +41,17 @@
desc->reply = mReplyMQ->dupeDesc();
}
if (mDataMQ) {
- desc->frameSizeBytes = mFrameSize;
- desc->bufferSizeFrames =
- mDataMQ->getQuantumCount() * mDataMQ->getQuantumSize() / mFrameSize;
+ const size_t frameSize = getFrameSize();
+ desc->frameSizeBytes = frameSize;
+ desc->bufferSizeFrames = mDataMQ->getQuantumCount() * mDataMQ->getQuantumSize() / frameSize;
desc->audio.set<StreamDescriptor::AudioBuffer::Tag::fmq>(mDataMQ->dupeDesc());
}
}
+size_t StreamContext::getFrameSize() const {
+ return getFrameSizeInBytes(mFormat, mChannelLayout);
+}
+
bool StreamContext::isValid() const {
if (mCommandMQ && !mCommandMQ->isValid()) {
LOG(ERROR) << "command FMQ is invalid";
@@ -51,8 +61,8 @@
LOG(ERROR) << "reply FMQ is invalid";
return false;
}
- if (mFrameSize == 0) {
- LOG(ERROR) << "frame size is not set";
+ if (getFrameSize() == 0) {
+ LOG(ERROR) << "frame size is invalid";
return false;
}
if (mDataMQ && !mDataMQ->isValid()) {
@@ -87,32 +97,46 @@
void StreamWorkerCommonLogic::populateReply(StreamDescriptor::Reply* reply,
bool isConnected) const {
+ reply->status = STATUS_OK;
if (isConnected) {
- reply->status = STATUS_OK;
reply->observable.frames = mFrameCount;
reply->observable.timeNs = ::android::elapsedRealtimeNano();
} else {
- reply->status = STATUS_NO_INIT;
+ reply->observable.frames = StreamDescriptor::Position::UNKNOWN;
+ reply->observable.timeNs = StreamDescriptor::Position::UNKNOWN;
}
}
+void StreamWorkerCommonLogic::populateReplyWrongState(
+ StreamDescriptor::Reply* reply, const StreamDescriptor::Command& command) const {
+ LOG(WARNING) << "command '" << toString(command.getTag())
+ << "' can not be handled in the state " << toString(mState);
+ reply->status = STATUS_INVALID_OPERATION;
+}
+
const std::string StreamInWorkerLogic::kThreadName = "reader";
StreamInWorkerLogic::Status StreamInWorkerLogic::cycle() {
+ // Note: for input streams, draining is driven by the client, thus
+ // "empty buffer" condition can only happen while handling the 'burst'
+ // command. Thus, unlike for output streams, it does not make sense to
+ // delay the 'DRAINING' state here by 'mTransientStateDelayMs'.
+ // TODO: Add a delay for transitions of async operations when/if they added.
+
StreamDescriptor::Command command{};
if (!mCommandMQ->readBlocking(&command, 1)) {
LOG(ERROR) << __func__ << ": reading of command from MQ failed";
mState = StreamDescriptor::State::ERROR;
return Status::ABORT;
}
+ LOG(DEBUG) << __func__ << ": received command " << command.toString() << " in " << kThreadName;
StreamDescriptor::Reply reply{};
reply.status = STATUS_BAD_VALUE;
using Tag = StreamDescriptor::Command::Tag;
switch (command.getTag()) {
- case Tag::hal_reserved_exit:
- if (const int32_t cookie = command.get<Tag::hal_reserved_exit>();
+ case Tag::halReservedExit:
+ if (const int32_t cookie = command.get<Tag::halReservedExit>();
cookie == mInternalCommandCookie) {
- LOG(DEBUG) << __func__ << ": received EXIT command";
setClosed();
// This is an internal command, no need to reply.
return Status::EXIT;
@@ -120,8 +144,10 @@
LOG(WARNING) << __func__ << ": EXIT command has a bad cookie: " << cookie;
}
break;
+ case Tag::getStatus:
+ populateReply(&reply, mIsConnected);
+ break;
case Tag::start:
- LOG(DEBUG) << __func__ << ": received START read command";
if (mState == StreamDescriptor::State::STANDBY ||
mState == StreamDescriptor::State::DRAINING) {
populateReply(&reply, mIsConnected);
@@ -129,15 +155,13 @@
? StreamDescriptor::State::IDLE
: StreamDescriptor::State::ACTIVE;
} else {
- LOG(WARNING) << __func__ << ": START command can not be handled in the state "
- << toString(mState);
- reply.status = STATUS_INVALID_OPERATION;
+ populateReplyWrongState(&reply, command);
}
break;
case Tag::burst:
if (const int32_t fmqByteCount = command.get<Tag::burst>(); fmqByteCount >= 0) {
- LOG(DEBUG) << __func__ << ": received BURST read command for " << fmqByteCount
- << " bytes";
+ LOG(DEBUG) << __func__ << ": '" << toString(command.getTag()) << "' command for "
+ << fmqByteCount << " bytes";
if (mState == StreamDescriptor::State::IDLE ||
mState == StreamDescriptor::State::ACTIVE ||
mState == StreamDescriptor::State::PAUSED ||
@@ -151,69 +175,61 @@
} else if (mState == StreamDescriptor::State::DRAINING) {
// To simplify the reference code, we assume that the read operation
// has consumed all the data remaining in the hardware buffer.
- // TODO: Provide parametrization on the duration of draining to test
- // handling of commands during the 'DRAINING' state.
+ // In a real implementation, here we would either remain in
+ // the 'DRAINING' state, or transfer to 'STANDBY' depending on the
+ // buffer state.
mState = StreamDescriptor::State::STANDBY;
}
} else {
- LOG(WARNING) << __func__ << ": BURST command can not be handled in the state "
- << toString(mState);
- reply.status = STATUS_INVALID_OPERATION;
+ populateReplyWrongState(&reply, command);
}
} else {
LOG(WARNING) << __func__ << ": invalid burst byte count: " << fmqByteCount;
}
break;
case Tag::drain:
- LOG(DEBUG) << __func__ << ": received DRAIN read command";
- if (mState == StreamDescriptor::State::ACTIVE) {
- usleep(1000); // Simulate a blocking call into the driver.
- populateReply(&reply, mIsConnected);
- // Can switch the state to ERROR if a driver error occurs.
- mState = StreamDescriptor::State::DRAINING;
+ if (command.get<Tag::drain>() == StreamDescriptor::DrainMode::DRAIN_UNSPECIFIED) {
+ if (mState == StreamDescriptor::State::ACTIVE) {
+ usleep(1000); // Simulate a blocking call into the driver.
+ populateReply(&reply, mIsConnected);
+ // Can switch the state to ERROR if a driver error occurs.
+ mState = StreamDescriptor::State::DRAINING;
+ } else {
+ populateReplyWrongState(&reply, command);
+ }
} else {
- LOG(WARNING) << __func__ << ": DRAIN command can not be handled in the state "
- << toString(mState);
- reply.status = STATUS_INVALID_OPERATION;
+ LOG(WARNING) << __func__
+ << ": invalid drain mode: " << toString(command.get<Tag::drain>());
}
break;
case Tag::standby:
- LOG(DEBUG) << __func__ << ": received STANDBY read command";
if (mState == StreamDescriptor::State::IDLE) {
usleep(1000); // Simulate a blocking call into the driver.
populateReply(&reply, mIsConnected);
// Can switch the state to ERROR if a driver error occurs.
mState = StreamDescriptor::State::STANDBY;
} else {
- LOG(WARNING) << __func__ << ": FLUSH command can not be handled in the state "
- << toString(mState);
- reply.status = STATUS_INVALID_OPERATION;
+ populateReplyWrongState(&reply, command);
}
break;
case Tag::pause:
- LOG(DEBUG) << __func__ << ": received PAUSE read command";
if (mState == StreamDescriptor::State::ACTIVE) {
usleep(1000); // Simulate a blocking call into the driver.
populateReply(&reply, mIsConnected);
// Can switch the state to ERROR if a driver error occurs.
mState = StreamDescriptor::State::PAUSED;
} else {
- LOG(WARNING) << __func__ << ": PAUSE command can not be handled in the state "
- << toString(mState);
- reply.status = STATUS_INVALID_OPERATION;
+ populateReplyWrongState(&reply, command);
}
break;
case Tag::flush:
- LOG(DEBUG) << __func__ << ": received FLUSH read command";
if (mState == StreamDescriptor::State::PAUSED) {
usleep(1000); // Simulate a blocking call into the driver.
populateReply(&reply, mIsConnected);
// Can switch the state to ERROR if a driver error occurs.
mState = StreamDescriptor::State::STANDBY;
} else {
- LOG(WARNING) << __func__ << ": FLUSH command can not be handled in the state "
- << toString(mState);
- reply.status = STATUS_INVALID_OPERATION;
+ populateReplyWrongState(&reply, command);
}
break;
}
@@ -261,20 +277,52 @@
const std::string StreamOutWorkerLogic::kThreadName = "writer";
StreamOutWorkerLogic::Status StreamOutWorkerLogic::cycle() {
+ if (mState == StreamDescriptor::State::DRAINING ||
+ mState == StreamDescriptor::State::TRANSFERRING) {
+ if (auto stateDurationMs = std::chrono::duration_cast<std::chrono::milliseconds>(
+ std::chrono::steady_clock::now() - mTransientStateStart);
+ stateDurationMs >= mTransientStateDelayMs) {
+ if (mAsyncCallback == nullptr) {
+ // In blocking mode, mState can only be DRAINING.
+ mState = StreamDescriptor::State::IDLE;
+ } else {
+ // In a real implementation, the driver should notify the HAL about
+ // drain or transfer completion. In the stub, we switch unconditionally.
+ if (mState == StreamDescriptor::State::DRAINING) {
+ mState = StreamDescriptor::State::IDLE;
+ ndk::ScopedAStatus status = mAsyncCallback->onDrainReady();
+ if (!status.isOk()) {
+ LOG(ERROR) << __func__ << ": error from onDrainReady: " << status;
+ }
+ } else {
+ mState = StreamDescriptor::State::ACTIVE;
+ ndk::ScopedAStatus status = mAsyncCallback->onTransferReady();
+ if (!status.isOk()) {
+ LOG(ERROR) << __func__ << ": error from onTransferReady: " << status;
+ }
+ }
+ }
+ if (mTransientStateDelayMs.count() != 0) {
+ LOG(DEBUG) << __func__ << ": switched to state " << toString(mState)
+ << " after a timeout";
+ }
+ }
+ }
+
StreamDescriptor::Command command{};
if (!mCommandMQ->readBlocking(&command, 1)) {
LOG(ERROR) << __func__ << ": reading of command from MQ failed";
mState = StreamDescriptor::State::ERROR;
return Status::ABORT;
}
+ LOG(DEBUG) << __func__ << ": received command " << command.toString() << " in " << kThreadName;
StreamDescriptor::Reply reply{};
reply.status = STATUS_BAD_VALUE;
using Tag = StreamDescriptor::Command::Tag;
switch (command.getTag()) {
- case Tag::hal_reserved_exit:
- if (const int32_t cookie = command.get<Tag::hal_reserved_exit>();
+ case Tag::halReservedExit:
+ if (const int32_t cookie = command.get<Tag::halReservedExit>();
cookie == mInternalCommandCookie) {
- LOG(DEBUG) << __func__ << ": received EXIT command";
setClosed();
// This is an internal command, no need to reply.
return Status::EXIT;
@@ -282,8 +330,11 @@
LOG(WARNING) << __func__ << ": EXIT command has a bad cookie: " << cookie;
}
break;
- case Tag::start:
- LOG(DEBUG) << __func__ << ": received START write command";
+ case Tag::getStatus:
+ populateReply(&reply, mIsConnected);
+ break;
+ case Tag::start: {
+ bool commandAccepted = true;
switch (mState) {
case StreamDescriptor::State::STANDBY:
mState = StreamDescriptor::State::IDLE;
@@ -292,97 +343,112 @@
mState = StreamDescriptor::State::ACTIVE;
break;
case StreamDescriptor::State::DRAIN_PAUSED:
- mState = StreamDescriptor::State::PAUSED;
+ switchToTransientState(StreamDescriptor::State::DRAINING);
+ break;
+ case StreamDescriptor::State::TRANSFER_PAUSED:
+ switchToTransientState(StreamDescriptor::State::TRANSFERRING);
break;
default:
- LOG(WARNING) << __func__ << ": START command can not be handled in the state "
- << toString(mState);
- reply.status = STATUS_INVALID_OPERATION;
+ populateReplyWrongState(&reply, command);
+ commandAccepted = false;
}
- if (reply.status != STATUS_INVALID_OPERATION) {
+ if (commandAccepted) {
populateReply(&reply, mIsConnected);
}
- break;
+ } break;
case Tag::burst:
if (const int32_t fmqByteCount = command.get<Tag::burst>(); fmqByteCount >= 0) {
- LOG(DEBUG) << __func__ << ": received BURST write command for " << fmqByteCount
- << " bytes";
- if (mState !=
- StreamDescriptor::State::ERROR) { // BURST can be handled in all valid states
+ LOG(DEBUG) << __func__ << ": '" << toString(command.getTag()) << "' command for "
+ << fmqByteCount << " bytes";
+ if (mState != StreamDescriptor::State::ERROR &&
+ mState != StreamDescriptor::State::TRANSFERRING &&
+ mState != StreamDescriptor::State::TRANSFER_PAUSED) {
if (!write(fmqByteCount, &reply)) {
mState = StreamDescriptor::State::ERROR;
}
if (mState == StreamDescriptor::State::STANDBY ||
- mState == StreamDescriptor::State::DRAIN_PAUSED) {
- mState = StreamDescriptor::State::PAUSED;
+ mState == StreamDescriptor::State::DRAIN_PAUSED ||
+ mState == StreamDescriptor::State::PAUSED) {
+ if (mAsyncCallback == nullptr ||
+ mState != StreamDescriptor::State::DRAIN_PAUSED) {
+ mState = StreamDescriptor::State::PAUSED;
+ } else {
+ mState = StreamDescriptor::State::TRANSFER_PAUSED;
+ }
} else if (mState == StreamDescriptor::State::IDLE ||
- mState == StreamDescriptor::State::DRAINING) {
- mState = StreamDescriptor::State::ACTIVE;
- } // When in 'ACTIVE' and 'PAUSED' do not need to change the state.
+ mState == StreamDescriptor::State::DRAINING ||
+ mState == StreamDescriptor::State::ACTIVE) {
+ if (mAsyncCallback == nullptr || reply.fmqByteCount == fmqByteCount) {
+ mState = StreamDescriptor::State::ACTIVE;
+ } else {
+ switchToTransientState(StreamDescriptor::State::TRANSFERRING);
+ }
+ }
} else {
- LOG(WARNING) << __func__ << ": BURST command can not be handled in the state "
- << toString(mState);
- reply.status = STATUS_INVALID_OPERATION;
+ populateReplyWrongState(&reply, command);
}
} else {
LOG(WARNING) << __func__ << ": invalid burst byte count: " << fmqByteCount;
}
break;
case Tag::drain:
- LOG(DEBUG) << __func__ << ": received DRAIN write command";
- if (mState == StreamDescriptor::State::ACTIVE) {
- usleep(1000); // Simulate a blocking call into the driver.
- populateReply(&reply, mIsConnected);
- // Can switch the state to ERROR if a driver error occurs.
- mState = StreamDescriptor::State::IDLE;
- // Since there is no actual hardware that would be draining the buffer,
- // in order to simplify the reference code, we assume that draining
- // happens instantly, thus skipping the 'DRAINING' state.
- // TODO: Provide parametrization on the duration of draining to test
- // handling of commands during the 'DRAINING' state.
+ if (command.get<Tag::drain>() == StreamDescriptor::DrainMode::DRAIN_ALL ||
+ command.get<Tag::drain>() == StreamDescriptor::DrainMode::DRAIN_EARLY_NOTIFY) {
+ if (mState == StreamDescriptor::State::ACTIVE ||
+ mState == StreamDescriptor::State::TRANSFERRING) {
+ usleep(1000); // Simulate a blocking call into the driver.
+ populateReply(&reply, mIsConnected);
+ // Can switch the state to ERROR if a driver error occurs.
+ switchToTransientState(StreamDescriptor::State::DRAINING);
+ } else if (mState == StreamDescriptor::State::TRANSFER_PAUSED) {
+ mState = StreamDescriptor::State::DRAIN_PAUSED;
+ populateReply(&reply, mIsConnected);
+ } else {
+ populateReplyWrongState(&reply, command);
+ }
} else {
- LOG(WARNING) << __func__ << ": DRAIN command can not be handled in the state "
- << toString(mState);
- reply.status = STATUS_INVALID_OPERATION;
+ LOG(WARNING) << __func__
+ << ": invalid drain mode: " << toString(command.get<Tag::drain>());
}
break;
case Tag::standby:
- LOG(DEBUG) << __func__ << ": received STANDBY write command";
if (mState == StreamDescriptor::State::IDLE) {
usleep(1000); // Simulate a blocking call into the driver.
populateReply(&reply, mIsConnected);
// Can switch the state to ERROR if a driver error occurs.
mState = StreamDescriptor::State::STANDBY;
} else {
- LOG(WARNING) << __func__ << ": STANDBY command can not be handled in the state "
- << toString(mState);
- reply.status = STATUS_INVALID_OPERATION;
+ populateReplyWrongState(&reply, command);
}
break;
- case Tag::pause:
- LOG(DEBUG) << __func__ << ": received PAUSE write command";
- if (mState == StreamDescriptor::State::ACTIVE ||
- mState == StreamDescriptor::State::DRAINING) {
+ case Tag::pause: {
+ bool commandAccepted = true;
+ switch (mState) {
+ case StreamDescriptor::State::ACTIVE:
+ mState = StreamDescriptor::State::PAUSED;
+ break;
+ case StreamDescriptor::State::DRAINING:
+ mState = StreamDescriptor::State::DRAIN_PAUSED;
+ break;
+ case StreamDescriptor::State::TRANSFERRING:
+ mState = StreamDescriptor::State::TRANSFER_PAUSED;
+ break;
+ default:
+ populateReplyWrongState(&reply, command);
+ commandAccepted = false;
+ }
+ if (commandAccepted) {
populateReply(&reply, mIsConnected);
- mState = mState == StreamDescriptor::State::ACTIVE
- ? StreamDescriptor::State::PAUSED
- : StreamDescriptor::State::DRAIN_PAUSED;
- } else {
- LOG(WARNING) << __func__ << ": PAUSE command can not be handled in the state "
- << toString(mState);
- reply.status = STATUS_INVALID_OPERATION;
}
- break;
+ } break;
case Tag::flush:
- LOG(DEBUG) << __func__ << ": received FLUSH write command";
if (mState == StreamDescriptor::State::PAUSED ||
- mState == StreamDescriptor::State::DRAIN_PAUSED) {
+ mState == StreamDescriptor::State::DRAIN_PAUSED ||
+ mState == StreamDescriptor::State::TRANSFER_PAUSED) {
populateReply(&reply, mIsConnected);
mState = StreamDescriptor::State::IDLE;
} else {
- LOG(WARNING) << __func__ << ": FLUSH command can not be handled in the state "
- << toString(mState);
- reply.status = STATUS_INVALID_OPERATION;
+ populateReplyWrongState(&reply, command);
}
break;
}
@@ -421,7 +487,7 @@
}
template <class Metadata, class StreamWorker>
-StreamCommon<Metadata, StreamWorker>::~StreamCommon() {
+StreamCommonImpl<Metadata, StreamWorker>::~StreamCommonImpl() {
if (!isClosed()) {
LOG(ERROR) << __func__ << ": stream was not closed prior to destruction, resource leak";
stopWorker();
@@ -430,7 +496,74 @@
}
template <class Metadata, class StreamWorker>
-ndk::ScopedAStatus StreamCommon<Metadata, StreamWorker>::close() {
+void StreamCommonImpl<Metadata, StreamWorker>::createStreamCommon(
+ const std::shared_ptr<StreamCommonInterface>& delegate) {
+ if (mCommon != nullptr) {
+ LOG(FATAL) << __func__ << ": attempting to create the common interface twice";
+ }
+ mCommon = ndk::SharedRefBase::make<StreamCommon>(delegate);
+ mCommonBinder = mCommon->asBinder();
+ AIBinder_setMinSchedulerPolicy(mCommonBinder.get(), SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
+}
+
+template <class Metadata, class StreamWorker>
+ndk::ScopedAStatus StreamCommonImpl<Metadata, StreamWorker>::getStreamCommon(
+ std::shared_ptr<IStreamCommon>* _aidl_return) {
+ if (mCommon == nullptr) {
+ LOG(FATAL) << __func__ << ": the common interface was not created";
+ }
+ *_aidl_return = mCommon;
+ LOG(DEBUG) << __func__ << ": returning " << _aidl_return->get()->asBinder().get();
+ return ndk::ScopedAStatus::ok();
+}
+
+template <class Metadata, class StreamWorker>
+ndk::ScopedAStatus StreamCommonImpl<Metadata, StreamWorker>::updateHwAvSyncId(
+ int32_t in_hwAvSyncId) {
+ LOG(DEBUG) << __func__ << ": id " << in_hwAvSyncId;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+template <class Metadata, class StreamWorker>
+ndk::ScopedAStatus StreamCommonImpl<Metadata, StreamWorker>::getVendorParameters(
+ const std::vector<std::string>& in_ids, std::vector<VendorParameter>* _aidl_return) {
+ LOG(DEBUG) << __func__ << ": id count: " << in_ids.size();
+ (void)_aidl_return;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+template <class Metadata, class StreamWorker>
+ndk::ScopedAStatus StreamCommonImpl<Metadata, StreamWorker>::setVendorParameters(
+ const std::vector<VendorParameter>& in_parameters, bool in_async) {
+ LOG(DEBUG) << __func__ << ": parameters count " << in_parameters.size()
+ << ", async: " << in_async;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+template <class Metadata, class StreamWorker>
+ndk::ScopedAStatus StreamCommonImpl<Metadata, StreamWorker>::addEffect(
+ const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect) {
+ if (in_effect == nullptr) {
+ LOG(DEBUG) << __func__ << ": null effect";
+ } else {
+ LOG(DEBUG) << __func__ << ": effect Binder" << in_effect->asBinder().get();
+ }
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+template <class Metadata, class StreamWorker>
+ndk::ScopedAStatus StreamCommonImpl<Metadata, StreamWorker>::removeEffect(
+ const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect) {
+ if (in_effect == nullptr) {
+ LOG(DEBUG) << __func__ << ": null effect";
+ } else {
+ LOG(DEBUG) << __func__ << ": effect Binder" << in_effect->asBinder().get();
+ }
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+template <class Metadata, class StreamWorker>
+ndk::ScopedAStatus StreamCommonImpl<Metadata, StreamWorker>::close() {
LOG(DEBUG) << __func__;
if (!isClosed()) {
stopWorker();
@@ -447,12 +580,11 @@
}
template <class Metadata, class StreamWorker>
-void StreamCommon<Metadata, StreamWorker>::stopWorker() {
+void StreamCommonImpl<Metadata, StreamWorker>::stopWorker() {
if (auto commandMQ = mContext.getCommandMQ(); commandMQ != nullptr) {
LOG(DEBUG) << __func__ << ": asking the worker to exit...";
- auto cmd =
- StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::hal_reserved_exit>(
- mContext.getInternalCommandCookie());
+ auto cmd = StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::halReservedExit>(
+ mContext.getInternalCommandCookie());
// Note: never call 'pause' and 'resume' methods of StreamWorker
// in the HAL implementation. These methods are to be used by
// the client side only. Preventing the worker loop from running
@@ -465,7 +597,8 @@
}
template <class Metadata, class StreamWorker>
-ndk::ScopedAStatus StreamCommon<Metadata, StreamWorker>::updateMetadata(const Metadata& metadata) {
+ndk::ScopedAStatus StreamCommonImpl<Metadata, StreamWorker>::updateMetadata(
+ const Metadata& metadata) {
LOG(DEBUG) << __func__;
if (!isClosed()) {
mMetadata = metadata;
@@ -475,16 +608,120 @@
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}
-StreamIn::StreamIn(const SinkMetadata& sinkMetadata, StreamContext context)
- : StreamCommon<SinkMetadata, StreamInWorker>(sinkMetadata, std::move(context)) {
+// static
+ndk::ScopedAStatus StreamIn::createInstance(const common::SinkMetadata& sinkMetadata,
+ StreamContext context,
+ const std::vector<MicrophoneInfo>& microphones,
+ std::shared_ptr<StreamIn>* result) {
+ auto stream = ndk::SharedRefBase::make<StreamIn>(sinkMetadata, std::move(context), microphones);
+ if (auto status = stream->init(); !status.isOk()) {
+ return status;
+ }
+ stream->createStreamCommon(stream);
+ *result = std::move(stream);
+ return ndk::ScopedAStatus::ok();
+}
+
+namespace {
+static std::map<AudioDevice, std::string> transformMicrophones(
+ const std::vector<MicrophoneInfo>& microphones) {
+ std::map<AudioDevice, std::string> result;
+ std::transform(microphones.begin(), microphones.end(), std::inserter(result, result.begin()),
+ [](const auto& mic) { return std::make_pair(mic.device, mic.id); });
+ return result;
+}
+} // namespace
+
+StreamIn::StreamIn(const SinkMetadata& sinkMetadata, StreamContext&& context,
+ const std::vector<MicrophoneInfo>& microphones)
+ : StreamCommonImpl<SinkMetadata, StreamInWorker>(sinkMetadata, std::move(context)),
+ mMicrophones(transformMicrophones(microphones)) {
LOG(DEBUG) << __func__;
}
-StreamOut::StreamOut(const SourceMetadata& sourceMetadata, StreamContext context,
+ndk::ScopedAStatus StreamIn::getActiveMicrophones(
+ std::vector<MicrophoneDynamicInfo>* _aidl_return) {
+ std::vector<MicrophoneDynamicInfo> result;
+ std::vector<MicrophoneDynamicInfo::ChannelMapping> channelMapping{
+ getChannelCount(mContext.getChannelLayout()),
+ MicrophoneDynamicInfo::ChannelMapping::DIRECT};
+ for (auto it = mConnectedDevices.begin(); it != mConnectedDevices.end(); ++it) {
+ if (auto micIt = mMicrophones.find(*it); micIt != mMicrophones.end()) {
+ MicrophoneDynamicInfo dynMic;
+ dynMic.id = micIt->second;
+ dynMic.channelMapping = channelMapping;
+ result.push_back(std::move(dynMic));
+ }
+ }
+ *_aidl_return = std::move(result);
+ LOG(DEBUG) << __func__ << ": returning " << ::android::internal::ToString(*_aidl_return);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus StreamIn::getMicrophoneDirection(MicrophoneDirection* _aidl_return) {
+ LOG(DEBUG) << __func__;
+ (void)_aidl_return;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus StreamIn::setMicrophoneDirection(MicrophoneDirection in_direction) {
+ LOG(DEBUG) << __func__ << ": direction " << toString(in_direction);
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus StreamIn::getMicrophoneFieldDimension(float* _aidl_return) {
+ LOG(DEBUG) << __func__;
+ (void)_aidl_return;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus StreamIn::setMicrophoneFieldDimension(float in_zoom) {
+ LOG(DEBUG) << __func__ << ": zoom " << in_zoom;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus StreamIn::getHwGain(std::vector<float>* _aidl_return) {
+ LOG(DEBUG) << __func__;
+ (void)_aidl_return;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus StreamIn::setHwGain(const std::vector<float>& in_channelGains) {
+ LOG(DEBUG) << __func__ << ": gains " << ::android::internal::ToString(in_channelGains);
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+// static
+ndk::ScopedAStatus StreamOut::createInstance(const SourceMetadata& sourceMetadata,
+ StreamContext context,
+ const std::optional<AudioOffloadInfo>& offloadInfo,
+ std::shared_ptr<StreamOut>* result) {
+ auto stream =
+ ndk::SharedRefBase::make<StreamOut>(sourceMetadata, std::move(context), offloadInfo);
+ if (auto status = stream->init(); !status.isOk()) {
+ return status;
+ }
+ stream->createStreamCommon(stream);
+ *result = std::move(stream);
+ return ndk::ScopedAStatus::ok();
+}
+
+StreamOut::StreamOut(const SourceMetadata& sourceMetadata, StreamContext&& context,
const std::optional<AudioOffloadInfo>& offloadInfo)
- : StreamCommon<SourceMetadata, StreamOutWorker>(sourceMetadata, std::move(context)),
+ : StreamCommonImpl<SourceMetadata, StreamOutWorker>(sourceMetadata, std::move(context)),
mOffloadInfo(offloadInfo) {
LOG(DEBUG) << __func__;
}
+ndk::ScopedAStatus StreamOut::getHwVolume(std::vector<float>* _aidl_return) {
+ LOG(DEBUG) << __func__;
+ (void)_aidl_return;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus StreamOut::setHwVolume(const std::vector<float>& in_channelVolumes) {
+ LOG(DEBUG) << __func__ << ": gains " << ::android::internal::ToString(in_channelVolumes);
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/android.hardware.audio.effect.service-aidl.example.rc b/audio/aidl/default/android.hardware.audio.effect.service-aidl.example.rc
index 68bbf5b..5f859a1 100644
--- a/audio/aidl/default/android.hardware.audio.effect.service-aidl.example.rc
+++ b/audio/aidl/default/android.hardware.audio.effect.service-aidl.example.rc
@@ -4,6 +4,8 @@
# media gid needed for /dev/fm (radio) and for /data/misc/media (tee)
group audio media
capabilities BLOCK_SUSPEND
+ # setting RLIMIT_RTPRIO allows binder RT priority inheritance
+ rlimit rtprio 10 10
ioprio rt 4
task_profiles ProcessCapacityHigh HighPerformance
onrestart restart audioserver
diff --git a/audio/aidl/default/android.hardware.audio.service-aidl.example.rc b/audio/aidl/default/android.hardware.audio.service-aidl.example.rc
index 02a9c37..2068735 100644
--- a/audio/aidl/default/android.hardware.audio.service-aidl.example.rc
+++ b/audio/aidl/default/android.hardware.audio.service-aidl.example.rc
@@ -4,6 +4,8 @@
# media gid needed for /dev/fm (radio) and for /data/misc/media (tee)
group audio camera drmrpc inet media mediadrm net_bt net_bt_admin net_bw_acct wakelock context_hub
capabilities BLOCK_SUSPEND
+ # setting RLIMIT_RTPRIO allows binder RT priority inheritance
+ rlimit rtprio 10 10
ioprio rt 4
task_profiles ProcessCapacityHigh HighPerformance
onrestart restart audioserver
diff --git a/audio/aidl/default/android.hardware.audio.service-aidl.xml b/audio/aidl/default/android.hardware.audio.service-aidl.xml
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/audio_effects_config.xml b/audio/aidl/default/audio_effects_config.xml
index f4ac8fe..9491bc3 100644
--- a/audio/aidl/default/audio_effects_config.xml
+++ b/audio/aidl/default/audio_effects_config.xml
@@ -30,10 +30,11 @@
<libraries>
<library name="bassboostsw" path="libbassboostsw.so"/>
<library name="bundle" path="libbundleaidl.so"/>
+ <library name="downmix" path="libdownmixaidl.so"/>
<library name="dynamics_processingsw" path="libdynamicsprocessingsw.so"/>
<library name="equalizersw" path="libequalizersw.so"/>
<library name="haptic_generatorsw" path="libhapticgeneratorsw.so"/>
- <library name="loudness_enhancersw" path="libloudnessenhancersw.so"/>
+ <library name="loudness_enhancer" path="libloudnessenhanceraidl.so"/>
<library name="env_reverbsw" path="libenvreverbsw.so"/>
<library name="preset_reverbsw" path="libpresetreverbsw.so"/>
<library name="virtualizersw" path="libvirtualizersw.so"/>
@@ -61,10 +62,14 @@
-->
<effects>
- <effect name="bassboost" library="bassboostsw" uuid="fa8181f2-588b-11ed-9b6a-0242ac120002"/>
+ <effectProxy name="bassboost" uuid="14804144-a5ee-4d24-aa88-0002a5d5c51b">
+ <libsw library="bassboostsw" uuid="fa8181f2-588b-11ed-9b6a-0242ac120002"/>
+ <libsw library="bundle" uuid="8631f300-72e2-11df-b57e-0002a5d5c51b"/>
+ </effectProxy>
+ <effect name="downmix" library="downmix" uuid="93f04452-e4fe-41cc-91f9-e475b6d1d69f"/>
<effect name="dynamics_processing" library="dynamics_processingsw" uuid="fa818d78-588b-11ed-9b6a-0242ac120002"/>
<effect name="haptic_generator" library="haptic_generatorsw" uuid="fa819110-588b-11ed-9b6a-0242ac120002"/>
- <effect name="loudness_enhancer" library="loudness_enhancersw" uuid="fa819610-588b-11ed-9b6a-0242ac120002"/>
+ <effect name="loudness_enhancer" library="loudness_enhancer" uuid="fa415329-2034-4bea-b5dc-5b381c8d1e2c"/>
<effect name="env_reverb" library="env_reverbsw" uuid="fa819886-588b-11ed-9b6a-0242ac120002"/>
<effect name="preset_reverb" library="preset_reverbsw" uuid="fa8199c6-588b-11ed-9b6a-0242ac120002"/>
<effect name="virtualizer" library="virtualizersw" uuid="fa819d86-588b-11ed-9b6a-0242ac120002"/>
diff --git a/audio/aidl/default/bassboost/BassBoostSw.cpp b/audio/aidl/default/bassboost/BassBoostSw.cpp
index c52d16f..8e4779d 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 = kBassBoostProxyUUID},
+ .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..ad79a0c
--- /dev/null
+++ b/audio/aidl/default/config/audioPolicy/api/current.txt
@@ -0,0 +1,609 @@
+// 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;
+ enum_constant public static final android.audio.policy.configuration.AudioEncapsulationType AUDIO_ENCAPSULATION_TYPE_PCM;
+ }
+
+ public enum AudioFormat {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC;
+ 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_BIT_PERFECT;
+ 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 99%
rename from audio/aidl/default/config/audio_policy_configuration.xsd
rename to audio/aidl/default/config/audioPolicy/audio_policy_configuration.xsd
index 2c18a1e..301c969 100644
--- a/audio/aidl/default/config/audio_policy_configuration.xsd
+++ b/audio/aidl/default/config/audioPolicy/audio_policy_configuration.xsd
@@ -181,6 +181,7 @@
<xs:enumeration value="AUDIO_OUTPUT_FLAG_GAPLESS_OFFLOAD" />
<xs:enumeration value="AUDIO_OUTPUT_FLAG_SPATIALIZER" />
<xs:enumeration value="AUDIO_OUTPUT_FLAG_ULTRASOUND" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_BIT_PERFECT" />
<xs:enumeration value="AUDIO_INPUT_FLAG_FAST" />
<xs:enumeration value="AUDIO_INPUT_FLAG_HW_HOTWORD" />
<xs:enumeration value="AUDIO_INPUT_FLAG_RAW" />
@@ -575,6 +576,7 @@
<xs:restriction base="xs:string">
<xs:enumeration value="AUDIO_ENCAPSULATION_TYPE_NONE"/>
<xs:enumeration value="AUDIO_ENCAPSULATION_TYPE_IEC61937"/>
+ <xs:enumeration value="AUDIO_ENCAPSULATION_TYPE_PCM"/>
</xs:restriction>
</xs:simpleType>
<xs:complexType name="profile">
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/downmix/Android.bp b/audio/aidl/default/downmix/Android.bp
new file mode 100644
index 0000000..230b2d8
--- /dev/null
+++ b/audio/aidl/default/downmix/Android.bp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_shared {
+ name: "libdownmixsw",
+ defaults: [
+ "aidlaudioeffectservice_defaults",
+ "latest_android_media_audio_common_types_ndk_shared",
+ "latest_android_hardware_audio_effect_ndk_shared",
+ ],
+ srcs: [
+ "DownmixSw.cpp",
+ ":effectCommonFile",
+ ],
+ visibility: [
+ "//hardware/interfaces/audio/aidl/default",
+ ],
+}
diff --git a/audio/aidl/default/downmix/DownmixSw.cpp b/audio/aidl/default/downmix/DownmixSw.cpp
new file mode 100644
index 0000000..7bb958d
--- /dev/null
+++ b/audio/aidl/default/downmix/DownmixSw.cpp
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cstddef>
+#define LOG_TAG "AHAL_DownmixSw"
+#include <Utils.h>
+#include <algorithm>
+#include <unordered_set>
+
+#include <android-base/logging.h>
+#include <fmq/AidlMessageQueue.h>
+
+#include "DownmixSw.h"
+
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::DownmixSw;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kDownmixSwImplUUID;
+using aidl::android::hardware::audio::effect::State;
+using aidl::android::media::audio::common::AudioUuid;
+
+extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
+ std::shared_ptr<IEffect>* instanceSpp) {
+ if (!in_impl_uuid || *in_impl_uuid != kDownmixSwImplUUID) {
+ LOG(ERROR) << __func__ << "uuid not supported";
+ return EX_ILLEGAL_ARGUMENT;
+ }
+ if (instanceSpp) {
+ *instanceSpp = ndk::SharedRefBase::make<DownmixSw>();
+ LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
+ return EX_NONE;
+ } else {
+ LOG(ERROR) << __func__ << " invalid input parameter!";
+ return EX_ILLEGAL_ARGUMENT;
+ }
+}
+
+extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) {
+ if (!in_impl_uuid || *in_impl_uuid != kDownmixSwImplUUID) {
+ LOG(ERROR) << __func__ << "uuid not supported";
+ return EX_ILLEGAL_ARGUMENT;
+ }
+ *_aidl_return = DownmixSw::kDescriptor;
+ return EX_NONE;
+}
+
+namespace aidl::android::hardware::audio::effect {
+
+const std::string DownmixSw::kEffectName = "DownmixSw";
+const Downmix::Capability DownmixSw::kCapability;
+const Descriptor DownmixSw::kDescriptor = {
+ .common = {.id = {.type = kDownmixTypeUUID,
+ .uuid = kDownmixSwImplUUID,
+ .proxy = std::nullopt},
+ .flags = {.type = Flags::Type::INSERT,
+ .insert = Flags::Insert::FIRST,
+ .volume = Flags::Volume::CTRL},
+ .name = kEffectName,
+ .implementor = "The Android Open Source Project"},
+ .capability = Capability::make<Capability::downmix>(kCapability)};
+
+ndk::ScopedAStatus DownmixSw::getDescriptor(Descriptor* _aidl_return) {
+ LOG(DEBUG) << __func__ << kDescriptor.toString();
+ *_aidl_return = kDescriptor;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus DownmixSw::setParameterSpecific(const Parameter::Specific& specific) {
+ RETURN_IF(Parameter::Specific::downmix != specific.getTag(), EX_ILLEGAL_ARGUMENT,
+ "EffectNotSupported");
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+ auto& dmParam = specific.get<Parameter::Specific::downmix>();
+ auto tag = dmParam.getTag();
+
+ switch (tag) {
+ case Downmix::type: {
+ RETURN_IF(mContext->setDmType(dmParam.get<Downmix::type>()) != RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setTypeFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ default: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "DownmixTagNotSupported");
+ }
+ }
+}
+
+ndk::ScopedAStatus DownmixSw::getParameterSpecific(const Parameter::Id& id,
+ Parameter::Specific* specific) {
+ auto tag = id.getTag();
+ RETURN_IF(Parameter::Id::downmixTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
+ auto dmId = id.get<Parameter::Id::downmixTag>();
+ auto dmIdTag = dmId.getTag();
+ switch (dmIdTag) {
+ case Downmix::Id::commonTag:
+ return getParameterDownmix(dmId.get<Downmix::Id::commonTag>(), specific);
+ default:
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "DownmixTagNotSupported");
+ }
+}
+
+ndk::ScopedAStatus DownmixSw::getParameterDownmix(const Downmix::Tag& tag,
+ Parameter::Specific* specific) {
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+ Downmix dmParam;
+ switch (tag) {
+ case Downmix::type: {
+ dmParam.set<Downmix::type>(mContext->getDmType());
+ break;
+ }
+ default: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "DownmixTagNotSupported");
+ }
+ }
+
+ specific->set<Parameter::Specific::downmix>(dmParam);
+ return ndk::ScopedAStatus::ok();
+}
+
+std::shared_ptr<EffectContext> DownmixSw::createContext(const Parameter::Common& common) {
+ if (mContext) {
+ LOG(DEBUG) << __func__ << " context already exist";
+ } else {
+ mContext = std::make_shared<DownmixSwContext>(1 /* statusFmqDepth */, common);
+ }
+
+ return mContext;
+}
+
+std::shared_ptr<EffectContext> DownmixSw::getContext() {
+ return mContext;
+}
+
+RetCode DownmixSw::releaseContext() {
+ if (mContext) {
+ mContext.reset();
+ }
+ return RetCode::SUCCESS;
+}
+
+// Processing method running in EffectWorker thread.
+IEffect::Status DownmixSw::effectProcessImpl(float* in, float* out, int samples) {
+ // TODO: get data buffer and process.
+ LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
+ for (int i = 0; i < samples; i++) {
+ *out++ = *in++;
+ }
+ return {STATUS_OK, samples, samples};
+}
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/downmix/DownmixSw.h b/audio/aidl/default/downmix/DownmixSw.h
new file mode 100644
index 0000000..51546c1
--- /dev/null
+++ b/audio/aidl/default/downmix/DownmixSw.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/audio/effect/BnEffect.h>
+#include <fmq/AidlMessageQueue.h>
+#include <cstdlib>
+#include <memory>
+
+#include "effect-impl/EffectImpl.h"
+#include "effect-impl/EffectUUID.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+class DownmixSwContext final : public EffectContext {
+ public:
+ DownmixSwContext(int statusDepth, const Parameter::Common& common)
+ : EffectContext(statusDepth, common) {
+ LOG(DEBUG) << __func__;
+ }
+
+ RetCode setDmType(Downmix::Type type) {
+ // TODO : Add implementation to apply new type
+ mType = type;
+ return RetCode::SUCCESS;
+ }
+ Downmix::Type getDmType() const { return mType; }
+
+ private:
+ Downmix::Type mType = Downmix::Type::STRIP;
+};
+
+class DownmixSw final : public EffectImpl {
+ public:
+ static const std::string kEffectName;
+ static const Downmix::Capability kCapability;
+ static const Descriptor kDescriptor;
+ DownmixSw() { LOG(DEBUG) << __func__; }
+ ~DownmixSw() {
+ cleanUp();
+ LOG(DEBUG) << __func__;
+ }
+
+ ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
+ ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
+ ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
+ Parameter::Specific* specific) override;
+
+ 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 sample) override;
+
+ private:
+ std::shared_ptr<DownmixSwContext> mContext;
+
+ ndk::ScopedAStatus getParameterDownmix(const Downmix::Tag& tag, Parameter::Specific* specific);
+};
+} // namespace aidl::android::hardware::audio::effect
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..65a8002 100644
--- a/audio/aidl/default/equalizer/EqualizerSw.h
+++ b/audio/aidl/default/equalizer/EqualizerSw.h
@@ -53,8 +53,9 @@
LOG(ERROR) << __func__ << " index illegal, skip: " << it.index << " - "
<< it.levelMb;
ret = RetCode::ERROR_ILLEGAL_PARAMETER;
+ } else {
+ mBandLevels[it.index] = it.levelMb;
}
- mBandLevels[it.index] = it.levelMb;
}
return ret;
}
@@ -80,6 +81,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 +97,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..f6211c4 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,28 +84,85 @@
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();
+ auto& hgParam = specific.get<Parameter::Specific::hapticGenerator>();
+ auto tag = hgParam.getTag();
+
+ switch (tag) {
+ case HapticGenerator::hapticScale: {
+ RETURN_IF(mContext->setHgHapticScale(hgParam.get<HapticGenerator::hapticScale>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "HapticScaleNotSupported");
+ return ndk::ScopedAStatus::ok();
+ }
+ case HapticGenerator::vibratorInfo: {
+ RETURN_IF(mContext->setHgVibratorInformation(
+ hgParam.get<HapticGenerator::vibratorInfo>()) != RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "VibratorInfoNotSupported");
+ return ndk::ScopedAStatus::ok();
+ }
+ default: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_ARGUMENT, "HapticGeneratorTagNotSupported");
+ }
+ }
}
ndk::ScopedAStatus HapticGeneratorSw::getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) {
auto tag = id.getTag();
RETURN_IF(Parameter::Id::hapticGeneratorTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
- specific->set<Parameter::Specific::hapticGenerator>(mSpecificParam);
+ auto hgId = id.get<Parameter::Id::hapticGeneratorTag>();
+ auto hgIdTag = hgId.getTag();
+ switch (hgIdTag) {
+ case HapticGenerator::Id::commonTag:
+ return getParameterHapticGenerator(hgId.get<HapticGenerator::Id::commonTag>(),
+ specific);
+ default:
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_ARGUMENT, "HapticGeneratorTagNotSupported");
+ }
+}
+
+ndk::ScopedAStatus HapticGeneratorSw::getParameterHapticGenerator(const HapticGenerator::Tag& tag,
+ Parameter::Specific* specific) {
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+ HapticGenerator hgParam;
+ switch (tag) {
+ case HapticGenerator::hapticScale: {
+ hgParam.set<HapticGenerator::hapticScale>(mContext->getHgHapticScale());
+ break;
+ }
+ case HapticGenerator::vibratorInfo: {
+ hgParam.set<HapticGenerator::vibratorInfo>(mContext->getHgVibratorInformation());
+ break;
+ }
+ default: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_ARGUMENT, "HapticGeneratorTagNotSupported");
+ }
+ }
+
+ specific->set<Parameter::Specific::hapticGenerator>(hgParam);
return ndk::ScopedAStatus::ok();
}
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 +174,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..d9ec744 100644
--- a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h
+++ b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h
@@ -32,11 +32,38 @@
: EffectContext(statusDepth, common) {
LOG(DEBUG) << __func__;
}
- // TODO: add specific context here
+
+ RetCode setHgHapticScale(const HapticGenerator::HapticScale& hapticScale) {
+ // All int values are valid for ID
+ mHapticScale = hapticScale;
+ return RetCode::SUCCESS;
+ }
+ HapticGenerator::HapticScale getHgHapticScale() const { return mHapticScale; }
+
+ RetCode setHgVibratorInformation(const HapticGenerator::VibratorInformation& vibratorInfo) {
+ // All float values are valid for resonantFrequencyHz, qFactor, maxAmplitude
+ mVibratorInformation = vibratorInfo;
+ return RetCode::SUCCESS;
+ }
+
+ HapticGenerator::VibratorInformation getHgVibratorInformation() const {
+ return mVibratorInformation;
+ }
+
+ private:
+ static constexpr float DEFAULT_RESONANT_FREQUENCY = 150.0f;
+ static constexpr float DEFAULT_Q_FACTOR = 1.0f;
+ static constexpr float DEFAULT_MAX_AMPLITUDE = 0.0f;
+ HapticGenerator::HapticScale mHapticScale = {0, HapticGenerator::VibratorScale::MUTE};
+ HapticGenerator::VibratorInformation mVibratorInformation = {
+ DEFAULT_RESONANT_FREQUENCY, DEFAULT_Q_FACTOR, DEFAULT_MAX_AMPLITUDE};
};
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,27 +74,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<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;
+ ndk::ScopedAStatus getParameterHapticGenerator(const HapticGenerator::Tag& tag,
+ Parameter::Specific* specific);
};
} // namespace aidl::android::hardware::audio::effect
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 d5cd30b..3b4c494 100644
--- a/audio/aidl/default/include/core-impl/Configuration.h
+++ b/audio/aidl/default/include/core-impl/Configuration.h
@@ -17,16 +17,19 @@
#pragma once
#include <map>
+#include <memory>
#include <vector>
#include <aidl/android/hardware/audio/core/AudioPatch.h>
#include <aidl/android/hardware/audio/core/AudioRoute.h>
+#include <aidl/android/hardware/audio/core/MicrophoneInfo.h>
#include <aidl/android/media/audio/common/AudioPort.h>
#include <aidl/android/media/audio/common/AudioPortConfig.h>
namespace aidl::android::hardware::audio::core::internal {
struct Configuration {
+ std::vector<MicrophoneInfo> microphones;
std::vector<::aidl::android::media::audio::common::AudioPort> ports;
std::vector<::aidl::android::media::audio::common::AudioPortConfig> portConfigs;
std::vector<::aidl::android::media::audio::common::AudioPortConfig> initialConfigs;
@@ -39,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 0086743..aa05d2a 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(
@@ -77,19 +80,40 @@
ndk::ScopedAStatus setMasterVolume(float in_volume) override;
ndk::ScopedAStatus getMicMute(bool* _aidl_return) override;
ndk::ScopedAStatus setMicMute(bool in_mute) override;
+ ndk::ScopedAStatus getMicrophones(std::vector<MicrophoneInfo>* _aidl_return) override;
ndk::ScopedAStatus updateAudioMode(
::aidl::android::hardware::audio::core::AudioMode in_mode) override;
ndk::ScopedAStatus updateScreenRotation(
::aidl::android::hardware::audio::core::IModule::ScreenRotation in_rotation) override;
ndk::ScopedAStatus updateScreenState(bool in_isTurnedOn) override;
+ ndk::ScopedAStatus getSoundDose(std::shared_ptr<ISoundDose>* _aidl_return) override;
+ ndk::ScopedAStatus generateHwAvSyncId(int32_t* _aidl_return) override;
+ ndk::ScopedAStatus getVendorParameters(const std::vector<std::string>& in_ids,
+ std::vector<VendorParameter>* _aidl_return) override;
+ ndk::ScopedAStatus setVendorParameters(const std::vector<VendorParameter>& in_parameters,
+ bool in_async) override;
+ ndk::ScopedAStatus addDeviceEffect(
+ int32_t in_portConfigId,
+ const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect)
+ override;
+ ndk::ScopedAStatus removeDeviceEffect(
+ int32_t in_portConfigId,
+ const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect)
+ override;
void cleanUpPatch(int32_t patchId);
ndk::ScopedAStatus createStreamContext(
int32_t in_portConfigId, int64_t in_bufferSizeFrames,
+ std::shared_ptr<IStreamCallback> asyncCallback,
::aidl::android::hardware::audio::core::StreamContext* out_context);
+ std::vector<::aidl::android::media::audio::common::AudioDevice> findConnectedDevices(
+ int32_t portConfigId);
+ std::set<int32_t> findConnectedPortConfigIds(int32_t portConfigId);
ndk::ScopedAStatus findPortIdForNewStream(
int32_t in_portConfigId, ::aidl::android::media::audio::common::AudioPort** port);
internal::Configuration& getConfig();
+ template <typename C>
+ std::set<int32_t> portIdsFromPortConfigIds(C portConfigIds);
void registerPatch(const AudioPatch& patch);
void updateStreamsConnectedState(const AudioPatch& oldPatch, const AudioPatch& newPatch);
@@ -98,11 +122,13 @@
// 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
// if the client has released it on its side, we need to hold it via a strong pointer.
std::shared_ptr<ITelephony> mTelephony;
+ ndk::SpAIBinder mTelephonyBinder;
// ids of ports created at runtime via 'connectExternalDevice'.
std::set<int32_t> mConnectedDevicePorts;
Streams mStreams;
@@ -112,6 +138,8 @@
bool mMasterMute = false;
float mMasterVolume = 1.0f;
bool mMicMute = false;
+ std::shared_ptr<ISoundDose> mSoundDose;
+ ndk::SpAIBinder mSoundDoseBinder;
};
} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/SoundDose.h b/audio/aidl/default/include/core-impl/SoundDose.h
new file mode 100644
index 0000000..54a6cbf
--- /dev/null
+++ b/audio/aidl/default/include/core-impl/SoundDose.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <mutex>
+
+#include <aidl/android/hardware/audio/core/BnSoundDose.h>
+#include <aidl/android/media/audio/common/AudioDevice.h>
+
+using aidl::android::media::audio::common::AudioDevice;
+
+namespace aidl::android::hardware::audio::core {
+
+class SoundDose : public BnSoundDose {
+ public:
+ SoundDose() : mRs2Value(DEFAULT_MAX_RS2){};
+
+ ndk::ScopedAStatus setOutputRs2(float in_rs2ValueDbA) override;
+ ndk::ScopedAStatus getOutputRs2(float* _aidl_return) override;
+ ndk::ScopedAStatus registerSoundDoseCallback(
+ const std::shared_ptr<ISoundDose::IHalSoundDoseCallback>& in_callback) override;
+
+ private:
+ std::shared_ptr<ISoundDose::IHalSoundDoseCallback> mCallback;
+ float mRs2Value;
+};
+
+} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h
index 5ee0f82..a5d240f 100644
--- a/audio/aidl/default/include/core-impl/Stream.h
+++ b/audio/aidl/default/include/core-impl/Stream.h
@@ -17,6 +17,7 @@
#pragma once
#include <atomic>
+#include <chrono>
#include <cstdlib>
#include <map>
#include <memory>
@@ -26,9 +27,13 @@
#include <StreamWorker.h>
#include <aidl/android/hardware/audio/common/SinkMetadata.h>
#include <aidl/android/hardware/audio/common/SourceMetadata.h>
+#include <aidl/android/hardware/audio/core/BnStreamCommon.h>
#include <aidl/android/hardware/audio/core/BnStreamIn.h>
#include <aidl/android/hardware/audio/core/BnStreamOut.h>
+#include <aidl/android/hardware/audio/core/IStreamCallback.h>
+#include <aidl/android/hardware/audio/core/MicrophoneInfo.h>
#include <aidl/android/hardware/audio/core/StreamDescriptor.h>
+#include <aidl/android/media/audio/common/AudioDevice.h>
#include <aidl/android/media/audio/common/AudioOffloadInfo.h>
#include <fmq/AidlMessageQueue.h>
#include <system/thread_defs.h>
@@ -59,33 +64,53 @@
StreamContext() = default;
StreamContext(std::unique_ptr<CommandMQ> commandMQ, std::unique_ptr<ReplyMQ> replyMQ,
- size_t frameSize, std::unique_ptr<DataMQ> dataMQ)
+ const ::aidl::android::media::audio::common::AudioFormatDescription& format,
+ const ::aidl::android::media::audio::common::AudioChannelLayout& channelLayout,
+ std::unique_ptr<DataMQ> dataMQ, std::shared_ptr<IStreamCallback> asyncCallback,
+ int transientStateDelayMs)
: mCommandMQ(std::move(commandMQ)),
mInternalCommandCookie(std::rand()),
mReplyMQ(std::move(replyMQ)),
- mFrameSize(frameSize),
- mDataMQ(std::move(dataMQ)) {}
+ mFormat(format),
+ mChannelLayout(channelLayout),
+ mDataMQ(std::move(dataMQ)),
+ mAsyncCallback(asyncCallback),
+ mTransientStateDelayMs(transientStateDelayMs) {}
StreamContext(StreamContext&& other)
: mCommandMQ(std::move(other.mCommandMQ)),
mInternalCommandCookie(other.mInternalCommandCookie),
mReplyMQ(std::move(other.mReplyMQ)),
- mFrameSize(other.mFrameSize),
- mDataMQ(std::move(other.mDataMQ)) {}
+ mFormat(other.mFormat),
+ mChannelLayout(other.mChannelLayout),
+ mDataMQ(std::move(other.mDataMQ)),
+ mAsyncCallback(other.mAsyncCallback),
+ mTransientStateDelayMs(other.mTransientStateDelayMs) {}
StreamContext& operator=(StreamContext&& other) {
mCommandMQ = std::move(other.mCommandMQ);
mInternalCommandCookie = other.mInternalCommandCookie;
mReplyMQ = std::move(other.mReplyMQ);
- mFrameSize = other.mFrameSize;
+ mFormat = std::move(other.mFormat);
+ mChannelLayout = std::move(other.mChannelLayout);
mDataMQ = std::move(other.mDataMQ);
+ mAsyncCallback = other.mAsyncCallback;
+ mTransientStateDelayMs = other.mTransientStateDelayMs;
return *this;
}
void fillDescriptor(StreamDescriptor* desc);
+ std::shared_ptr<IStreamCallback> getAsyncCallback() const { return mAsyncCallback; }
+ ::aidl::android::media::audio::common::AudioChannelLayout getChannelLayout() const {
+ return mChannelLayout;
+ }
CommandMQ* getCommandMQ() const { return mCommandMQ.get(); }
DataMQ* getDataMQ() const { return mDataMQ.get(); }
- size_t getFrameSize() const { return mFrameSize; }
+ ::aidl::android::media::audio::common::AudioFormatDescription getFormat() const {
+ return mFormat;
+ }
+ size_t getFrameSize() const;
int getInternalCommandCookie() const { return mInternalCommandCookie; }
ReplyMQ* getReplyMQ() const { return mReplyMQ.get(); }
+ int getTransientStateDelayMs() const { return mTransientStateDelayMs; }
bool isValid() const;
void reset();
@@ -93,8 +118,11 @@
std::unique_ptr<CommandMQ> mCommandMQ;
int mInternalCommandCookie; // The value used to confirm that the command was posted internally
std::unique_ptr<ReplyMQ> mReplyMQ;
- size_t mFrameSize;
+ ::aidl::android::media::audio::common::AudioFormatDescription mFormat;
+ ::aidl::android::media::audio::common::AudioChannelLayout mChannelLayout;
std::unique_ptr<DataMQ> mDataMQ;
+ std::shared_ptr<IStreamCallback> mAsyncCallback;
+ int mTransientStateDelayMs;
};
class StreamWorkerCommonLogic : public ::android::hardware::audio::common::StreamLogic {
@@ -111,9 +139,17 @@
mFrameSize(context.getFrameSize()),
mCommandMQ(context.getCommandMQ()),
mReplyMQ(context.getReplyMQ()),
- mDataMQ(context.getDataMQ()) {}
+ mDataMQ(context.getDataMQ()),
+ mAsyncCallback(context.getAsyncCallback()),
+ mTransientStateDelayMs(context.getTransientStateDelayMs()) {}
std::string init() override;
void populateReply(StreamDescriptor::Reply* reply, bool isConnected) const;
+ void populateReplyWrongState(StreamDescriptor::Reply* reply,
+ const StreamDescriptor::Command& command) const;
+ void switchToTransientState(StreamDescriptor::State state) {
+ mState = state;
+ mTransientStateStart = std::chrono::steady_clock::now();
+ }
// Atomic fields are used both by the main and worker threads.
std::atomic<bool> mIsConnected = false;
@@ -125,6 +161,9 @@
StreamContext::CommandMQ* mCommandMQ;
StreamContext::ReplyMQ* mReplyMQ;
StreamContext::DataMQ* mDataMQ;
+ std::shared_ptr<IStreamCallback> mAsyncCallback;
+ const std::chrono::duration<int, std::milli> mTransientStateDelayMs;
+ std::chrono::time_point<std::chrono::steady_clock> mTransientStateStart;
// We use an array and the "size" field instead of a vector to be able to detect
// memory allocation issues.
std::unique_ptr<int8_t[]> mDataBuffer;
@@ -159,76 +198,205 @@
};
using StreamOutWorker = ::android::hardware::audio::common::StreamWorker<StreamOutWorkerLogic>;
-template <class Metadata, class StreamWorker>
-class StreamCommon {
+// This provides a C++ interface with methods of the IStreamCommon Binder interface,
+// but intentionally does not inherit from it. This is needed to avoid inheriting
+// StreamIn and StreamOut from two Binder interface classes, as these parts of the class
+// will be reference counted separately.
+//
+// The implementation of these common methods is in the StreamCommonImpl template class.
+struct StreamCommonInterface {
+ virtual ~StreamCommonInterface() = default;
+ virtual ndk::ScopedAStatus close() = 0;
+ virtual ndk::ScopedAStatus updateHwAvSyncId(int32_t in_hwAvSyncId) = 0;
+ virtual ndk::ScopedAStatus getVendorParameters(const std::vector<std::string>& in_ids,
+ std::vector<VendorParameter>* _aidl_return) = 0;
+ virtual ndk::ScopedAStatus setVendorParameters(
+ const std::vector<VendorParameter>& in_parameters, bool in_async) = 0;
+ virtual ndk::ScopedAStatus addEffect(
+ const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>&
+ in_effect) = 0;
+ virtual ndk::ScopedAStatus removeEffect(
+ const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>&
+ in_effect) = 0;
+};
+
+class StreamCommon : public BnStreamCommon {
public:
- ndk::ScopedAStatus close();
+ explicit StreamCommon(const std::shared_ptr<StreamCommonInterface>& delegate)
+ : mDelegate(delegate) {}
+
+ private:
+ ndk::ScopedAStatus close() override {
+ auto delegate = mDelegate.lock();
+ return delegate != nullptr ? delegate->close()
+ : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
+ ndk::ScopedAStatus updateHwAvSyncId(int32_t in_hwAvSyncId) override {
+ auto delegate = mDelegate.lock();
+ return delegate != nullptr ? delegate->updateHwAvSyncId(in_hwAvSyncId)
+ : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
+ ndk::ScopedAStatus getVendorParameters(const std::vector<std::string>& in_ids,
+ std::vector<VendorParameter>* _aidl_return) override {
+ auto delegate = mDelegate.lock();
+ return delegate != nullptr ? delegate->getVendorParameters(in_ids, _aidl_return)
+ : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
+ ndk::ScopedAStatus setVendorParameters(const std::vector<VendorParameter>& in_parameters,
+ bool in_async) override {
+ auto delegate = mDelegate.lock();
+ return delegate != nullptr ? delegate->setVendorParameters(in_parameters, in_async)
+ : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
+ ndk::ScopedAStatus addEffect(
+ const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect)
+ override {
+ auto delegate = mDelegate.lock();
+ return delegate != nullptr ? delegate->addEffect(in_effect)
+ : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
+ ndk::ScopedAStatus removeEffect(
+ const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect)
+ override {
+ auto delegate = mDelegate.lock();
+ return delegate != nullptr ? delegate->removeEffect(in_effect)
+ : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
+ // It is possible that on the client side the proxy for IStreamCommon will outlive
+ // the IStream* instance, and the server side IStream* instance will get destroyed
+ // while this IStreamCommon instance is still alive.
+ std::weak_ptr<StreamCommonInterface> mDelegate;
+};
+
+template <class Metadata, class StreamWorker>
+class StreamCommonImpl : public StreamCommonInterface {
+ public:
+ ndk::ScopedAStatus close() override;
+ ndk::ScopedAStatus updateHwAvSyncId(int32_t in_hwAvSyncId) override;
+ ndk::ScopedAStatus getVendorParameters(const std::vector<std::string>& in_ids,
+ std::vector<VendorParameter>* _aidl_return) override;
+ ndk::ScopedAStatus setVendorParameters(const std::vector<VendorParameter>& in_parameters,
+ bool in_async) override;
+ ndk::ScopedAStatus addEffect(
+ const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect)
+ override;
+ ndk::ScopedAStatus removeEffect(
+ const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect)
+ override;
+
+ ndk::ScopedAStatus getStreamCommon(std::shared_ptr<IStreamCommon>* _aidl_return);
ndk::ScopedAStatus init() {
return mWorker.start(StreamWorker::kThreadName, ANDROID_PRIORITY_AUDIO)
? ndk::ScopedAStatus::ok()
: ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}
bool isClosed() const { return mWorker.isClosed(); }
- void setIsConnected(bool connected) { mWorker.setIsConnected(connected); }
+ void setIsConnected(
+ const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) {
+ mWorker.setIsConnected(!devices.empty());
+ mConnectedDevices = devices;
+ }
ndk::ScopedAStatus updateMetadata(const Metadata& metadata);
protected:
- StreamCommon(const Metadata& metadata, StreamContext context)
+ StreamCommonImpl(const Metadata& metadata, StreamContext&& context)
: mMetadata(metadata), mContext(std::move(context)), mWorker(mContext) {}
- ~StreamCommon();
+ ~StreamCommonImpl();
void stopWorker();
+ void createStreamCommon(const std::shared_ptr<StreamCommonInterface>& delegate);
+ std::shared_ptr<StreamCommon> mCommon;
+ ndk::SpAIBinder mCommonBinder;
Metadata mMetadata;
StreamContext mContext;
StreamWorker mWorker;
+ std::vector<::aidl::android::media::audio::common::AudioDevice> mConnectedDevices;
};
-class StreamIn
- : public StreamCommon<::aidl::android::hardware::audio::common::SinkMetadata, StreamInWorker>,
- public BnStreamIn {
- ndk::ScopedAStatus close() override {
- return StreamCommon<::aidl::android::hardware::audio::common::SinkMetadata,
- StreamInWorker>::close();
+class StreamIn : public StreamCommonImpl<::aidl::android::hardware::audio::common::SinkMetadata,
+ StreamInWorker>,
+ public BnStreamIn {
+ ndk::ScopedAStatus getStreamCommon(std::shared_ptr<IStreamCommon>* _aidl_return) override {
+ return StreamCommonImpl<::aidl::android::hardware::audio::common::SinkMetadata,
+ StreamInWorker>::getStreamCommon(_aidl_return);
}
+ ndk::ScopedAStatus getActiveMicrophones(
+ std::vector<MicrophoneDynamicInfo>* _aidl_return) override;
+ ndk::ScopedAStatus getMicrophoneDirection(MicrophoneDirection* _aidl_return) override;
+ ndk::ScopedAStatus setMicrophoneDirection(MicrophoneDirection in_direction) override;
+ ndk::ScopedAStatus getMicrophoneFieldDimension(float* _aidl_return) override;
+ ndk::ScopedAStatus setMicrophoneFieldDimension(float in_zoom) override;
ndk::ScopedAStatus updateMetadata(const ::aidl::android::hardware::audio::common::SinkMetadata&
in_sinkMetadata) override {
- return StreamCommon<::aidl::android::hardware::audio::common::SinkMetadata,
- StreamInWorker>::updateMetadata(in_sinkMetadata);
+ return StreamCommonImpl<::aidl::android::hardware::audio::common::SinkMetadata,
+ StreamInWorker>::updateMetadata(in_sinkMetadata);
}
+ ndk::ScopedAStatus getHwGain(std::vector<float>* _aidl_return) override;
+ ndk::ScopedAStatus setHwGain(const std::vector<float>& in_channelGains) override;
public:
+ static ndk::ScopedAStatus createInstance(
+ const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
+ StreamContext context, const std::vector<MicrophoneInfo>& microphones,
+ std::shared_ptr<StreamIn>* result);
+
+ private:
+ friend class ndk::SharedRefBase;
StreamIn(const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
- StreamContext context);
+ StreamContext&& context, const std::vector<MicrophoneInfo>& microphones);
+ void createStreamCommon(const std::shared_ptr<StreamIn>& myPtr) {
+ StreamCommonImpl<::aidl::android::hardware::audio::common::SinkMetadata,
+ StreamInWorker>::createStreamCommon(myPtr);
+ }
+
+ const std::map<::aidl::android::media::audio::common::AudioDevice, std::string> mMicrophones;
};
-class StreamOut : public StreamCommon<::aidl::android::hardware::audio::common::SourceMetadata,
- StreamOutWorker>,
+class StreamOut : public StreamCommonImpl<::aidl::android::hardware::audio::common::SourceMetadata,
+ StreamOutWorker>,
public BnStreamOut {
- ndk::ScopedAStatus close() override {
- return StreamCommon<::aidl::android::hardware::audio::common::SourceMetadata,
- StreamOutWorker>::close();
+ ndk::ScopedAStatus getStreamCommon(std::shared_ptr<IStreamCommon>* _aidl_return) override {
+ return StreamCommonImpl<::aidl::android::hardware::audio::common::SourceMetadata,
+ StreamOutWorker>::getStreamCommon(_aidl_return);
}
ndk::ScopedAStatus updateMetadata(
const ::aidl::android::hardware::audio::common::SourceMetadata& in_sourceMetadata)
override {
- return StreamCommon<::aidl::android::hardware::audio::common::SourceMetadata,
- StreamOutWorker>::updateMetadata(in_sourceMetadata);
+ return StreamCommonImpl<::aidl::android::hardware::audio::common::SourceMetadata,
+ StreamOutWorker>::updateMetadata(in_sourceMetadata);
}
+ ndk::ScopedAStatus getHwVolume(std::vector<float>* _aidl_return) override;
+ ndk::ScopedAStatus setHwVolume(const std::vector<float>& in_channelVolumes) override;
public:
- StreamOut(const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
- StreamContext context,
- const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
- offloadInfo);
+ static ndk::ScopedAStatus createInstance(
+ const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
+ StreamContext context,
+ const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
+ offloadInfo,
+ std::shared_ptr<StreamOut>* result);
private:
+ friend class ndk::SharedRefBase;
+ StreamOut(const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
+ StreamContext&& context,
+ const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
+ offloadInfo);
+ void createStreamCommon(const std::shared_ptr<StreamOut>& myPtr) {
+ StreamCommonImpl<::aidl::android::hardware::audio::common::SourceMetadata,
+ StreamOutWorker>::createStreamCommon(myPtr);
+ }
+
std::optional<::aidl::android::media::audio::common::AudioOffloadInfo> mOffloadInfo;
};
class StreamWrapper {
public:
- explicit StreamWrapper(std::shared_ptr<StreamIn> streamIn) : mStream(streamIn) {}
- explicit StreamWrapper(std::shared_ptr<StreamOut> streamOut) : mStream(streamOut) {}
+ explicit StreamWrapper(const std::shared_ptr<StreamIn>& streamIn)
+ : mStream(streamIn), mStreamBinder(streamIn->asBinder()) {}
+ explicit StreamWrapper(const std::shared_ptr<StreamOut>& streamOut)
+ : mStream(streamOut), mStreamBinder(streamOut->asBinder()) {}
+ ndk::SpAIBinder getBinder() const { return mStreamBinder; }
bool isStreamOpen() const {
return std::visit(
[](auto&& ws) -> bool {
@@ -237,17 +405,19 @@
},
mStream);
}
- void setStreamIsConnected(bool connected) {
+ void setStreamIsConnected(
+ const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) {
std::visit(
[&](auto&& ws) {
auto s = ws.lock();
- if (s) s->setIsConnected(connected);
+ if (s) s->setIsConnected(devices);
},
mStream);
}
private:
std::variant<std::weak_ptr<StreamIn>, std::weak_ptr<StreamOut>> mStream;
+ ndk::SpAIBinder mStreamBinder;
};
class Streams {
@@ -264,9 +434,11 @@
mStreams.insert(std::pair{portConfigId, sw});
mStreams.insert(std::pair{portId, std::move(sw)});
}
- void setStreamIsConnected(int32_t portConfigId, bool connected) {
+ void setStreamIsConnected(
+ int32_t portConfigId,
+ const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) {
if (auto it = mStreams.find(portConfigId); it != mStreams.end()) {
- it->second.setStreamIsConnected(connected);
+ it->second.setStreamIsConnected(devices);
}
}
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..1f39db0 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,24 +71,19 @@
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
+ // reset buffer status by abandon input data 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());
- mStatusMQ->read(status.data(), mStatusMQ->availableToRead());
}
void dupeFmq(IEffect::OpenEffectReturn* effectRet) {
if (effectRet) {
- effectRet->statusMQ = getStatusFmq()->dupeDesc();
- effectRet->inputDataMQ = getInputDataFmq()->dupeDesc();
- effectRet->outputDataMQ = getOutputDataFmq()->dupeDesc();
+ effectRet->statusMQ = mStatusMQ->dupeDesc();
+ effectRet->inputDataMQ = mInputMQ->dupeDesc();
+ effectRet->outputDataMQ = mOutputMQ->dupeDesc();
}
}
size_t getInputFrameSize() { return mInputFrameSize; }
@@ -138,7 +130,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/EffectUUID.h b/audio/aidl/default/include/effect-impl/EffectUUID.h
index 7709eab..c9bb1f4 100644
--- a/audio/aidl/default/include/effect-impl/EffectUUID.h
+++ b/audio/aidl/default/include/effect-impl/EffectUUID.h
@@ -45,6 +45,18 @@
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// 8631f300-72e2-11df-b57e-0002a5d5c51b
+static const AudioUuid kBassBoostBundleImplUUID = {static_cast<int32_t>(0x8631f300),
+ 0x72e2,
+ 0x11df,
+ 0xb57e,
+ {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+// 14804144-a5ee-4d24-aa88-0002a5d5c51b
+static const AudioUuid kBassBoostProxyUUID = {static_cast<int32_t>(0x14804144),
+ 0xa5ee,
+ 0x4d24,
+ 0xaa88,
+ {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
// fa81862a-588b-11ed-9b6a-0242ac120002
static const AudioUuid kDownmixTypeUUID = {static_cast<int32_t>(0xfa81862a),
0x588b,
@@ -57,6 +69,12 @@
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// 93f04452-e4fe-41cc-91f9-e475b6d1d69f
+static const AudioUuid kDownmixImplUUID = {static_cast<int32_t>(0x93f04452),
+ 0xe4fe,
+ 0x41cc,
+ 0x91f9,
+ {0xe4, 0x75, 0xb6, 0xd1, 0xd6, 0x9f}};
// 0bed4300-ddd6-11db-8f34-0002a5d5c51b.
static const AudioUuid kEqualizerTypeUUID = {static_cast<int32_t>(0x0bed4300),
0xddd6,
@@ -117,6 +135,12 @@
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// fa415329-2034-4bea-b5dc-5b381c8d1e2c
+static const AudioUuid kLoudnessEnhancerImplUUID = {static_cast<int32_t>(0xfa415329),
+ 0x2034,
+ 0x4bea,
+ 0xb5dc,
+ {0x5b, 0x38, 0x1c, 0x8d, 0x1e, 0x2c}};
// c2e5d5f0-94bd-4763-9cac-4e234d06839e
static const AudioUuid kEnvReverbTypeUUID = {static_cast<int32_t>(0xc2e5d5f0),
0x94bd,
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..04bd1bb 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,15 +83,21 @@
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;
- std::map<std::weak_ptr<IEffect>, aidl::android::media::audio::common::AudioUuid,
- std::owner_less<>>
- mEffectUuidMap;
+ 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;
+
+ typedef std::pair<aidl::android::media::audio::common::AudioUuid, ndk::SpAIBinder> EffectEntry;
+ std::map<std::weak_ptr<IEffect>, EffectEntry, std::owner_less<>> mEffectMap;
ndk::ScopedAStatus destroyEffectImpl(const std::shared_ptr<IEffect>& in_handle);
void cleanupEffectMap();
@@ -101,6 +108,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 15874a0..b66c134 100644
--- a/audio/aidl/default/main.cpp
+++ b/audio/aidl/default/main.cpp
@@ -16,14 +16,16 @@
#include <cstdlib>
#include <ctime>
+#include <utility>
+
+#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"
-#include <android-base/logging.h>
-#include <android/binder_manager.h>
-#include <android/binder_process.h>
-
using aidl::android::hardware::audio::core::Config;
using aidl::android::hardware::audio::core::Module;
@@ -42,11 +44,18 @@
AServiceManager_addService(config->asBinder().get(), configName.c_str());
CHECK_EQ(STATUS_OK, status);
- // Make the default module
- auto moduleDefault = ndk::SharedRefBase::make<Module>();
- const std::string moduleDefaultName = std::string() + Module::descriptor + "/default";
- status = AServiceManager_addService(moduleDefault->asBinder().get(), moduleDefaultName.c_str());
- CHECK_EQ(STATUS_OK, status);
+ // Make modules
+ auto createModule = [](Module::Type type, const std::string& instance) {
+ auto module = ndk::SharedRefBase::make<Module>(type);
+ ndk::SpAIBinder moduleBinder = module->asBinder();
+ const std::string moduleName = std::string(Module::descriptor).append("/").append(instance);
+ AIBinder_setMinSchedulerPolicy(moduleBinder.get(), SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
+ binder_status_t status = AServiceManager_addService(moduleBinder.get(), moduleName.c_str());
+ CHECK_EQ(STATUS_OK, status);
+ return std::make_pair(module, moduleBinder);
+ };
+ auto modules = {createModule(Module::Type::DEFAULT, "default"),
+ createModule(Module::Type::R_SUBMIX, "r_submix")};
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..37eb30b 100644
--- a/audio/aidl/default/visualizer/VisualizerSw.cpp
+++ b/audio/aidl/default/visualizer/VisualizerSw.cpp
@@ -14,17 +14,13 @@
* limitations under the License.
*/
-#include <cstddef>
#define LOG_TAG "AHAL_VisualizerSw"
-#include <Utils.h>
-#include <algorithm>
-#include <unordered_set>
#include <android-base/logging.h>
-#include <fmq/AidlMessageQueue.h>
#include "VisualizerSw.h"
+using aidl::android::hardware::audio::effect::Descriptor;
using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::hardware::audio::effect::kVisualizerSwImplUUID;
using aidl::android::hardware::audio::effect::State;
@@ -47,23 +43,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 != 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";
+/* capabilities */
+const Visualizer::CaptureSizeRange mCaptureSizeRange = {MIN_CAPTURE_SIZE, MAX_CAPTURE_SIZE};
+const Visualizer::Capability VisualizerSw::kCapability = {.maxLatencyMs = MAX_LATENCY,
+ .captureSizeRange = mCaptureSizeRange};
+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,11 +79,54 @@
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();
+ auto& vsParam = specific.get<Parameter::Specific::visualizer>();
+ auto tag = vsParam.getTag();
+
+ switch (tag) {
+ case Visualizer::captureSizeBytes: {
+ RETURN_IF(mContext->setVsCaptureSize(vsParam.get<Visualizer::captureSizeBytes>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "captureSizeNotSupported");
+ return ndk::ScopedAStatus::ok();
+ }
+ case Visualizer::scalingMode: {
+ RETURN_IF(mContext->setVsScalingMode(vsParam.get<Visualizer::scalingMode>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "scalingModeNotSupported");
+ return ndk::ScopedAStatus::ok();
+ }
+ case Visualizer::measurementMode: {
+ RETURN_IF(mContext->setVsMeasurementMode(vsParam.get<Visualizer::measurementMode>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "measurementModeNotSupported");
+ return ndk::ScopedAStatus::ok();
+ }
+ case Visualizer::setOnlyParameters: {
+ return setSetOnlyParameterVisualizer(vsParam.get<Visualizer::setOnlyParameters>());
+ }
+ case Visualizer::getOnlyParameters: {
+ LOG(ERROR) << __func__ << " unsupported settable getOnlyParam";
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_ARGUMENT, "SetofGetOnlyParamsNotSupported");
+ }
+ default: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "VisualizerTagNotSupported");
+ }
+ }
+}
+
+ndk::ScopedAStatus VisualizerSw::setSetOnlyParameterVisualizer(
+ Visualizer::SetOnlyParameters setOnlyParam) {
+ auto tag = setOnlyParam.getTag();
+ RETURN_IF(Visualizer::SetOnlyParameters::latencyMs != tag, EX_ILLEGAL_ARGUMENT,
+ "SetOnlyParametersTagNotSupported");
+ RETURN_IF(
+ mContext->setVsLatency(setOnlyParam.get<Visualizer::SetOnlyParameters::latencyMs>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "latencyNotSupported");
return ndk::ScopedAStatus::ok();
}
@@ -85,16 +134,90 @@
Parameter::Specific* specific) {
auto tag = id.getTag();
RETURN_IF(Parameter::Id::visualizerTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
- specific->set<Parameter::Specific::visualizer>(mSpecificParam);
+ auto vsId = id.get<Parameter::Id::visualizerTag>();
+ auto vsIdTag = vsId.getTag();
+ switch (vsIdTag) {
+ case Visualizer::Id::commonTag:
+ return getParameterVisualizer(vsId.get<Visualizer::Id::commonTag>(), specific);
+ case Visualizer::Id::getOnlyParamTag:
+ return getGetOnlyParameterVisualizer(vsId.get<Visualizer::Id::getOnlyParamTag>(),
+ specific);
+ case Visualizer::Id::setOnlyParamTag: {
+ LOG(ERROR) << __func__ << " unsupported gettable setOnlyParam";
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_ARGUMENT, "GetofSetOnlyParamsNotSupported");
+ }
+ default:
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "VisualizerTagNotSupported");
+ }
+}
+ndk::ScopedAStatus VisualizerSw::getParameterVisualizer(const Visualizer::Tag& tag,
+ Parameter::Specific* specific) {
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+ Visualizer vsParam;
+ switch (tag) {
+ case Visualizer::captureSizeBytes: {
+ vsParam.set<Visualizer::captureSizeBytes>(mContext->getVsCaptureSize());
+ break;
+ }
+ case Visualizer::scalingMode: {
+ vsParam.set<Visualizer::scalingMode>(mContext->getVsScalingMode());
+ break;
+ }
+ case Visualizer::measurementMode: {
+ vsParam.set<Visualizer::measurementMode>(mContext->getVsMeasurementMode());
+ break;
+ }
+ default: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "VisualizerTagNotSupported");
+ }
+ }
+ specific->set<Parameter::Specific::visualizer>(vsParam);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus VisualizerSw::getGetOnlyParameterVisualizer(
+ const Visualizer::GetOnlyParameters::Tag& tag, Parameter::Specific* specific) {
+ Visualizer::GetOnlyParameters getOnlyParam;
+ switch (tag) {
+ case Visualizer::GetOnlyParameters::measurement: {
+ getOnlyParam.set<Visualizer::GetOnlyParameters::measurement>(
+ mContext->getVsMeasurement());
+ break;
+ }
+ case Visualizer::GetOnlyParameters::captureBytes: {
+ getOnlyParam.set<Visualizer::GetOnlyParameters::captureBytes>(
+ mContext->getVsCaptureBytes());
+ break;
+ }
+ default: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_ARGUMENT, "GetOnlyParameterTagNotSupported");
+ }
+ }
+ Visualizer vsParam;
+ vsParam.set<Visualizer::getOnlyParameters>(getOnlyParam);
+ specific->set<Parameter::Specific::visualizer>(vsParam);
return ndk::ScopedAStatus::ok();
}
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 +229,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..a95537c 100644
--- a/audio/aidl/default/visualizer/VisualizerSw.h
+++ b/audio/aidl/default/visualizer/VisualizerSw.h
@@ -17,13 +17,16 @@
#pragma once
#include <aidl/android/hardware/audio/effect/BnEffect.h>
-#include <fmq/AidlMessageQueue.h>
-#include <cstdlib>
-#include <memory>
+#include <vector>
#include "effect-impl/EffectImpl.h"
#include "effect-impl/EffectUUID.h"
+#define MIN_CAPTURE_SIZE 128
+#define MAX_CAPTURE_SIZE 1024
+#define MAX_LATENCY 3000
+#define CAPTURE_BUF_SIZE 65536
+
namespace aidl::android::hardware::audio::effect {
class VisualizerSwContext final : public EffectContext {
@@ -31,12 +34,62 @@
VisualizerSwContext(int statusDepth, const Parameter::Common& common)
: EffectContext(statusDepth, common) {
LOG(DEBUG) << __func__;
+ mCaptureBytes.resize(CAPTURE_BUF_SIZE);
+ fill(mCaptureBytes.begin(), mCaptureBytes.end(), 0x80);
}
- // TODO: add specific context here
+
+ RetCode setVsCaptureSize(int captureSize) {
+ if (captureSize < MIN_CAPTURE_SIZE || captureSize > MAX_CAPTURE_SIZE) {
+ LOG(ERROR) << __func__ << " invalid captureSize " << captureSize;
+ return RetCode::ERROR_ILLEGAL_PARAMETER;
+ }
+ // TODO : Add implementation to apply new captureSize
+ mCaptureSize = captureSize;
+ return RetCode::SUCCESS;
+ }
+ int getVsCaptureSize() const { return mCaptureSize; }
+
+ RetCode setVsScalingMode(Visualizer::ScalingMode scalingMode) {
+ // TODO : Add implementation to apply new scalingMode
+ mScalingMode = scalingMode;
+ return RetCode::SUCCESS;
+ }
+ Visualizer::ScalingMode getVsScalingMode() const { return mScalingMode; }
+
+ RetCode setVsMeasurementMode(Visualizer::MeasurementMode measurementMode) {
+ // TODO : Add implementation to apply new measurementMode
+ mMeasurementMode = measurementMode;
+ return RetCode::SUCCESS;
+ }
+ Visualizer::MeasurementMode getVsMeasurementMode() const { return mMeasurementMode; }
+
+ RetCode setVsLatency(int latency) {
+ if (latency < 0 || latency > MAX_LATENCY) {
+ LOG(ERROR) << __func__ << " invalid latency " << latency;
+ return RetCode::ERROR_ILLEGAL_PARAMETER;
+ }
+ // TODO : Add implementation to modify latency
+ mLatency = latency;
+ return RetCode::SUCCESS;
+ }
+
+ Visualizer::GetOnlyParameters::Measurement getVsMeasurement() const { return mMeasurement; }
+ std::vector<uint8_t> getVsCaptureBytes() const { return mCaptureBytes; }
+
+ private:
+ int mCaptureSize = MAX_CAPTURE_SIZE;
+ Visualizer::ScalingMode mScalingMode = Visualizer::ScalingMode::NORMALIZED;
+ Visualizer::MeasurementMode mMeasurementMode = Visualizer::MeasurementMode::NONE;
+ int mLatency;
+ const Visualizer::GetOnlyParameters::Measurement mMeasurement = {0, 0};
+ std::vector<uint8_t> mCaptureBytes;
};
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,27 +100,21 @@
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;
+ ndk::ScopedAStatus setSetOnlyParameterVisualizer(Visualizer::SetOnlyParameters setOnlyParam);
+ ndk::ScopedAStatus getParameterVisualizer(const Visualizer::Tag& tag,
+ Parameter::Specific* specific);
+ ndk::ScopedAStatus getGetOnlyParameterVisualizer(const Visualizer::GetOnlyParameters::Tag& tag,
+ Parameter::Specific* specific);
};
} // namespace aidl::android::hardware::audio::effect
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/sounddose/Android.bp b/audio/aidl/sounddose/Android.bp
new file mode 100644
index 0000000..85d6e21
--- /dev/null
+++ b/audio/aidl/sounddose/Android.bp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+ // 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.audio.sounddose",
+ host_supported: true,
+ vendor_available: true,
+ stability: "vintf",
+ srcs: [
+ "android/hardware/audio/sounddose/ISoundDoseFactory.aidl",
+ ],
+ imports: [
+ latest_android_hardware_audio_core_sounddose,
+ ],
+ backend: {
+ // The C++ backend is disabled transitively due to use by core audio HAL.
+ cpp: {
+ enabled: false,
+ },
+ java: {
+ sdk_version: "module_current",
+ },
+ },
+ versions_with_info: [
+ // IMPORTANT: Update latest_android_hardware_audio_sounddose every time you
+ // add the latest frozen version to versions_with_info
+ ],
+}
+
+// Note: This should always be one version ahead of the last frozen version
+latest_android_hardware_audio_sounddose = "android.hardware.audio.sounddose-V1"
+
+// Modules that depend on android.hardware.audio.sounddose directly can include
+// the following cc_defaults to avoid explicitly managing dependency versions
+// across many scattered files.
+cc_defaults {
+ name: "latest_android_hardware_audio_sounddose_ndk_shared",
+ shared_libs: [
+ latest_android_hardware_audio_sounddose + "-ndk",
+ ],
+}
+
+cc_defaults {
+ name: "latest_android_hardware_audio_sounddose_ndk_static",
+ static_libs: [
+ latest_android_hardware_audio_sounddose + "-ndk",
+ ],
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl b/audio/aidl/sounddose/aidl_api/android.hardware.audio.core.sounddose/current/android/hardware/audio/core/ISoundDose.aidl
similarity index 71%
copy from audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
copy to audio/aidl/sounddose/aidl_api/android.hardware.audio.core.sounddose/current/android/hardware/audio/core/ISoundDose.aidl
index 8ad4848..dff17e2 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
+++ b/audio/aidl/sounddose/aidl_api/android.hardware.audio.core.sounddose/current/android/hardware/audio/core/ISoundDose.aidl
@@ -31,27 +31,21 @@
// with such a backward incompatible 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.audio.core;
@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;
+interface ISoundDose {
+ void setOutputRs2(float rs2ValueDbA);
+ float getOutputRs2();
+ void registerSoundDoseCallback(in android.hardware.audio.core.ISoundDose.IHalSoundDoseCallback callback);
+ const int DEFAULT_MAX_RS2 = 100;
@VintfStability
- union Id {
- int vendorExtensionTag;
- android.hardware.audio.effect.Reverb.Tag commonTag;
- }
- @VintfStability
- parcelable Capability {
- android.hardware.audio.effect.VendorExtension extension;
- int maxDecayTimeMs;
+ interface IHalSoundDoseCallback {
+ oneway void onMomentaryExposureWarning(float currentDbA, in android.media.audio.common.AudioDevice audioDevice);
+ oneway void onNewMelValues(in android.hardware.audio.core.ISoundDose.IHalSoundDoseCallback.MelRecord melRecord, in android.media.audio.common.AudioDevice audioDevice);
+ @VintfStability
+ parcelable MelRecord {
+ float[] melValues;
+ long timestamp;
+ }
}
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl b/audio/aidl/sounddose/aidl_api/android.hardware.audio.sounddose/current/android/hardware/audio/sounddose/ISoundDoseFactory.aidl
similarity index 75%
copy from audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
copy to audio/aidl/sounddose/aidl_api/android.hardware.audio.sounddose/current/android/hardware/audio/sounddose/ISoundDoseFactory.aidl
index 8ad4848..7dda011 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
+++ b/audio/aidl/sounddose/aidl_api/android.hardware.audio.sounddose/current/android/hardware/audio/sounddose/ISoundDoseFactory.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.audio.sounddose;
@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 ISoundDoseFactory {
+ @nullable android.hardware.audio.core.ISoundDose getSoundDose(in @utf8InCpp String module);
}
diff --git a/audio/aidl/sounddose/android/hardware/audio/sounddose/ISoundDoseFactory.aidl b/audio/aidl/sounddose/android/hardware/audio/sounddose/ISoundDoseFactory.aidl
new file mode 100644
index 0000000..3487237
--- /dev/null
+++ b/audio/aidl/sounddose/android/hardware/audio/sounddose/ISoundDoseFactory.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.sounddose;
+
+import android.hardware.audio.core.ISoundDose;
+
+/**
+ * This interface is used to provide an easy way to implement the ISoundDose interface
+ * without switching the audio HAL to AIDL. The implementation is intended as a workaround
+ * for the certification with IEC62368-1 3rd edition and EN50332-3.
+ * Note that this interface will be deprecated in favor of the audio AIDL HAL.
+ */
+@VintfStability
+interface ISoundDoseFactory {
+ /**
+ * Retrieve the sound dose interface for a given audio HAL module name.
+ *
+ * If a device must comply to IEC62368-1 3rd edition audio safety requirements and is
+ * implementing audio offload decoding or other direct playback paths where volume control
+ * happens below the audio HAL, it must return an instance of the ISoundDose interface.
+ * The same instance must be returned during the lifetime of the HAL module.
+ * If the HAL module does not support sound dose, null must be returned, without throwing
+ * any errors.
+ *
+ * @param module for which we trigger sound dose updates.
+ * @return An instance of the ISoundDose interface implementation.
+ * @throws EX_ILLEGAL_STATE If there was an error creating an instance.
+ */
+ @nullable ISoundDose getSoundDose(in @utf8InCpp String module);
+}
diff --git a/audio/aidl/sounddose/default/Android.bp b/audio/aidl/sounddose/default/Android.bp
new file mode 100644
index 0000000..bd770fa
--- /dev/null
+++ b/audio/aidl/sounddose/default/Android.bp
@@ -0,0 +1,46 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_defaults {
+ name: "aidlsounddoseservice_defaults",
+ vendor: true,
+ header_libs: [
+ "libsounddoseaidl_headers",
+ ],
+}
+
+cc_library {
+ name: "libsounddoseserviceexampleimpl",
+ defaults: [
+ "aidlsounddoseservice_defaults",
+ "latest_android_media_audio_common_types_ndk_shared",
+ "latest_android_hardware_audio_core_sounddose_ndk_shared",
+ "latest_android_hardware_audio_sounddose_ndk_shared",
+ ],
+ export_include_dirs: ["include"],
+ srcs: [
+ "SoundDoseFactory.cpp",
+ ],
+ shared_libs: [
+ "libaudioservicesounddoseimpl",
+ "libbase",
+ "libbinder_ndk",
+ ],
+
+ visibility: [
+ "//hardware/interfaces/audio/common/all-versions/default/service",
+ ],
+}
+
+cc_library_headers {
+ name: "libsounddoseaidl_headers",
+ export_include_dirs: ["include"],
+ vendor_available: true,
+ host_supported: true,
+}
diff --git a/audio/aidl/sounddose/default/SoundDoseFactory.cpp b/audio/aidl/sounddose/default/SoundDoseFactory.cpp
new file mode 100644
index 0000000..50796d0
--- /dev/null
+++ b/audio/aidl/sounddose/default/SoundDoseFactory.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AHAL_SoundDoseFactory"
+
+#include "SoundDoseFactory.h"
+
+#include <android-base/logging.h>
+#include <core-impl/SoundDose.h>
+
+namespace aidl::android::hardware::audio::sounddose {
+
+using ::aidl::android::hardware::audio::core::SoundDose;
+
+ndk::ScopedAStatus SoundDoseFactory::getSoundDose(const std::string& in_module,
+ std::shared_ptr<ISoundDose>* _aidl_return) {
+ auto soundDoseIt = mSoundDoseBinderMap.find(in_module);
+ if (soundDoseIt != mSoundDoseBinderMap.end()) {
+ *_aidl_return = ISoundDose::fromBinder(soundDoseIt->second);
+
+ LOG(DEBUG) << __func__
+ << ": returning cached instance of ISoundDose: " << _aidl_return->get()
+ << " for module " << in_module;
+ return ndk::ScopedAStatus::ok();
+ }
+
+ auto soundDose = ndk::SharedRefBase::make<SoundDose>();
+ mSoundDoseBinderMap[in_module] = soundDose->asBinder();
+ *_aidl_return = soundDose;
+
+ LOG(DEBUG) << __func__ << ": returning new instance of ISoundDose: " << _aidl_return->get()
+ << " for module " << in_module;
+ return ndk::ScopedAStatus::ok();
+}
+
+} // namespace aidl::android::hardware::audio::sounddose
diff --git a/audio/aidl/sounddose/default/include/SoundDoseFactory.h b/audio/aidl/sounddose/default/include/SoundDoseFactory.h
new file mode 100644
index 0000000..4cf3277
--- /dev/null
+++ b/audio/aidl/sounddose/default/include/SoundDoseFactory.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/audio/core/ISoundDose.h>
+#include <aidl/android/hardware/audio/sounddose/BnSoundDoseFactory.h>
+#include <android/binder_interface_utils.h>
+
+#include <unordered_map>
+
+namespace aidl::android::hardware::audio::sounddose {
+
+using ::aidl::android::hardware::audio::core::ISoundDose;
+
+class SoundDoseFactory : public BnSoundDoseFactory {
+ public:
+ ndk::ScopedAStatus getSoundDose(const std::string& module,
+ std::shared_ptr<ISoundDose>* _aidl_return) override;
+
+ private:
+ std::unordered_map<std::string, ndk::SpAIBinder> mSoundDoseBinderMap;
+};
+
+} // namespace aidl::android::hardware::audio::sounddose
diff --git a/audio/aidl/sounddose/vts/Android.bp b/audio/aidl/sounddose/vts/Android.bp
new file mode 100644
index 0000000..88be968
--- /dev/null
+++ b/audio/aidl/sounddose/vts/Android.bp
@@ -0,0 +1,36 @@
+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: "VtsHalSoundDoseFactoryTargetTest",
+ defaults: [
+ "latest_android_hardware_audio_core_sounddose_ndk_static",
+ "latest_android_hardware_audio_sounddose_ndk_static",
+ "latest_android_media_audio_common_types_ndk_static",
+ "use_libaidlvintf_gtest_helper_static",
+ "VtsHalTargetTestDefaults",
+ ],
+ shared_libs: [
+ "libbinder_ndk",
+ "libcutils",
+ ],
+ srcs: [
+ "VtsHalSoundDoseFactoryTargetTest.cpp",
+ ],
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-Wthread-safety",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+}
diff --git a/audio/aidl/sounddose/vts/TEST_MAPPING b/audio/aidl/sounddose/vts/TEST_MAPPING
new file mode 100644
index 0000000..bebeed9
--- /dev/null
+++ b/audio/aidl/sounddose/vts/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "VtsHalSoundDoseFactoryTargetTest"
+ }
+ ]
+}
diff --git a/audio/aidl/sounddose/vts/VtsHalSoundDoseFactoryTargetTest.cpp b/audio/aidl/sounddose/vts/VtsHalSoundDoseFactoryTargetTest.cpp
new file mode 100644
index 0000000..7448c1f
--- /dev/null
+++ b/audio/aidl/sounddose/vts/VtsHalSoundDoseFactoryTargetTest.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.
+ */
+
+#define LOG_TAG "VtsHalSoundDose.Factory"
+#include <android-base/logging.h>
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/audio/sounddose/ISoundDoseFactory.h>
+#include <android/binder_manager.h>
+
+#include <memory>
+
+namespace android::hardware::audio::common::testing {
+
+namespace detail {
+
+inline ::testing::AssertionResult assertIsOk(const char* expr, const ::ndk::ScopedAStatus& status) {
+ if (status.isOk()) {
+ return ::testing::AssertionSuccess();
+ }
+ return ::testing::AssertionFailure()
+ << "Expected the transaction \'" << expr << "\' to succeed\n"
+ << " but it has failed with: " << status;
+}
+
+} // namespace detail
+
+} // namespace android::hardware::audio::common::testing
+
+// Test that the transaction status 'isOk'
+#define EXPECT_IS_OK(ret) \
+ EXPECT_PRED_FORMAT1(::android::hardware::audio::common::testing::detail::assertIsOk, ret)
+
+using namespace android;
+
+using aidl::android::hardware::audio::core::ISoundDose;
+using aidl::android::hardware::audio::sounddose::ISoundDoseFactory;
+
+class SoundDoseFactory : public testing::TestWithParam<std::string> {
+ public:
+ void SetUp() override { ASSERT_NO_FATAL_FAILURE(ConnectToService(GetParam())); }
+
+ void TearDown() override {}
+
+ void ConnectToService(const std::string& interfaceName) {
+ ndk::SpAIBinder binder =
+ ndk::SpAIBinder(AServiceManager_waitForService(interfaceName.c_str()));
+ if (binder == nullptr) {
+ LOG(ERROR) << "Failed to get service " << interfaceName;
+ } else {
+ LOG(DEBUG) << "Succeeded to get service " << interfaceName;
+ }
+ soundDoseFactory = ISoundDoseFactory::fromBinder(binder);
+ ASSERT_NE(soundDoseFactory, nullptr);
+ }
+
+ std::shared_ptr<ISoundDoseFactory> soundDoseFactory;
+};
+
+TEST_P(SoundDoseFactory, GetSoundDoseForSameModule) {
+ const std::string module = "primary";
+
+ std::shared_ptr<ISoundDose> soundDose1;
+ EXPECT_IS_OK(soundDoseFactory->getSoundDose(module, &soundDose1));
+
+ if (soundDose1 == nullptr) {
+ LOG(WARNING) << "Primary module does not support sound dose";
+ return;
+ }
+
+ std::shared_ptr<ISoundDose> soundDose2;
+ EXPECT_IS_OK(soundDoseFactory->getSoundDose(module, &soundDose2));
+ EXPECT_NE(nullptr, soundDose2);
+ EXPECT_EQ(soundDose1->asBinder(), soundDose2->asBinder())
+ << "getSoundDose must return the same interface for the same module";
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ SoundDoseFactoryTest, SoundDoseFactory,
+ testing::ValuesIn(android::getAidlHalInstanceNames(ISoundDoseFactory::descriptor)),
+ android::PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SoundDoseFactory);
diff --git a/audio/aidl/vts/Android.bp b/audio/aidl/vts/Android.bp
index 03e9fca..dcdecab 100644
--- a/audio/aidl/vts/Android.bp
+++ b/audio/aidl/vts/Android.bp
@@ -24,6 +24,7 @@
"android.hardware.common-V2-ndk",
"android.hardware.common.fmq-V1-ndk",
"libaudioaidlcommon",
+ "libaidlcommonsupport",
],
header_libs: ["libaudioaidl_headers"],
cflags: [
@@ -49,7 +50,8 @@
],
srcs: [
"ModuleConfig.cpp",
- "VtsHalAudioCoreTargetTest.cpp",
+ "VtsHalAudioCoreConfigTargetTest.cpp",
+ "VtsHalAudioCoreModuleTargetTest.cpp",
],
}
@@ -66,13 +68,37 @@
}
cc_test {
+ name: "VtsHalBassBoostTargetTest",
+ defaults: ["VtsHalAudioTargetTestDefaults"],
+ srcs: ["VtsHalBassBoostTargetTest.cpp"],
+}
+
+cc_test {
+ name: "VtsHalDownmixTargetTest",
+ defaults: ["VtsHalAudioTargetTestDefaults"],
+ srcs: ["VtsHalDownmixTargetTest.cpp"],
+}
+
+cc_test {
name: "VtsHalEqualizerTargetTest",
defaults: ["VtsHalAudioTargetTestDefaults"],
srcs: ["VtsHalEqualizerTargetTest.cpp"],
}
cc_test {
+ name: "VtsHalHapticGeneratorTargetTest",
+ defaults: ["VtsHalAudioTargetTestDefaults"],
+ srcs: ["VtsHalHapticGeneratorTargetTest.cpp"],
+}
+
+cc_test {
name: "VtsHalLoudnessEnhancerTargetTest",
defaults: ["VtsHalAudioTargetTestDefaults"],
srcs: ["VtsHalLoudnessEnhancerTargetTest.cpp"],
}
+
+cc_test {
+ name: "VtsHalVisualizerTargetTest",
+ defaults: ["VtsHalAudioTargetTestDefaults"],
+ srcs: ["VtsHalVisualizerTargetTest.cpp"],
+}
diff --git a/audio/aidl/vts/AudioHalBinderServiceUtil.h b/audio/aidl/vts/AudioHalBinderServiceUtil.h
index c8d81b1..b4b4632 100644
--- a/audio/aidl/vts/AudioHalBinderServiceUtil.h
+++ b/audio/aidl/vts/AudioHalBinderServiceUtil.h
@@ -31,7 +31,7 @@
public:
ndk::SpAIBinder connectToService(const std::string& serviceName) {
mServiceName = serviceName;
- mBinder = ndk::SpAIBinder(AServiceManager_getService(serviceName.c_str()));
+ mBinder = ndk::SpAIBinder(AServiceManager_waitForService(serviceName.c_str()));
if (mBinder == nullptr) {
LOG(ERROR) << "Failed to get service " << serviceName;
} else {
diff --git a/audio/aidl/vts/EffectFactoryHelper.h b/audio/aidl/vts/EffectFactoryHelper.h
index dc766dd..0d5c649 100644
--- a/audio/aidl/vts/EffectFactoryHelper.h
+++ b/audio/aidl/vts/EffectFactoryHelper.h
@@ -49,22 +49,23 @@
std::shared_ptr<IFactory> GetFactory() const { return mEffectFactory; }
- static std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor::Identity>>
- getAllEffectDescriptors(std::string serviceName, std::optional<AudioUuid> type = std::nullopt) {
+ static std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor>> getAllEffectDescriptors(
+ std::string serviceName, std::optional<AudioUuid> type = std::nullopt) {
AudioHalBinderServiceUtil util;
auto names = android::getAidlHalInstanceNames(serviceName);
- std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor::Identity>> result;
+ std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor>> result;
for (const auto& name : names) {
auto factory = IFactory::fromBinder(util.connectToService(name));
if (factory) {
- if (std::vector<Descriptor::Identity> ids;
- factory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids).isOk()) {
- for (const auto& id : ids) {
- if (type.has_value() && id.type != type.value()) {
+ if (std::vector<Descriptor> descs;
+ factory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &descs)
+ .isOk()) {
+ for (const auto& desc : descs) {
+ if (type.has_value() && desc.common.id.type != type.value()) {
continue;
}
- result.emplace_back(factory, id);
+ result.emplace_back(factory, desc);
}
}
}
diff --git a/audio/aidl/vts/EffectHelper.h b/audio/aidl/vts/EffectHelper.h
index 73a1f49..7222d4f 100644
--- a/audio/aidl/vts/EffectHelper.h
+++ b/audio/aidl/vts/EffectHelper.h
@@ -58,26 +58,34 @@
class EffectHelper {
public:
static void create(std::shared_ptr<IFactory> factory, std::shared_ptr<IEffect>& effect,
- Descriptor::Identity id, binder_status_t status = EX_NONE) {
+ Descriptor& desc, binder_status_t status = EX_NONE) {
ASSERT_NE(factory, nullptr);
- EXPECT_STATUS(status, factory->createEffect(id.uuid, &effect));
+ auto& id = desc.common.id;
+ ASSERT_STATUS(status, factory->createEffect(id.uuid, &effect));
if (status == EX_NONE) {
ASSERT_NE(effect, nullptr) << id.uuid.toString();
}
}
+ static void destroyIgnoreRet(std::shared_ptr<IFactory> factory,
+ std::shared_ptr<IEffect> effect) {
+ if (factory && effect) {
+ factory->destroyEffect(effect);
+ }
+ }
+
static void destroy(std::shared_ptr<IFactory> factory, std::shared_ptr<IEffect> effect,
binder_status_t status = EX_NONE) {
ASSERT_NE(factory, nullptr);
ASSERT_NE(effect, nullptr);
- EXPECT_STATUS(status, factory->destroyEffect(effect));
+ ASSERT_STATUS(status, factory->destroyEffect(effect));
}
static void open(std::shared_ptr<IEffect> effect, const Parameter::Common& common,
const std::optional<Parameter::Specific>& specific,
IEffect::OpenEffectReturn* ret, binder_status_t status = EX_NONE) {
ASSERT_NE(effect, nullptr);
- EXPECT_STATUS(status, effect->open(common, specific, ret));
+ ASSERT_STATUS(status, effect->open(common, specific, ret));
}
static void open(std::shared_ptr<IEffect> effect, int session = 0,
@@ -85,30 +93,40 @@
ASSERT_NE(effect, nullptr);
Parameter::Common common = EffectHelper::createParamCommon(session);
IEffect::OpenEffectReturn ret;
- open(effect, common, std::nullopt /* specific */, &ret, status);
+ ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, status));
}
+ static void closeIgnoreRet(std::shared_ptr<IEffect> effect) {
+ if (effect) {
+ effect->close();
+ }
+ }
static void close(std::shared_ptr<IEffect> effect, binder_status_t status = EX_NONE) {
if (effect) {
- EXPECT_STATUS(status, effect->close());
+ ASSERT_STATUS(status, effect->close());
}
}
static void getDescriptor(std::shared_ptr<IEffect> effect, Descriptor& desc,
binder_status_t status = EX_NONE) {
ASSERT_NE(effect, nullptr);
- EXPECT_STATUS(status, effect->getDescriptor(&desc));
+ ASSERT_STATUS(status, effect->getDescriptor(&desc));
}
static void expectState(std::shared_ptr<IEffect> effect, State expectState,
binder_status_t status = EX_NONE) {
ASSERT_NE(effect, nullptr);
State state;
- EXPECT_STATUS(status, effect->getState(&state));
- EXPECT_EQ(expectState, state);
+ ASSERT_STATUS(status, effect->getState(&state));
+ ASSERT_EQ(expectState, state);
+ }
+ static void commandIgnoreRet(std::shared_ptr<IEffect> effect, CommandId command) {
+ if (effect) {
+ effect->command(command);
+ }
}
static void command(std::shared_ptr<IEffect> effect, CommandId command,
binder_status_t status = EX_NONE) {
ASSERT_NE(effect, nullptr);
- EXPECT_STATUS(status, effect->command(command));
+ ASSERT_STATUS(status, effect->command(command));
}
static void allocateInputData(const Parameter::Common common, std::unique_ptr<DataMQ>& mq,
std::vector<float>& buffer) {
@@ -116,29 +134,29 @@
auto frameSize = android::hardware::audio::common::getFrameSizeInBytes(
common.input.base.format, common.input.base.channelMask);
const size_t floatsToWrite = mq->availableToWrite();
- EXPECT_NE(0UL, floatsToWrite);
- EXPECT_EQ(frameSize * common.input.frameCount, floatsToWrite * sizeof(float));
+ ASSERT_NE(0UL, floatsToWrite);
+ ASSERT_EQ(frameSize * common.input.frameCount, floatsToWrite * sizeof(float));
buffer.resize(floatsToWrite);
std::fill(buffer.begin(), buffer.end(), 0x5a);
}
static void writeToFmq(std::unique_ptr<DataMQ>& mq, const std::vector<float>& buffer) {
const size_t available = mq->availableToWrite();
- EXPECT_NE(0Ul, available);
+ ASSERT_NE(0Ul, available);
auto bufferFloats = buffer.size();
auto floatsToWrite = std::min(available, bufferFloats);
- EXPECT_TRUE(mq->write(buffer.data(), floatsToWrite));
+ ASSERT_TRUE(mq->write(buffer.data(), floatsToWrite));
}
static void readFromFmq(std::unique_ptr<StatusMQ>& statusMq, size_t statusNum,
std::unique_ptr<DataMQ>& dataMq, size_t expectFloats,
std::vector<float>& buffer) {
IEffect::Status status{};
- EXPECT_TRUE(statusMq->readBlocking(&status, statusNum));
- EXPECT_EQ(STATUS_OK, status.status);
+ ASSERT_TRUE(statusMq->readBlocking(&status, statusNum));
+ ASSERT_EQ(STATUS_OK, status.status);
if (statusNum != 0) {
- EXPECT_EQ(expectFloats, (unsigned)status.fmqProduced);
- EXPECT_EQ(expectFloats, dataMq->availableToRead());
+ ASSERT_EQ(expectFloats, (unsigned)status.fmqProduced);
+ ASSERT_EQ(expectFloats, dataMq->availableToRead());
if (expectFloats != 0) {
- EXPECT_TRUE(dataMq->read(buffer.data(), expectFloats));
+ ASSERT_TRUE(dataMq->read(buffer.data(), expectFloats));
}
}
}
diff --git a/audio/aidl/vts/ModuleConfig.cpp b/audio/aidl/vts/ModuleConfig.cpp
index 33c5b72..7e4b148 100644
--- a/audio/aidl/vts/ModuleConfig.cpp
+++ b/audio/aidl/vts/ModuleConfig.cpp
@@ -28,6 +28,7 @@
using aidl::android::hardware::audio::core::IModule;
using aidl::android::media::audio::common::AudioChannelLayout;
+using aidl::android::media::audio::common::AudioDeviceType;
using aidl::android::media::audio::common::AudioEncapsulationMode;
using aidl::android::media::audio::common::AudioFormatDescription;
using aidl::android::media::audio::common::AudioFormatType;
@@ -62,6 +63,18 @@
return {};
}
+// static
+std::vector<aidl::android::media::audio::common::AudioPort> ModuleConfig::getBuiltInMicPorts(
+ const std::vector<aidl::android::media::audio::common::AudioPort>& ports) {
+ std::vector<AudioPort> result;
+ std::copy_if(ports.begin(), ports.end(), std::back_inserter(result), [](const auto& port) {
+ const auto type = port.ext.template get<AudioPortExt::Tag::device>().device.type;
+ return type.connection.empty() && (type.type == AudioDeviceType::IN_MICROPHONE ||
+ type.type == AudioDeviceType::IN_MICROPHONE_BACK);
+ });
+ return result;
+}
+
template <typename T>
auto findById(const std::vector<T>& v, int32_t id) {
return std::find_if(v.begin(), v.end(), [&](const auto& p) { return p.id == id; });
@@ -107,39 +120,46 @@
return result;
}
-std::vector<AudioPort> ModuleConfig::getInputMixPorts() const {
+std::vector<AudioPort> ModuleConfig::getInputMixPorts(bool attachedOnly) const {
std::vector<AudioPort> result;
- std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result), [](const auto& port) {
+ std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result), [&](const auto& port) {
return port.ext.getTag() == AudioPortExt::Tag::mix &&
- port.flags.getTag() == AudioIoFlags::Tag::input;
+ port.flags.getTag() == AudioIoFlags::Tag::input &&
+ (!attachedOnly || !getAttachedSourceDevicesPortsForMixPort(port).empty());
});
return result;
}
-std::vector<AudioPort> ModuleConfig::getOutputMixPorts() const {
+std::vector<AudioPort> ModuleConfig::getOutputMixPorts(bool attachedOnly) const {
std::vector<AudioPort> result;
- std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result), [](const auto& port) {
+ std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result), [&](const auto& port) {
return port.ext.getTag() == AudioPortExt::Tag::mix &&
- port.flags.getTag() == AudioIoFlags::Tag::output;
+ port.flags.getTag() == AudioIoFlags::Tag::output &&
+ (!attachedOnly || !getAttachedSinkDevicesPortsForMixPort(port).empty());
});
return result;
}
+std::vector<AudioPort> ModuleConfig::getNonBlockingMixPorts(bool attachedOnly,
+ bool singlePort) const {
+ return findMixPorts(false /*isInput*/, attachedOnly, singlePort, [&](const AudioPort& port) {
+ return isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::output>(),
+ AudioOutputFlags::NON_BLOCKING);
+ });
+}
+
std::vector<AudioPort> ModuleConfig::getOffloadMixPorts(bool attachedOnly, bool singlePort) const {
- std::vector<AudioPort> result;
- const auto mixPorts = getMixPorts(false /*isInput*/);
- auto offloadPortIt = mixPorts.begin();
- while (offloadPortIt != mixPorts.end()) {
- offloadPortIt = std::find_if(offloadPortIt, mixPorts.end(), [&](const AudioPort& port) {
- return isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::output>(),
- AudioOutputFlags::COMPRESS_OFFLOAD) &&
- (!attachedOnly || !getAttachedSinkDevicesPortsForMixPort(port).empty());
- });
- if (offloadPortIt == mixPorts.end()) break;
- result.push_back(*offloadPortIt++);
- if (singlePort) break;
- }
- return result;
+ return findMixPorts(false /*isInput*/, attachedOnly, singlePort, [&](const AudioPort& port) {
+ return isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::output>(),
+ AudioOutputFlags::COMPRESS_OFFLOAD);
+ });
+}
+
+std::vector<AudioPort> ModuleConfig::getPrimaryMixPorts(bool attachedOnly, bool singlePort) const {
+ return findMixPorts(false /*isInput*/, attachedOnly, singlePort, [&](const AudioPort& port) {
+ return isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::output>(),
+ AudioOutputFlags::PRIMARY);
+ });
}
std::vector<AudioPort> ModuleConfig::getAttachedDevicesPortsForMixPort(
@@ -193,7 +213,7 @@
std::optional<ModuleConfig::SrcSinkPair> ModuleConfig::getNonRoutableSrcSinkPair(
bool isInput) const {
- const auto mixPorts = getMixPorts(isInput);
+ const auto mixPorts = getMixPorts(isInput, false /*attachedOnly*/);
std::set<std::pair<int32_t, int32_t>> allowedRoutes;
for (const auto& route : mRoutes) {
for (const auto srcPortId : route.sourcePortIds) {
@@ -343,6 +363,20 @@
profile.sampleRates.empty() || profile.channelMasks.empty();
}
+std::vector<AudioPort> ModuleConfig::findMixPorts(
+ bool isInput, bool attachedOnly, bool singlePort,
+ const std::function<bool(const AudioPort&)>& pred) const {
+ std::vector<AudioPort> result;
+ const auto mixPorts = getMixPorts(isInput, attachedOnly);
+ for (auto mixPortIt = mixPorts.begin(); mixPortIt != mixPorts.end();) {
+ mixPortIt = std::find_if(mixPortIt, mixPorts.end(), pred);
+ if (mixPortIt == mixPorts.end()) break;
+ result.push_back(*mixPortIt++);
+ if (singlePort) break;
+ }
+ return result;
+}
+
std::vector<AudioPortConfig> ModuleConfig::generateAudioMixPortConfigs(
const std::vector<AudioPort>& ports, bool isInput, bool singleProfile) const {
std::vector<AudioPortConfig> result;
diff --git a/audio/aidl/vts/ModuleConfig.h b/audio/aidl/vts/ModuleConfig.h
index dc109a7..7247f3b 100644
--- a/audio/aidl/vts/ModuleConfig.h
+++ b/audio/aidl/vts/ModuleConfig.h
@@ -16,6 +16,7 @@
#pragma once
+#include <functional>
#include <optional>
#include <set>
#include <utility>
@@ -36,20 +37,32 @@
static std::optional<aidl::android::media::audio::common::AudioOffloadInfo>
generateOffloadInfoIfNeeded(
const aidl::android::media::audio::common::AudioPortConfig& portConfig);
+ static std::vector<aidl::android::media::audio::common::AudioPort> getBuiltInMicPorts(
+ const std::vector<aidl::android::media::audio::common::AudioPort>& ports);
explicit ModuleConfig(aidl::android::hardware::audio::core::IModule* module);
const ndk::ScopedAStatus& getStatus() const { return mStatus; }
std::string getError() const { return mStatus.getMessage(); }
std::vector<aidl::android::media::audio::common::AudioPort> getAttachedDevicePorts() const;
- std::vector<aidl::android::media::audio::common::AudioPort> getExternalDevicePorts() const;
- std::vector<aidl::android::media::audio::common::AudioPort> getInputMixPorts() const;
- std::vector<aidl::android::media::audio::common::AudioPort> getOutputMixPorts() const;
- std::vector<aidl::android::media::audio::common::AudioPort> getMixPorts(bool isInput) const {
- return isInput ? getInputMixPorts() : getOutputMixPorts();
+ std::vector<aidl::android::media::audio::common::AudioPort> getAttachedMicrophonePorts() const {
+ return getBuiltInMicPorts(getAttachedDevicePorts());
}
+ std::vector<aidl::android::media::audio::common::AudioPort> getExternalDevicePorts() const;
+ std::vector<aidl::android::media::audio::common::AudioPort> getInputMixPorts(
+ bool attachedOnly) const;
+ std::vector<aidl::android::media::audio::common::AudioPort> getOutputMixPorts(
+ bool attachedOnly) const;
+ std::vector<aidl::android::media::audio::common::AudioPort> getMixPorts(
+ bool isInput, bool attachedOnly) const {
+ return isInput ? getInputMixPorts(attachedOnly) : getOutputMixPorts(attachedOnly);
+ }
+ std::vector<aidl::android::media::audio::common::AudioPort> getNonBlockingMixPorts(
+ bool attachedOnly, bool singlePort) const;
std::vector<aidl::android::media::audio::common::AudioPort> getOffloadMixPorts(
bool attachedOnly, bool singlePort) const;
+ std::vector<aidl::android::media::audio::common::AudioPort> getPrimaryMixPorts(
+ bool attachedOnly, bool singlePort) const;
std::vector<aidl::android::media::audio::common::AudioPort> getAttachedDevicesPortsForMixPort(
bool isInput, const aidl::android::media::audio::common::AudioPort& mixPort) const {
@@ -78,14 +91,17 @@
}
std::vector<aidl::android::media::audio::common::AudioPortConfig> getPortConfigsForMixPorts()
const {
- auto inputs = generateAudioMixPortConfigs(getInputMixPorts(), true, false);
- auto outputs = generateAudioMixPortConfigs(getOutputMixPorts(), false, false);
+ auto inputs =
+ generateAudioMixPortConfigs(getInputMixPorts(false /*attachedOnly*/), true, false);
+ auto outputs = generateAudioMixPortConfigs(getOutputMixPorts(false /*attachedOnly*/), false,
+ false);
inputs.insert(inputs.end(), outputs.begin(), outputs.end());
return inputs;
}
std::vector<aidl::android::media::audio::common::AudioPortConfig> getPortConfigsForMixPorts(
bool isInput) const {
- return generateAudioMixPortConfigs(getMixPorts(isInput), isInput, false);
+ return generateAudioMixPortConfigs(getMixPorts(isInput, false /*attachedOnly*/), isInput,
+ false);
}
std::vector<aidl::android::media::audio::common::AudioPortConfig> getPortConfigsForMixPorts(
bool isInput, const aidl::android::media::audio::common::AudioPort& port) const {
@@ -93,7 +109,8 @@
}
std::optional<aidl::android::media::audio::common::AudioPortConfig> getSingleConfigForMixPort(
bool isInput) const {
- const auto config = generateAudioMixPortConfigs(getMixPorts(isInput), isInput, true);
+ const auto config = generateAudioMixPortConfigs(
+ getMixPorts(isInput, false /*attachedOnly*/), isInput, true);
if (!config.empty()) {
return *config.begin();
}
@@ -121,6 +138,10 @@
std::string toString() const;
private:
+ std::vector<aidl::android::media::audio::common::AudioPort> findMixPorts(
+ bool isInput, bool attachedOnly, bool singlePort,
+ const std::function<bool(const aidl::android::media::audio::common::AudioPort&)>& pred)
+ const;
std::vector<aidl::android::media::audio::common::AudioPortConfig> generateAudioMixPortConfigs(
const std::vector<aidl::android::media::audio::common::AudioPort>& ports, bool isInput,
bool singleProfile) const;
diff --git a/audio/aidl/vts/TestUtils.h b/audio/aidl/vts/TestUtils.h
index 5e4d56a..4c1d42c 100644
--- a/audio/aidl/vts/TestUtils.h
+++ b/audio/aidl/vts/TestUtils.h
@@ -16,6 +16,8 @@
#pragma once
+#include <algorithm>
+#include <initializer_list>
#include <iostream>
#include <android/binder_auto_utils.h>
@@ -45,6 +47,19 @@
<< "\n but is has completed with: " << status;
}
+template <typename T>
+inline ::testing::AssertionResult assertResult(const char* exp_expr, const char* act_expr,
+ const std::initializer_list<T>& expected,
+ const ::ndk::ScopedAStatus& status) {
+ if (std::find(expected.begin(), expected.end(), status.getExceptionCode()) != expected.end()) {
+ return ::testing::AssertionSuccess();
+ }
+ return ::testing::AssertionFailure() << "Expected the transaction \'" << act_expr
+ << "\' to complete with one of: " << exp_expr
+ << "\n which is: " << ::testing::PrintToString(expected)
+ << "\n but is has completed with: " << status;
+}
+
} // namespace detail
} // namespace android::hardware::audio::common::testing
diff --git a/audio/aidl/vts/VtsHalAudioCoreConfigTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreConfigTargetTest.cpp
new file mode 100644
index 0000000..e7f5817
--- /dev/null
+++ b/audio/aidl/vts/VtsHalAudioCoreConfigTargetTest.cpp
@@ -0,0 +1,335 @@
+#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 <aidl/android/media/audio/common/AudioFlag.h>
+#include <aidl/android/media/audio/common/AudioProductStrategyType.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/VtsHalAudioCoreModuleTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
new file mode 100644
index 0000000..2508afd
--- /dev/null
+++ b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
@@ -0,0 +1,3128 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <algorithm>
+#include <chrono>
+#include <cmath>
+#include <condition_variable>
+#include <limits>
+#include <memory>
+#include <mutex>
+#include <optional>
+#include <set>
+#include <string>
+#include <variant>
+#include <vector>
+
+#define LOG_TAG "VtsHalAudioCore.Module"
+#include <android-base/logging.h>
+
+#include <StreamWorker.h>
+#include <Utils.h>
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/audio/core/BnStreamCallback.h>
+#include <aidl/android/hardware/audio/core/IModule.h>
+#include <aidl/android/hardware/audio/core/ISoundDose.h>
+#include <aidl/android/hardware/audio/core/ITelephony.h>
+#include <aidl/android/media/audio/common/AudioIoFlags.h>
+#include <aidl/android/media/audio/common/AudioOutputFlags.h>
+#include <android-base/chrono_utils.h>
+#include <android/binder_enums.h>
+#include <fmq/AidlMessageQueue.h>
+
+#include "AudioHalBinderServiceUtil.h"
+#include "ModuleConfig.h"
+#include "TestUtils.h"
+
+using namespace android;
+using aidl::android::hardware::audio::common::PlaybackTrackMetadata;
+using aidl::android::hardware::audio::common::RecordTrackMetadata;
+using aidl::android::hardware::audio::common::SinkMetadata;
+using aidl::android::hardware::audio::common::SourceMetadata;
+using aidl::android::hardware::audio::core::AudioMode;
+using aidl::android::hardware::audio::core::AudioPatch;
+using aidl::android::hardware::audio::core::AudioRoute;
+using aidl::android::hardware::audio::core::IModule;
+using aidl::android::hardware::audio::core::ISoundDose;
+using aidl::android::hardware::audio::core::IStreamCommon;
+using aidl::android::hardware::audio::core::IStreamIn;
+using aidl::android::hardware::audio::core::IStreamOut;
+using aidl::android::hardware::audio::core::ITelephony;
+using aidl::android::hardware::audio::core::MicrophoneDynamicInfo;
+using aidl::android::hardware::audio::core::MicrophoneInfo;
+using aidl::android::hardware::audio::core::ModuleDebug;
+using aidl::android::hardware::audio::core::StreamDescriptor;
+using aidl::android::hardware::audio::core::VendorParameter;
+using aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using aidl::android::media::audio::common::AudioContentType;
+using aidl::android::media::audio::common::AudioDevice;
+using aidl::android::media::audio::common::AudioDeviceAddress;
+using aidl::android::media::audio::common::AudioDeviceType;
+using aidl::android::media::audio::common::AudioFormatType;
+using aidl::android::media::audio::common::AudioIoFlags;
+using aidl::android::media::audio::common::AudioOutputFlags;
+using aidl::android::media::audio::common::AudioPort;
+using aidl::android::media::audio::common::AudioPortConfig;
+using aidl::android::media::audio::common::AudioPortDeviceExt;
+using aidl::android::media::audio::common::AudioPortExt;
+using aidl::android::media::audio::common::AudioSource;
+using aidl::android::media::audio::common::AudioUsage;
+using aidl::android::media::audio::common::Void;
+using android::hardware::audio::common::getChannelCount;
+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;
+using ndk::ScopedAStatus;
+
+template <typename T>
+auto findById(std::vector<T>& v, int32_t id) {
+ return std::find_if(v.begin(), v.end(), [&](const auto& e) { return e.id == id; });
+}
+
+template <typename C>
+std::vector<int32_t> GetNonExistentIds(const C& allIds) {
+ if (allIds.empty()) {
+ return std::vector<int32_t>{-1, 0, 1};
+ }
+ std::vector<int32_t> nonExistentIds;
+ nonExistentIds.push_back(*std::min_element(allIds.begin(), allIds.end()) - 1);
+ nonExistentIds.push_back(*std::max_element(allIds.begin(), allIds.end()) + 1);
+ return nonExistentIds;
+}
+
+AudioDeviceAddress GenerateUniqueDeviceAddress() {
+ static int nextId = 1;
+ // TODO: Use connection-specific ID.
+ return AudioDeviceAddress::make<AudioDeviceAddress::Tag::id>(std::to_string(++nextId));
+}
+
+// All 'With*' classes are move-only because they are associated with some
+// resource or state of a HAL module.
+class WithDebugFlags {
+ public:
+ static WithDebugFlags createNested(const WithDebugFlags& parent) {
+ return WithDebugFlags(parent.mFlags);
+ }
+
+ WithDebugFlags() {}
+ explicit WithDebugFlags(const ModuleDebug& initial) : mInitial(initial), mFlags(initial) {}
+ WithDebugFlags(const WithDebugFlags&) = delete;
+ WithDebugFlags& operator=(const WithDebugFlags&) = delete;
+ ~WithDebugFlags() {
+ if (mModule != nullptr) {
+ EXPECT_IS_OK(mModule->setModuleDebug(mInitial));
+ }
+ }
+ void SetUp(IModule* module) { ASSERT_IS_OK(module->setModuleDebug(mFlags)); }
+ ModuleDebug& flags() { return mFlags; }
+
+ private:
+ ModuleDebug mInitial;
+ ModuleDebug mFlags;
+ IModule* mModule = nullptr;
+};
+
+// For consistency, WithAudioPortConfig can start both with a non-existent
+// port config, and with an existing one. Existence is determined by the
+// id of the provided config. If it's not 0, then WithAudioPortConfig is
+// essentially a no-op wrapper.
+class WithAudioPortConfig {
+ public:
+ WithAudioPortConfig() {}
+ explicit WithAudioPortConfig(const AudioPortConfig& config) : mInitialConfig(config) {}
+ WithAudioPortConfig(const WithAudioPortConfig&) = delete;
+ WithAudioPortConfig& operator=(const WithAudioPortConfig&) = delete;
+ ~WithAudioPortConfig() {
+ if (mModule != nullptr) {
+ EXPECT_IS_OK(mModule->resetAudioPortConfig(getId())) << "port config id " << getId();
+ }
+ }
+ void SetUp(IModule* module) {
+ ASSERT_NE(AudioPortExt::Tag::unspecified, mInitialConfig.ext.getTag())
+ << "config: " << mInitialConfig.toString();
+ // Negotiation is allowed for device ports because the HAL module is
+ // allowed to provide an empty profiles list for attached devices.
+ ASSERT_NO_FATAL_FAILURE(
+ SetUpImpl(module, mInitialConfig.ext.getTag() == AudioPortExt::Tag::device));
+ }
+ int32_t getId() const { return mConfig.id; }
+ const AudioPortConfig& get() const { return mConfig; }
+
+ private:
+ void SetUpImpl(IModule* module, bool negotiate) {
+ if (mInitialConfig.id == 0) {
+ AudioPortConfig suggested;
+ bool applied = false;
+ ASSERT_IS_OK(module->setAudioPortConfig(mInitialConfig, &suggested, &applied))
+ << "Config: " << mInitialConfig.toString();
+ if (!applied && negotiate) {
+ mInitialConfig = suggested;
+ ASSERT_NO_FATAL_FAILURE(SetUpImpl(module, false))
+ << " while applying suggested config: " << suggested.toString();
+ } else {
+ ASSERT_TRUE(applied) << "Suggested: " << suggested.toString();
+ mConfig = suggested;
+ mModule = module;
+ }
+ } else {
+ mConfig = mInitialConfig;
+ }
+ }
+
+ AudioPortConfig mInitialConfig;
+ IModule* mModule = nullptr;
+ AudioPortConfig mConfig;
+};
+
+template <typename T>
+void GenerateTestArrays(size_t validElementCount, T validMin, T validMax,
+ std::vector<std::vector<T>>* validValues,
+ std::vector<std::vector<T>>* invalidValues) {
+ validValues->emplace_back(validElementCount, validMin);
+ validValues->emplace_back(validElementCount, validMax);
+ validValues->emplace_back(validElementCount, (validMin + validMax) / 2.f);
+ if (validElementCount > 0) {
+ invalidValues->emplace_back(validElementCount - 1, validMin);
+ }
+ invalidValues->emplace_back(validElementCount + 1, validMin);
+ for (auto m : {-2, -1, 2}) {
+ const auto invalidMin = m * validMin;
+ if (invalidMin < validMin || invalidMin > validMax) {
+ invalidValues->emplace_back(validElementCount, invalidMin);
+ }
+ const auto invalidMax = m * validMax;
+ if (invalidMax < validMin || invalidMax > validMax) {
+ invalidValues->emplace_back(validElementCount, invalidMax);
+ }
+ }
+}
+
+template <typename PropType, class Instance, typename Getter, typename Setter>
+void TestAccessors(Instance* inst, Getter getter, Setter setter,
+ const std::vector<PropType>& validValues,
+ const std::vector<PropType>& invalidValues, bool* isSupported) {
+ PropType initialValue{};
+ ScopedAStatus status = (inst->*getter)(&initialValue);
+ if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+ *isSupported = false;
+ return;
+ }
+ ASSERT_TRUE(status.isOk()) << "Unexpected status from a getter: " << status;
+ *isSupported = true;
+ for (const auto v : validValues) {
+ EXPECT_IS_OK((inst->*setter)(v)) << "for a valid value: " << ::testing::PrintToString(v);
+ PropType currentValue{};
+ EXPECT_IS_OK((inst->*getter)(¤tValue));
+ EXPECT_EQ(v, currentValue);
+ }
+ for (const auto v : invalidValues) {
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, (inst->*setter)(v))
+ << "for an invalid value: " << ::testing::PrintToString(v);
+ }
+ EXPECT_IS_OK((inst->*setter)(initialValue)) << "Failed to restore the initial value";
+}
+
+template <class Instance>
+void TestGetVendorParameters(Instance* inst, bool* isSupported) {
+ static const std::vector<std::vector<std::string>> kIdsLists = {{}, {"zero"}, {"one", "two"}};
+ static const auto kStatuses = {EX_ILLEGAL_ARGUMENT, EX_ILLEGAL_STATE, EX_UNSUPPORTED_OPERATION};
+ for (const auto& ids : kIdsLists) {
+ std::vector<VendorParameter> params;
+ if (ndk::ScopedAStatus status = inst->getVendorParameters(ids, ¶ms); status.isOk()) {
+ EXPECT_EQ(ids.size(), params.size()) << "Size of the returned parameters list must "
+ << "match the size of the provided ids list";
+ for (const auto& param : params) {
+ EXPECT_NE(ids.end(), std::find(ids.begin(), ids.end(), param.id))
+ << "Returned parameter id \"" << param.id << "\" is unexpected";
+ }
+ for (const auto& id : ids) {
+ EXPECT_NE(params.end(),
+ std::find_if(params.begin(), params.end(),
+ [&](const auto& param) { return param.id == id; }))
+ << "Requested parameter with id \"" << id << "\" was not returned";
+ }
+ } else {
+ EXPECT_STATUS(kStatuses, status);
+ if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+ *isSupported = false;
+ return;
+ }
+ }
+ }
+ *isSupported = true;
+}
+
+template <class Instance>
+void TestSetVendorParameters(Instance* inst, bool* isSupported) {
+ static const auto kStatuses = {EX_NONE, EX_ILLEGAL_ARGUMENT, EX_ILLEGAL_STATE,
+ EX_UNSUPPORTED_OPERATION};
+ static const std::vector<std::vector<VendorParameter>> kParamsLists = {
+ {}, {VendorParameter{"zero"}}, {VendorParameter{"one"}, VendorParameter{"two"}}};
+ for (const auto& params : kParamsLists) {
+ ndk::ScopedAStatus status = inst->setVendorParameters(params, false);
+ if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+ *isSupported = false;
+ return;
+ }
+ EXPECT_STATUS(kStatuses, status)
+ << ::android::internal::ToString(params) << ", async: false";
+ EXPECT_STATUS(kStatuses, inst->setVendorParameters(params, true))
+ << ::android::internal::ToString(params) << ", async: true";
+ }
+ *isSupported = true;
+}
+
+// Can be used as a base for any test here, does not depend on the fixture GTest parameters.
+class AudioCoreModuleBase {
+ public:
+ // The default buffer size is used mostly for negative tests.
+ static constexpr int kDefaultBufferSizeFrames = 256;
+
+ void SetUpImpl(const std::string& moduleName) {
+ ASSERT_NO_FATAL_FAILURE(ConnectToService(moduleName));
+ debug.flags().simulateDeviceConnections = true;
+ ASSERT_NO_FATAL_FAILURE(debug.SetUp(module.get()));
+ }
+
+ void TearDownImpl() {
+ if (module != nullptr) {
+ EXPECT_IS_OK(module->setModuleDebug(ModuleDebug{}));
+ }
+ }
+
+ void ConnectToService(const std::string& moduleName) {
+ module = IModule::fromBinder(binderUtil.connectToService(moduleName));
+ ASSERT_NE(module, nullptr);
+ }
+
+ void RestartService() {
+ ASSERT_NE(module, nullptr);
+ moduleConfig.reset();
+ module = IModule::fromBinder(binderUtil.restartService());
+ ASSERT_NE(module, nullptr);
+ }
+
+ void ApplyEveryConfig(const std::vector<AudioPortConfig>& configs) {
+ for (const auto& config : configs) {
+ ASSERT_NE(0, config.portId);
+ WithAudioPortConfig portConfig(config);
+ ASSERT_NO_FATAL_FAILURE(portConfig.SetUp(module.get())); // calls setAudioPortConfig
+ EXPECT_EQ(config.portId, portConfig.get().portId);
+ std::vector<AudioPortConfig> retrievedPortConfigs;
+ ASSERT_IS_OK(module->getAudioPortConfigs(&retrievedPortConfigs));
+ const int32_t portConfigId = portConfig.getId();
+ auto configIt = std::find_if(
+ retrievedPortConfigs.begin(), retrievedPortConfigs.end(),
+ [&portConfigId](const auto& retrConf) { return retrConf.id == portConfigId; });
+ EXPECT_NE(configIt, retrievedPortConfigs.end())
+ << "Port config id returned by setAudioPortConfig: " << portConfigId
+ << " is not found in the list returned by getAudioPortConfigs";
+ if (configIt != retrievedPortConfigs.end()) {
+ EXPECT_EQ(portConfig.get(), *configIt)
+ << "Applied port config returned by setAudioPortConfig: "
+ << portConfig.get().toString()
+ << " is not the same as retrieved via getAudioPortConfigs: "
+ << configIt->toString();
+ }
+ }
+ }
+
+ template <typename Entity>
+ void GetAllEntityIds(std::set<int32_t>* entityIds,
+ ScopedAStatus (IModule::*getter)(std::vector<Entity>*),
+ const std::string& errorMessage) {
+ std::vector<Entity> entities;
+ { ASSERT_IS_OK((module.get()->*getter)(&entities)); }
+ std::transform(entities.begin(), entities.end(),
+ std::inserter(*entityIds, entityIds->begin()),
+ [](const auto& entity) { return entity.id; });
+ EXPECT_EQ(entities.size(), entityIds->size()) << errorMessage;
+ }
+
+ void GetAllPatchIds(std::set<int32_t>* patchIds) {
+ return GetAllEntityIds<AudioPatch>(
+ patchIds, &IModule::getAudioPatches,
+ "IDs of audio patches returned by IModule.getAudioPatches are not unique");
+ }
+
+ void GetAllPortIds(std::set<int32_t>* portIds) {
+ return GetAllEntityIds<AudioPort>(
+ portIds, &IModule::getAudioPorts,
+ "IDs of audio ports returned by IModule.getAudioPorts are not unique");
+ }
+
+ void GetAllPortConfigIds(std::set<int32_t>* portConfigIds) {
+ return GetAllEntityIds<AudioPortConfig>(
+ portConfigIds, &IModule::getAudioPortConfigs,
+ "IDs of audio port configs returned by IModule.getAudioPortConfigs are not unique");
+ }
+
+ void SetUpModuleConfig() {
+ if (moduleConfig == nullptr) {
+ moduleConfig = std::make_unique<ModuleConfig>(module.get());
+ ASSERT_EQ(EX_NONE, moduleConfig->getStatus().getExceptionCode())
+ << "ModuleConfig init error: " << moduleConfig->getError();
+ }
+ }
+
+ std::shared_ptr<IModule> module;
+ std::unique_ptr<ModuleConfig> moduleConfig;
+ AudioHalBinderServiceUtil binderUtil;
+ WithDebugFlags debug;
+};
+
+class AudioCoreModule : public AudioCoreModuleBase, public testing::TestWithParam<std::string> {
+ public:
+ void SetUp() override { ASSERT_NO_FATAL_FAILURE(SetUpImpl(GetParam())); }
+
+ void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownImpl()); }
+};
+
+class WithDevicePortConnectedState {
+ public:
+ explicit WithDevicePortConnectedState(const AudioPort& idAndData) : mIdAndData(idAndData) {}
+ WithDevicePortConnectedState(const AudioPort& id, const AudioDeviceAddress& address)
+ : mIdAndData(setAudioPortAddress(id, address)) {}
+ WithDevicePortConnectedState(const WithDevicePortConnectedState&) = delete;
+ WithDevicePortConnectedState& operator=(const WithDevicePortConnectedState&) = delete;
+ ~WithDevicePortConnectedState() {
+ if (mModule != nullptr) {
+ EXPECT_IS_OK(mModule->disconnectExternalDevice(getId()))
+ << "when disconnecting device port ID " << getId();
+ }
+ }
+ void SetUp(IModule* module) {
+ ASSERT_IS_OK(module->connectExternalDevice(mIdAndData, &mConnectedPort))
+ << "when connecting device port ID & data " << mIdAndData.toString();
+ ASSERT_NE(mIdAndData.id, getId())
+ << "ID of the connected port must not be the same as the ID of the template port";
+ mModule = module;
+ }
+ int32_t getId() const { return mConnectedPort.id; }
+ const AudioPort& get() { return mConnectedPort; }
+
+ private:
+ static AudioPort setAudioPortAddress(const AudioPort& id, const AudioDeviceAddress& address) {
+ AudioPort result = id;
+ result.ext.get<AudioPortExt::Tag::device>().device.address = address;
+ return result;
+ }
+
+ const AudioPort mIdAndData;
+ IModule* mModule = nullptr;
+ AudioPort mConnectedPort;
+};
+
+class StreamContext {
+ public:
+ typedef AidlMessageQueue<StreamDescriptor::Command, SynchronizedReadWrite> CommandMQ;
+ typedef AidlMessageQueue<StreamDescriptor::Reply, SynchronizedReadWrite> ReplyMQ;
+ typedef AidlMessageQueue<int8_t, SynchronizedReadWrite> DataMQ;
+
+ explicit StreamContext(const StreamDescriptor& descriptor)
+ : mFrameSizeBytes(descriptor.frameSizeBytes),
+ mCommandMQ(new CommandMQ(descriptor.command)),
+ mReplyMQ(new ReplyMQ(descriptor.reply)),
+ mBufferSizeFrames(descriptor.bufferSizeFrames),
+ mDataMQ(maybeCreateDataMQ(descriptor)) {}
+ void checkIsValid() const {
+ EXPECT_NE(0UL, mFrameSizeBytes);
+ ASSERT_NE(nullptr, mCommandMQ);
+ EXPECT_TRUE(mCommandMQ->isValid());
+ ASSERT_NE(nullptr, mReplyMQ);
+ EXPECT_TRUE(mReplyMQ->isValid());
+ if (mDataMQ != nullptr) {
+ EXPECT_TRUE(mDataMQ->isValid());
+ EXPECT_GE(mDataMQ->getQuantumCount() * mDataMQ->getQuantumSize(),
+ mFrameSizeBytes * mBufferSizeFrames)
+ << "Data MQ actual buffer size is "
+ "less than the buffer size as specified by the descriptor";
+ }
+ }
+ size_t getBufferSizeBytes() const { return mFrameSizeBytes * mBufferSizeFrames; }
+ size_t getBufferSizeFrames() const { return mBufferSizeFrames; }
+ CommandMQ* getCommandMQ() const { return mCommandMQ.get(); }
+ DataMQ* getDataMQ() const { return mDataMQ.get(); }
+ ReplyMQ* getReplyMQ() const { return mReplyMQ.get(); }
+
+ private:
+ static std::unique_ptr<DataMQ> maybeCreateDataMQ(const StreamDescriptor& descriptor) {
+ using Tag = StreamDescriptor::AudioBuffer::Tag;
+ if (descriptor.audio.getTag() == Tag::fmq) {
+ return std::make_unique<DataMQ>(descriptor.audio.get<Tag::fmq>());
+ }
+ return nullptr;
+ }
+
+ const size_t mFrameSizeBytes;
+ std::unique_ptr<CommandMQ> mCommandMQ;
+ std::unique_ptr<ReplyMQ> mReplyMQ;
+ const size_t mBufferSizeFrames;
+ std::unique_ptr<DataMQ> mDataMQ;
+};
+
+struct StreamEventReceiver {
+ virtual ~StreamEventReceiver() = default;
+ enum class Event { None, DrainReady, Error, TransferReady };
+ virtual std::tuple<int, Event> getLastEvent() const = 0;
+ virtual std::tuple<int, Event> waitForEvent(int clientEventSeq) = 0;
+ static constexpr int kEventSeqInit = -1;
+};
+std::string toString(StreamEventReceiver::Event event) {
+ switch (event) {
+ case StreamEventReceiver::Event::None:
+ return "None";
+ case StreamEventReceiver::Event::DrainReady:
+ return "DrainReady";
+ case StreamEventReceiver::Event::Error:
+ return "Error";
+ case StreamEventReceiver::Event::TransferReady:
+ return "TransferReady";
+ }
+ return std::to_string(static_cast<int32_t>(event));
+}
+
+// Transition to the next state happens either due to a command from the client,
+// or after an event received from the server.
+using TransitionTrigger = std::variant<StreamDescriptor::Command, StreamEventReceiver::Event>;
+using StateTransition = std::pair<TransitionTrigger, StreamDescriptor::State>;
+struct StateSequence {
+ virtual ~StateSequence() = default;
+ virtual void rewind() = 0;
+ virtual bool done() const = 0;
+ virtual TransitionTrigger getTrigger() = 0;
+ virtual std::set<StreamDescriptor::State> getExpectedStates() = 0;
+ virtual void advance(StreamDescriptor::State state) = 0;
+};
+
+static const StreamDescriptor::Command kGetStatusCommand =
+ StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::getStatus>(Void{});
+static const StreamDescriptor::Command kStartCommand =
+ StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::start>(Void{});
+static const StreamDescriptor::Command kBurstCommand =
+ StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::burst>(0);
+static const StreamDescriptor::Command kDrainInCommand =
+ StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::drain>(
+ StreamDescriptor::DrainMode::DRAIN_UNSPECIFIED);
+static const StreamDescriptor::Command kDrainOutAllCommand =
+ StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::drain>(
+ StreamDescriptor::DrainMode::DRAIN_ALL);
+static const StreamDescriptor::Command kDrainOutEarlyCommand =
+ StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::drain>(
+ StreamDescriptor::DrainMode::DRAIN_EARLY_NOTIFY);
+static const StreamDescriptor::Command kStandbyCommand =
+ StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::standby>(Void{});
+static const StreamDescriptor::Command kPauseCommand =
+ StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::pause>(Void{});
+static const StreamDescriptor::Command kFlushCommand =
+ StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::flush>(Void{});
+static const StreamEventReceiver::Event kTransferReadyEvent =
+ StreamEventReceiver::Event::TransferReady;
+static const StreamEventReceiver::Event kDrainReadyEvent = StreamEventReceiver::Event::DrainReady;
+
+// Handle possible bifurcations:
+// - on burst and on start: 'TRANSFERRING' -> {'ACTIVE', 'TRANSFERRING'}
+// - on pause: 'TRANSFER_PAUSED' -> {'PAUSED', 'TRANSFER_PAUSED'}
+// It is assumed that the 'steps' provided on the construction contain the sequence
+// for the async case, which gets corrected in the case when the HAL decided to do
+// a synchronous transfer.
+class SmartStateSequence : public StateSequence {
+ public:
+ explicit SmartStateSequence(const std::vector<StateTransition>& steps) : mSteps(steps) {}
+ explicit SmartStateSequence(std::vector<StateTransition>&& steps) : mSteps(std::move(steps)) {}
+ void rewind() override { mCurrentStep = 0; }
+ bool done() const override { return mCurrentStep >= mSteps.size(); }
+ TransitionTrigger getTrigger() override { return mSteps[mCurrentStep].first; }
+ std::set<StreamDescriptor::State> getExpectedStates() override {
+ std::set<StreamDescriptor::State> result = {getState()};
+ if (isBurstBifurcation() || isStartBifurcation()) {
+ result.insert(StreamDescriptor::State::ACTIVE);
+ } else if (isPauseBifurcation()) {
+ result.insert(StreamDescriptor::State::PAUSED);
+ }
+ return result;
+ }
+ void advance(StreamDescriptor::State state) override {
+ if (isBurstBifurcation() && state == StreamDescriptor::State::ACTIVE &&
+ mCurrentStep + 1 < mSteps.size() &&
+ mSteps[mCurrentStep + 1].first == TransitionTrigger{kTransferReadyEvent}) {
+ mCurrentStep++;
+ }
+ mCurrentStep++;
+ }
+
+ private:
+ StreamDescriptor::State getState() const { return mSteps[mCurrentStep].second; }
+ bool isBurstBifurcation() {
+ return getTrigger() == TransitionTrigger{kBurstCommand} &&
+ getState() == StreamDescriptor::State::TRANSFERRING;
+ }
+ bool isPauseBifurcation() {
+ return getTrigger() == TransitionTrigger{kPauseCommand} &&
+ getState() == StreamDescriptor::State::TRANSFER_PAUSED;
+ }
+ bool isStartBifurcation() {
+ return getTrigger() == TransitionTrigger{kStartCommand} &&
+ getState() == StreamDescriptor::State::TRANSFERRING;
+ }
+ const std::vector<StateTransition> mSteps;
+ size_t mCurrentStep = 0;
+};
+
+std::string toString(const TransitionTrigger& trigger) {
+ if (std::holds_alternative<StreamDescriptor::Command>(trigger)) {
+ return std::string("'")
+ .append(toString(std::get<StreamDescriptor::Command>(trigger).getTag()))
+ .append("' command");
+ }
+ return std::string("'")
+ .append(toString(std::get<StreamEventReceiver::Event>(trigger)))
+ .append("' event");
+}
+
+struct StreamLogicDriver {
+ virtual ~StreamLogicDriver() = default;
+ // Return 'true' to stop the worker.
+ virtual bool done() = 0;
+ // For 'Writer' logic, if the 'actualSize' is 0, write is skipped.
+ // The 'fmqByteCount' from the returned command is passed as is to the HAL.
+ virtual TransitionTrigger getNextTrigger(int maxDataSize, int* actualSize = nullptr) = 0;
+ // Return 'true' to indicate that no further processing is needed,
+ // for example, the driver is expecting a bad status to be returned.
+ // The logic cycle will return with 'CONTINUE' status. Otherwise,
+ // the reply will be validated and then passed to 'processValidReply'.
+ virtual bool interceptRawReply(const StreamDescriptor::Reply& reply) = 0;
+ // Return 'false' to indicate that the contents of the reply are unexpected.
+ // Will abort the logic cycle.
+ virtual bool processValidReply(const StreamDescriptor::Reply& reply) = 0;
+};
+
+class StreamCommonLogic : public StreamLogic {
+ protected:
+ StreamCommonLogic(const StreamContext& context, StreamLogicDriver* driver,
+ StreamEventReceiver* eventReceiver)
+ : mCommandMQ(context.getCommandMQ()),
+ mReplyMQ(context.getReplyMQ()),
+ mDataMQ(context.getDataMQ()),
+ mData(context.getBufferSizeBytes()),
+ mDriver(driver),
+ mEventReceiver(eventReceiver) {}
+ StreamContext::CommandMQ* getCommandMQ() const { return mCommandMQ; }
+ StreamContext::ReplyMQ* getReplyMQ() const { return mReplyMQ; }
+ StreamContext::DataMQ* getDataMQ() const { return mDataMQ; }
+ StreamLogicDriver* getDriver() const { return mDriver; }
+ StreamEventReceiver* getEventReceiver() const { return mEventReceiver; }
+
+ std::string init() override {
+ LOG(DEBUG) << __func__;
+ return "";
+ }
+ std::optional<StreamDescriptor::Command> maybeGetNextCommand(int* actualSize = nullptr) {
+ TransitionTrigger trigger = mDriver->getNextTrigger(mData.size(), actualSize);
+ if (StreamEventReceiver::Event* expEvent =
+ std::get_if<StreamEventReceiver::Event>(&trigger);
+ expEvent != nullptr) {
+ auto [eventSeq, event] = mEventReceiver->waitForEvent(mLastEventSeq);
+ mLastEventSeq = eventSeq;
+ if (event != *expEvent) {
+ LOG(ERROR) << __func__ << ": expected event " << toString(*expEvent) << ", got "
+ << toString(event);
+ return {};
+ }
+ // If we were waiting for an event, the new stream state must be retrieved
+ // via 'getStatus'.
+ return StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::getStatus>(
+ Void{});
+ }
+ return std::get<StreamDescriptor::Command>(trigger);
+ }
+ bool readDataFromMQ(size_t readCount) {
+ std::vector<int8_t> data(readCount);
+ if (mDataMQ->read(data.data(), readCount)) {
+ memcpy(mData.data(), data.data(), std::min(mData.size(), data.size()));
+ return true;
+ }
+ LOG(ERROR) << __func__ << ": reading of " << readCount << " bytes from MQ failed";
+ return false;
+ }
+ bool writeDataToMQ() {
+ if (mDataMQ->write(mData.data(), mData.size())) {
+ return true;
+ }
+ LOG(ERROR) << __func__ << ": writing of " << mData.size() << " bytes to MQ failed";
+ return false;
+ }
+
+ private:
+ StreamContext::CommandMQ* mCommandMQ;
+ StreamContext::ReplyMQ* mReplyMQ;
+ StreamContext::DataMQ* mDataMQ;
+ std::vector<int8_t> mData;
+ StreamLogicDriver* const mDriver;
+ StreamEventReceiver* const mEventReceiver;
+ int mLastEventSeq = StreamEventReceiver::kEventSeqInit;
+};
+
+class StreamReaderLogic : public StreamCommonLogic {
+ public:
+ StreamReaderLogic(const StreamContext& context, StreamLogicDriver* driver,
+ StreamEventReceiver* eventReceiver)
+ : StreamCommonLogic(context, driver, eventReceiver) {}
+
+ protected:
+ Status cycle() override {
+ if (getDriver()->done()) {
+ LOG(DEBUG) << __func__ << ": clean exit";
+ return Status::EXIT;
+ }
+ StreamDescriptor::Command command;
+ if (auto maybeCommand = maybeGetNextCommand(); maybeCommand.has_value()) {
+ command = std::move(maybeCommand.value());
+ } else {
+ LOG(ERROR) << __func__ << ": no next command";
+ return Status::ABORT;
+ }
+ LOG(DEBUG) << "Writing command: " << command.toString();
+ if (!getCommandMQ()->writeBlocking(&command, 1)) {
+ LOG(ERROR) << __func__ << ": writing of command into MQ failed";
+ return Status::ABORT;
+ }
+ StreamDescriptor::Reply reply{};
+ LOG(DEBUG) << "Reading reply...";
+ if (!getReplyMQ()->readBlocking(&reply, 1)) {
+ return Status::ABORT;
+ }
+ LOG(DEBUG) << "Reply received: " << reply.toString();
+ if (getDriver()->interceptRawReply(reply)) {
+ LOG(DEBUG) << __func__ << ": reply has been intercepted by the driver";
+ return Status::CONTINUE;
+ }
+ if (reply.status != STATUS_OK) {
+ LOG(ERROR) << __func__ << ": received error status: " << statusToString(reply.status);
+ return Status::ABORT;
+ }
+ if (reply.fmqByteCount < 0 ||
+ (command.getTag() == StreamDescriptor::Command::Tag::burst &&
+ reply.fmqByteCount > command.get<StreamDescriptor::Command::Tag::burst>())) {
+ LOG(ERROR) << __func__
+ << ": received invalid byte count in the reply: " << reply.fmqByteCount;
+ return Status::ABORT;
+ }
+ if (static_cast<size_t>(reply.fmqByteCount) != getDataMQ()->availableToRead()) {
+ LOG(ERROR) << __func__
+ << ": the byte count in the reply is not the same as the amount of "
+ << "data available in the MQ: " << reply.fmqByteCount
+ << " != " << getDataMQ()->availableToRead();
+ }
+ if (reply.latencyMs < 0 && reply.latencyMs != StreamDescriptor::LATENCY_UNKNOWN) {
+ LOG(ERROR) << __func__ << ": received invalid latency value: " << reply.latencyMs;
+ return Status::ABORT;
+ }
+ if (reply.xrunFrames < 0) {
+ LOG(ERROR) << __func__ << ": received invalid xrunFrames value: " << reply.xrunFrames;
+ return Status::ABORT;
+ }
+ if (std::find(enum_range<StreamDescriptor::State>().begin(),
+ enum_range<StreamDescriptor::State>().end(),
+ reply.state) == enum_range<StreamDescriptor::State>().end()) {
+ LOG(ERROR) << __func__ << ": received invalid stream state: " << toString(reply.state);
+ return Status::ABORT;
+ }
+ const bool acceptedReply = getDriver()->processValidReply(reply);
+ if (const size_t readCount = getDataMQ()->availableToRead(); readCount > 0) {
+ if (readDataFromMQ(readCount)) {
+ goto checkAcceptedReply;
+ }
+ LOG(ERROR) << __func__ << ": reading of " << readCount << " data bytes from MQ failed";
+ return Status::ABORT;
+ } // readCount == 0
+ checkAcceptedReply:
+ if (acceptedReply) {
+ return Status::CONTINUE;
+ }
+ LOG(ERROR) << __func__ << ": unacceptable reply: " << reply.toString();
+ return Status::ABORT;
+ }
+};
+using StreamReader = StreamWorker<StreamReaderLogic>;
+
+class StreamWriterLogic : public StreamCommonLogic {
+ public:
+ StreamWriterLogic(const StreamContext& context, StreamLogicDriver* driver,
+ StreamEventReceiver* eventReceiver)
+ : StreamCommonLogic(context, driver, eventReceiver) {}
+
+ protected:
+ Status cycle() override {
+ if (getDriver()->done()) {
+ LOG(DEBUG) << __func__ << ": clean exit";
+ return Status::EXIT;
+ }
+ int actualSize = 0;
+ StreamDescriptor::Command command;
+ if (auto maybeCommand = maybeGetNextCommand(&actualSize); maybeCommand.has_value()) {
+ command = std::move(maybeCommand.value());
+ } else {
+ LOG(ERROR) << __func__ << ": no next command";
+ return Status::ABORT;
+ }
+ if (actualSize != 0 && !writeDataToMQ()) {
+ return Status::ABORT;
+ }
+ LOG(DEBUG) << "Writing command: " << command.toString();
+ if (!getCommandMQ()->writeBlocking(&command, 1)) {
+ LOG(ERROR) << __func__ << ": writing of command into MQ failed";
+ return Status::ABORT;
+ }
+ StreamDescriptor::Reply reply{};
+ LOG(DEBUG) << "Reading reply...";
+ if (!getReplyMQ()->readBlocking(&reply, 1)) {
+ LOG(ERROR) << __func__ << ": reading of reply from MQ failed";
+ return Status::ABORT;
+ }
+ LOG(DEBUG) << "Reply received: " << reply.toString();
+ if (getDriver()->interceptRawReply(reply)) {
+ return Status::CONTINUE;
+ }
+ if (reply.status != STATUS_OK) {
+ LOG(ERROR) << __func__ << ": received error status: " << statusToString(reply.status);
+ return Status::ABORT;
+ }
+ if (reply.fmqByteCount < 0 ||
+ (command.getTag() == StreamDescriptor::Command::Tag::burst &&
+ reply.fmqByteCount > command.get<StreamDescriptor::Command::Tag::burst>())) {
+ LOG(ERROR) << __func__
+ << ": received invalid byte count in the reply: " << reply.fmqByteCount;
+ return Status::ABORT;
+ }
+ if (getDataMQ()->availableToWrite() != getDataMQ()->getQuantumCount()) {
+ LOG(ERROR) << __func__ << ": the HAL module did not consume all data from the data MQ: "
+ << "available to write " << getDataMQ()->availableToWrite()
+ << ", total size: " << getDataMQ()->getQuantumCount();
+ return Status::ABORT;
+ }
+ if (reply.latencyMs < 0 && reply.latencyMs != StreamDescriptor::LATENCY_UNKNOWN) {
+ LOG(ERROR) << __func__ << ": received invalid latency value: " << reply.latencyMs;
+ return Status::ABORT;
+ }
+ if (reply.xrunFrames < 0) {
+ LOG(ERROR) << __func__ << ": received invalid xrunFrames value: " << reply.xrunFrames;
+ return Status::ABORT;
+ }
+ if (std::find(enum_range<StreamDescriptor::State>().begin(),
+ enum_range<StreamDescriptor::State>().end(),
+ reply.state) == enum_range<StreamDescriptor::State>().end()) {
+ LOG(ERROR) << __func__ << ": received invalid stream state: " << toString(reply.state);
+ return Status::ABORT;
+ }
+ if (getDriver()->processValidReply(reply)) {
+ return Status::CONTINUE;
+ }
+ LOG(ERROR) << __func__ << ": unacceptable reply: " << reply.toString();
+ return Status::ABORT;
+ }
+};
+using StreamWriter = StreamWorker<StreamWriterLogic>;
+
+class DefaultStreamCallback : public ::aidl::android::hardware::audio::core::BnStreamCallback,
+ public StreamEventReceiver {
+ ndk::ScopedAStatus onTransferReady() override {
+ LOG(DEBUG) << __func__;
+ putLastEvent(Event::TransferReady);
+ return ndk::ScopedAStatus::ok();
+ }
+ ndk::ScopedAStatus onError() override {
+ LOG(DEBUG) << __func__;
+ putLastEvent(Event::Error);
+ return ndk::ScopedAStatus::ok();
+ }
+ ndk::ScopedAStatus onDrainReady() override {
+ LOG(DEBUG) << __func__;
+ putLastEvent(Event::DrainReady);
+ return ndk::ScopedAStatus::ok();
+ }
+
+ public:
+ // To avoid timing out the whole test suite in case no event is received
+ // from the HAL, use a local timeout for event waiting.
+ static constexpr auto kEventTimeoutMs = std::chrono::milliseconds(1000);
+
+ StreamEventReceiver* getEventReceiver() { return this; }
+ std::tuple<int, Event> getLastEvent() const override {
+ std::lock_guard l(mLock);
+ return getLastEvent_l();
+ }
+ std::tuple<int, Event> waitForEvent(int clientEventSeq) override {
+ std::unique_lock l(mLock);
+ android::base::ScopedLockAssertion lock_assertion(mLock);
+ LOG(DEBUG) << __func__ << ": client " << clientEventSeq << ", last " << mLastEventSeq;
+ if (mCv.wait_for(l, kEventTimeoutMs, [&]() {
+ android::base::ScopedLockAssertion lock_assertion(mLock);
+ return clientEventSeq < mLastEventSeq;
+ })) {
+ } else {
+ LOG(WARNING) << __func__ << ": timed out waiting for an event";
+ putLastEvent_l(Event::None);
+ }
+ return getLastEvent_l();
+ }
+
+ private:
+ std::tuple<int, Event> getLastEvent_l() const REQUIRES(mLock) {
+ return std::make_tuple(mLastEventSeq, mLastEvent);
+ }
+ void putLastEvent(Event event) {
+ {
+ std::lock_guard l(mLock);
+ putLastEvent_l(event);
+ }
+ mCv.notify_one();
+ }
+ void putLastEvent_l(Event event) REQUIRES(mLock) {
+ mLastEventSeq++;
+ mLastEvent = event;
+ }
+
+ mutable std::mutex mLock;
+ std::condition_variable mCv;
+ int mLastEventSeq GUARDED_BY(mLock) = kEventSeqInit;
+ Event mLastEvent GUARDED_BY(mLock) = Event::None;
+};
+
+template <typename T>
+struct IOTraits {
+ static constexpr bool is_input = std::is_same_v<T, IStreamIn>;
+ using Worker = std::conditional_t<is_input, StreamReader, StreamWriter>;
+};
+
+template <typename Stream>
+class WithStream {
+ public:
+ static ndk::ScopedAStatus callClose(std::shared_ptr<Stream> stream) {
+ std::shared_ptr<IStreamCommon> common;
+ ndk::ScopedAStatus status = stream->getStreamCommon(&common);
+ if (!status.isOk()) return status;
+ return common->close();
+ }
+
+ WithStream() {}
+ explicit WithStream(const AudioPortConfig& portConfig) : mPortConfig(portConfig) {}
+ WithStream(const WithStream&) = delete;
+ WithStream& operator=(const WithStream&) = delete;
+ ~WithStream() {
+ if (mStream != nullptr) {
+ mContext.reset();
+ EXPECT_IS_OK(callClose(mStream)) << "port config id " << getPortId();
+ }
+ }
+ void SetUpPortConfig(IModule* module) { ASSERT_NO_FATAL_FAILURE(mPortConfig.SetUp(module)); }
+ ScopedAStatus SetUpNoChecks(IModule* module, long bufferSizeFrames) {
+ return SetUpNoChecks(module, mPortConfig.get(), bufferSizeFrames);
+ }
+ ScopedAStatus SetUpNoChecks(IModule* module, const AudioPortConfig& portConfig,
+ long bufferSizeFrames);
+ void SetUp(IModule* module, long bufferSizeFrames) {
+ ASSERT_NO_FATAL_FAILURE(SetUpPortConfig(module));
+ ASSERT_IS_OK(SetUpNoChecks(module, bufferSizeFrames)) << "port config id " << getPortId();
+ ASSERT_NE(nullptr, mStream) << "port config id " << getPortId();
+ EXPECT_GE(mDescriptor.bufferSizeFrames, bufferSizeFrames)
+ << "actual buffer size must be no less than requested";
+ mContext.emplace(mDescriptor);
+ ASSERT_NO_FATAL_FAILURE(mContext.value().checkIsValid());
+ }
+ Stream* get() const { return mStream.get(); }
+ const StreamContext* getContext() const { return mContext ? &(mContext.value()) : nullptr; }
+ StreamEventReceiver* getEventReceiver() { return mStreamCallback->getEventReceiver(); }
+ std::shared_ptr<Stream> getSharedPointer() const { return mStream; }
+ const AudioPortConfig& getPortConfig() const { return mPortConfig.get(); }
+ int32_t getPortId() const { return mPortConfig.getId(); }
+
+ private:
+ WithAudioPortConfig mPortConfig;
+ std::shared_ptr<Stream> mStream;
+ StreamDescriptor mDescriptor;
+ std::optional<StreamContext> mContext;
+ std::shared_ptr<DefaultStreamCallback> mStreamCallback;
+};
+
+SinkMetadata GenerateSinkMetadata(const AudioPortConfig& portConfig) {
+ RecordTrackMetadata trackMeta;
+ trackMeta.source = AudioSource::MIC;
+ trackMeta.gain = 1.0;
+ trackMeta.channelMask = portConfig.channelMask.value();
+ SinkMetadata metadata;
+ metadata.tracks.push_back(trackMeta);
+ return metadata;
+}
+
+template <>
+ScopedAStatus WithStream<IStreamIn>::SetUpNoChecks(IModule* module,
+ const AudioPortConfig& portConfig,
+ long bufferSizeFrames) {
+ aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments args;
+ args.portConfigId = portConfig.id;
+ args.sinkMetadata = GenerateSinkMetadata(portConfig);
+ args.bufferSizeFrames = bufferSizeFrames;
+ auto callback = ndk::SharedRefBase::make<DefaultStreamCallback>();
+ // TODO: Uncomment when support for asynchronous input is implemented.
+ // args.callback = callback;
+ aidl::android::hardware::audio::core::IModule::OpenInputStreamReturn ret;
+ ScopedAStatus status = module->openInputStream(args, &ret);
+ if (status.isOk()) {
+ mStream = std::move(ret.stream);
+ mDescriptor = std::move(ret.desc);
+ mStreamCallback = std::move(callback);
+ }
+ return status;
+}
+
+SourceMetadata GenerateSourceMetadata(const AudioPortConfig& portConfig) {
+ PlaybackTrackMetadata trackMeta;
+ trackMeta.usage = AudioUsage::MEDIA;
+ trackMeta.contentType = AudioContentType::MUSIC;
+ trackMeta.gain = 1.0;
+ trackMeta.channelMask = portConfig.channelMask.value();
+ SourceMetadata metadata;
+ metadata.tracks.push_back(trackMeta);
+ return metadata;
+}
+
+template <>
+ScopedAStatus WithStream<IStreamOut>::SetUpNoChecks(IModule* module,
+ const AudioPortConfig& portConfig,
+ long bufferSizeFrames) {
+ aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
+ args.portConfigId = portConfig.id;
+ args.sourceMetadata = GenerateSourceMetadata(portConfig);
+ args.offloadInfo = ModuleConfig::generateOffloadInfoIfNeeded(portConfig);
+ args.bufferSizeFrames = bufferSizeFrames;
+ auto callback = ndk::SharedRefBase::make<DefaultStreamCallback>();
+ args.callback = callback;
+ aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
+ ScopedAStatus status = module->openOutputStream(args, &ret);
+ if (status.isOk()) {
+ mStream = std::move(ret.stream);
+ mDescriptor = std::move(ret.desc);
+ mStreamCallback = std::move(callback);
+ }
+ return status;
+}
+
+class WithAudioPatch {
+ public:
+ WithAudioPatch() {}
+ WithAudioPatch(const AudioPortConfig& srcPortConfig, const AudioPortConfig& sinkPortConfig)
+ : mSrcPortConfig(srcPortConfig), mSinkPortConfig(sinkPortConfig) {}
+ WithAudioPatch(bool sinkIsCfg1, const AudioPortConfig& portConfig1,
+ const AudioPortConfig& portConfig2)
+ : mSrcPortConfig(sinkIsCfg1 ? portConfig2 : portConfig1),
+ mSinkPortConfig(sinkIsCfg1 ? portConfig1 : portConfig2) {}
+ WithAudioPatch(const WithAudioPatch&) = delete;
+ WithAudioPatch& operator=(const WithAudioPatch&) = delete;
+ ~WithAudioPatch() {
+ if (mModule != nullptr && mPatch.id != 0) {
+ EXPECT_IS_OK(mModule->resetAudioPatch(mPatch.id)) << "patch id " << getId();
+ }
+ }
+ void SetUpPortConfigs(IModule* module) {
+ ASSERT_NO_FATAL_FAILURE(mSrcPortConfig.SetUp(module));
+ ASSERT_NO_FATAL_FAILURE(mSinkPortConfig.SetUp(module));
+ }
+ ScopedAStatus SetUpNoChecks(IModule* module) {
+ mModule = module;
+ mPatch.sourcePortConfigIds = std::vector<int32_t>{mSrcPortConfig.getId()};
+ mPatch.sinkPortConfigIds = std::vector<int32_t>{mSinkPortConfig.getId()};
+ return mModule->setAudioPatch(mPatch, &mPatch);
+ }
+ void SetUp(IModule* module) {
+ ASSERT_NO_FATAL_FAILURE(SetUpPortConfigs(module));
+ ASSERT_IS_OK(SetUpNoChecks(module)) << "source port config id " << mSrcPortConfig.getId()
+ << "; sink port config id " << mSinkPortConfig.getId();
+ EXPECT_GT(mPatch.minimumStreamBufferSizeFrames, 0) << "patch id " << getId();
+ for (auto latencyMs : mPatch.latenciesMs) {
+ EXPECT_GT(latencyMs, 0) << "patch id " << getId();
+ }
+ }
+ int32_t getId() const { return mPatch.id; }
+ const AudioPatch& get() const { return mPatch; }
+ const AudioPortConfig& getSinkPortConfig() const { return mSinkPortConfig.get(); }
+ const AudioPortConfig& getSrcPortConfig() const { return mSrcPortConfig.get(); }
+ const AudioPortConfig& getPortConfig(bool getSink) const {
+ return getSink ? getSinkPortConfig() : getSrcPortConfig();
+ }
+
+ private:
+ WithAudioPortConfig mSrcPortConfig;
+ WithAudioPortConfig mSinkPortConfig;
+ IModule* mModule = nullptr;
+ AudioPatch mPatch;
+};
+
+TEST_P(AudioCoreModule, Published) {
+ // SetUp must complete with no failures.
+}
+
+TEST_P(AudioCoreModule, CanBeRestarted) {
+ ASSERT_NO_FATAL_FAILURE(RestartService());
+}
+
+TEST_P(AudioCoreModule, PortIdsAreUnique) {
+ std::set<int32_t> portIds;
+ ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
+}
+
+TEST_P(AudioCoreModule, GetAudioPortsIsStable) {
+ std::vector<AudioPort> ports1;
+ ASSERT_IS_OK(module->getAudioPorts(&ports1));
+ std::vector<AudioPort> ports2;
+ ASSERT_IS_OK(module->getAudioPorts(&ports2));
+ ASSERT_EQ(ports1.size(), ports2.size())
+ << "Sizes of audio port arrays do not match across consequent calls to getAudioPorts";
+ std::sort(ports1.begin(), ports1.end());
+ std::sort(ports2.begin(), ports2.end());
+ EXPECT_EQ(ports1, ports2);
+}
+
+TEST_P(AudioCoreModule, GetAudioRoutesIsStable) {
+ std::vector<AudioRoute> routes1;
+ ASSERT_IS_OK(module->getAudioRoutes(&routes1));
+ std::vector<AudioRoute> routes2;
+ ASSERT_IS_OK(module->getAudioRoutes(&routes2));
+ ASSERT_EQ(routes1.size(), routes2.size())
+ << "Sizes of audio route arrays do not match across consequent calls to getAudioRoutes";
+ std::sort(routes1.begin(), routes1.end());
+ std::sort(routes2.begin(), routes2.end());
+ EXPECT_EQ(routes1, routes2);
+}
+
+TEST_P(AudioCoreModule, GetAudioRoutesAreValid) {
+ std::vector<AudioRoute> routes;
+ ASSERT_IS_OK(module->getAudioRoutes(&routes));
+ for (const auto& route : routes) {
+ std::set<int32_t> sources(route.sourcePortIds.begin(), route.sourcePortIds.end());
+ EXPECT_NE(0UL, sources.size())
+ << "empty audio port sinks in the audio route: " << route.toString();
+ EXPECT_EQ(sources.size(), route.sourcePortIds.size())
+ << "IDs of audio port sinks are not unique in the audio route: "
+ << route.toString();
+ }
+}
+
+TEST_P(AudioCoreModule, GetAudioRoutesPortIdsAreValid) {
+ std::set<int32_t> portIds;
+ ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
+ std::vector<AudioRoute> routes;
+ ASSERT_IS_OK(module->getAudioRoutes(&routes));
+ for (const auto& route : routes) {
+ EXPECT_EQ(1UL, portIds.count(route.sinkPortId))
+ << route.sinkPortId << " sink port id is unknown";
+ for (const auto& source : route.sourcePortIds) {
+ EXPECT_EQ(1UL, portIds.count(source)) << source << " source port id is unknown";
+ }
+ }
+}
+
+TEST_P(AudioCoreModule, GetAudioRoutesForAudioPort) {
+ std::set<int32_t> portIds;
+ ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
+ if (portIds.empty()) {
+ GTEST_SKIP() << "No ports in the module.";
+ }
+ for (const auto portId : portIds) {
+ std::vector<AudioRoute> routes;
+ EXPECT_IS_OK(module->getAudioRoutesForAudioPort(portId, &routes));
+ for (const auto& r : routes) {
+ if (r.sinkPortId != portId) {
+ const auto& srcs = r.sourcePortIds;
+ EXPECT_TRUE(std::find(srcs.begin(), srcs.end(), portId) != srcs.end())
+ << " port ID " << portId << " does not used by the route " << r.toString();
+ }
+ }
+ }
+ for (const auto portId : GetNonExistentIds(portIds)) {
+ std::vector<AudioRoute> routes;
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->getAudioRoutesForAudioPort(portId, &routes))
+ << "port ID " << portId;
+ }
+}
+
+TEST_P(AudioCoreModule, CheckDevicePorts) {
+ std::vector<AudioPort> ports;
+ ASSERT_IS_OK(module->getAudioPorts(&ports));
+ std::optional<int32_t> defaultOutput, defaultInput;
+ std::set<AudioDevice> inputs, outputs;
+ const int defaultDeviceFlag = 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE;
+ for (const auto& port : ports) {
+ if (port.ext.getTag() != AudioPortExt::Tag::device) continue;
+ const auto& devicePort = port.ext.get<AudioPortExt::Tag::device>();
+ EXPECT_NE(AudioDeviceType::NONE, devicePort.device.type.type);
+ EXPECT_NE(AudioDeviceType::IN_DEFAULT, devicePort.device.type.type);
+ EXPECT_NE(AudioDeviceType::OUT_DEFAULT, devicePort.device.type.type);
+ if (devicePort.device.type.type > AudioDeviceType::IN_DEFAULT &&
+ devicePort.device.type.type < AudioDeviceType::OUT_DEFAULT) {
+ EXPECT_EQ(AudioIoFlags::Tag::input, port.flags.getTag());
+ } else if (devicePort.device.type.type > AudioDeviceType::OUT_DEFAULT) {
+ EXPECT_EQ(AudioIoFlags::Tag::output, port.flags.getTag());
+ }
+ EXPECT_FALSE((devicePort.flags & defaultDeviceFlag) != 0 &&
+ !devicePort.device.type.connection.empty())
+ << "Device port " << port.id
+ << " must be permanently attached to be set as default";
+ if ((devicePort.flags & defaultDeviceFlag) != 0) {
+ if (port.flags.getTag() == AudioIoFlags::Tag::output) {
+ EXPECT_FALSE(defaultOutput.has_value())
+ << "At least two output device ports are declared as default: "
+ << defaultOutput.value() << " and " << port.id;
+ defaultOutput = port.id;
+ EXPECT_EQ(0UL, outputs.count(devicePort.device))
+ << "Non-unique output device: " << devicePort.device.toString();
+ outputs.insert(devicePort.device);
+ } else if (port.flags.getTag() == AudioIoFlags::Tag::input) {
+ EXPECT_FALSE(defaultInput.has_value())
+ << "At least two input device ports are declared as default: "
+ << defaultInput.value() << " and " << port.id;
+ defaultInput = port.id;
+ EXPECT_EQ(0UL, inputs.count(devicePort.device))
+ << "Non-unique input device: " << devicePort.device.toString();
+ inputs.insert(devicePort.device);
+ } else {
+ FAIL() << "Invalid AudioIoFlags Tag: " << toString(port.flags.getTag());
+ }
+ }
+ }
+}
+
+TEST_P(AudioCoreModule, CheckMixPorts) {
+ std::vector<AudioPort> ports;
+ ASSERT_IS_OK(module->getAudioPorts(&ports));
+ std::optional<int32_t> primaryMixPort;
+ for (const auto& port : ports) {
+ if (port.ext.getTag() != AudioPortExt::Tag::mix) continue;
+ const auto& mixPort = port.ext.get<AudioPortExt::Tag::mix>();
+ if (port.flags.getTag() == AudioIoFlags::Tag::output &&
+ isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::output>(),
+ AudioOutputFlags::PRIMARY)) {
+ EXPECT_FALSE(primaryMixPort.has_value())
+ << "At least two mix ports have PRIMARY flag set: " << primaryMixPort.value()
+ << " and " << port.id;
+ primaryMixPort = port.id;
+ EXPECT_EQ(1, mixPort.maxOpenStreamCount)
+ << "Primary mix port " << port.id << " can not have maxOpenStreamCount "
+ << mixPort.maxOpenStreamCount;
+ }
+ }
+}
+
+TEST_P(AudioCoreModule, GetAudioPort) {
+ std::set<int32_t> portIds;
+ ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
+ if (portIds.empty()) {
+ GTEST_SKIP() << "No ports in the module.";
+ }
+ for (const auto portId : portIds) {
+ AudioPort port;
+ EXPECT_IS_OK(module->getAudioPort(portId, &port));
+ EXPECT_EQ(portId, port.id);
+ }
+ for (const auto portId : GetNonExistentIds(portIds)) {
+ AudioPort port;
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->getAudioPort(portId, &port))
+ << "port ID " << portId;
+ }
+}
+
+TEST_P(AudioCoreModule, SetUpModuleConfig) {
+ ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+ // Send the module config to logcat to facilitate failures investigation.
+ LOG(INFO) << "SetUpModuleConfig: " << moduleConfig->toString();
+}
+
+// Verify that HAL module reports for a connected device port at least one non-dynamic profile,
+// that is, a profile with actual supported configuration.
+// Note: This test relies on simulation of external device connections by the HAL module.
+TEST_P(AudioCoreModule, GetAudioPortWithExternalDevices) {
+ ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+ std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
+ if (ports.empty()) {
+ GTEST_SKIP() << "No external devices in the module.";
+ }
+ for (const auto& port : ports) {
+ AudioPort portWithData = port;
+ portWithData.ext.get<AudioPortExt::Tag::device>().device.address =
+ GenerateUniqueDeviceAddress();
+ WithDevicePortConnectedState portConnected(portWithData);
+ ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
+ const int32_t connectedPortId = portConnected.getId();
+ ASSERT_NE(portWithData.id, connectedPortId);
+ ASSERT_EQ(portWithData.ext.getTag(), portConnected.get().ext.getTag());
+ EXPECT_EQ(portWithData.ext.get<AudioPortExt::Tag::device>().device,
+ portConnected.get().ext.get<AudioPortExt::Tag::device>().device);
+ // Verify that 'getAudioPort' and 'getAudioPorts' return the same connected port.
+ AudioPort connectedPort;
+ EXPECT_IS_OK(module->getAudioPort(connectedPortId, &connectedPort))
+ << "port ID " << connectedPortId;
+ EXPECT_EQ(portConnected.get(), connectedPort);
+ const auto& portProfiles = connectedPort.profiles;
+ EXPECT_NE(0UL, portProfiles.size())
+ << "Connected port has no profiles: " << connectedPort.toString();
+ const auto dynamicProfileIt =
+ std::find_if(portProfiles.begin(), portProfiles.end(), [](const auto& profile) {
+ return profile.format.type == AudioFormatType::DEFAULT;
+ });
+ EXPECT_EQ(portProfiles.end(), dynamicProfileIt) << "Connected port contains dynamic "
+ << "profiles: " << connectedPort.toString();
+
+ std::vector<AudioPort> allPorts;
+ ASSERT_IS_OK(module->getAudioPorts(&allPorts));
+ const auto allPortsIt = findById(allPorts, connectedPortId);
+ EXPECT_NE(allPorts.end(), allPortsIt);
+ if (allPortsIt != allPorts.end()) {
+ EXPECT_EQ(portConnected.get(), *allPortsIt);
+ }
+ }
+}
+
+TEST_P(AudioCoreModule, OpenStreamInvalidPortConfigId) {
+ std::set<int32_t> portConfigIds;
+ ASSERT_NO_FATAL_FAILURE(GetAllPortConfigIds(&portConfigIds));
+ for (const auto portConfigId : GetNonExistentIds(portConfigIds)) {
+ {
+ aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments args;
+ args.portConfigId = portConfigId;
+ args.bufferSizeFrames = kDefaultBufferSizeFrames;
+ aidl::android::hardware::audio::core::IModule::OpenInputStreamReturn ret;
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->openInputStream(args, &ret))
+ << "port config ID " << portConfigId;
+ EXPECT_EQ(nullptr, ret.stream);
+ }
+ {
+ aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
+ args.portConfigId = portConfigId;
+ args.bufferSizeFrames = kDefaultBufferSizeFrames;
+ aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->openOutputStream(args, &ret))
+ << "port config ID " << portConfigId;
+ EXPECT_EQ(nullptr, ret.stream);
+ }
+ }
+}
+
+TEST_P(AudioCoreModule, PortConfigIdsAreUnique) {
+ std::set<int32_t> portConfigIds;
+ ASSERT_NO_FATAL_FAILURE(GetAllPortConfigIds(&portConfigIds));
+}
+
+TEST_P(AudioCoreModule, PortConfigPortIdsAreValid) {
+ std::set<int32_t> portIds;
+ ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
+ std::vector<AudioPortConfig> portConfigs;
+ ASSERT_IS_OK(module->getAudioPortConfigs(&portConfigs));
+ for (const auto& config : portConfigs) {
+ EXPECT_EQ(1UL, portIds.count(config.portId))
+ << config.portId << " port id is unknown, config id " << config.id;
+ }
+}
+
+TEST_P(AudioCoreModule, ResetAudioPortConfigInvalidId) {
+ std::set<int32_t> portConfigIds;
+ ASSERT_NO_FATAL_FAILURE(GetAllPortConfigIds(&portConfigIds));
+ for (const auto portConfigId : GetNonExistentIds(portConfigIds)) {
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->resetAudioPortConfig(portConfigId))
+ << "port config ID " << portConfigId;
+ }
+}
+
+// Verify that for the audio port configs provided by the HAL after init, resetting
+// the config does not delete it, but brings it back to the initial config.
+TEST_P(AudioCoreModule, ResetAudioPortConfigToInitialValue) {
+ std::vector<AudioPortConfig> portConfigsBefore;
+ ASSERT_IS_OK(module->getAudioPortConfigs(&portConfigsBefore));
+ // TODO: Change port configs according to port profiles.
+ for (const auto& c : portConfigsBefore) {
+ EXPECT_IS_OK(module->resetAudioPortConfig(c.id)) << "port config ID " << c.id;
+ }
+ std::vector<AudioPortConfig> portConfigsAfter;
+ ASSERT_IS_OK(module->getAudioPortConfigs(&portConfigsAfter));
+ for (const auto& c : portConfigsBefore) {
+ auto afterIt = findById<AudioPortConfig>(portConfigsAfter, c.id);
+ EXPECT_NE(portConfigsAfter.end(), afterIt)
+ << " port config ID " << c.id << " was removed by reset";
+ if (afterIt != portConfigsAfter.end()) {
+ EXPECT_EQ(c, *afterIt);
+ }
+ }
+}
+
+TEST_P(AudioCoreModule, SetAudioPortConfigSuggestedConfig) {
+ ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+ auto srcMixPort = moduleConfig->getSourceMixPortForAttachedDevice();
+ if (!srcMixPort.has_value()) {
+ GTEST_SKIP() << "No mix port for attached output devices";
+ }
+ AudioPortConfig portConfig;
+ AudioPortConfig suggestedConfig;
+ portConfig.portId = srcMixPort.value().id;
+ {
+ bool applied = true;
+ ASSERT_IS_OK(module->setAudioPortConfig(portConfig, &suggestedConfig, &applied))
+ << "Config: " << portConfig.toString();
+ EXPECT_FALSE(applied);
+ }
+ EXPECT_EQ(0, suggestedConfig.id);
+ EXPECT_TRUE(suggestedConfig.sampleRate.has_value());
+ EXPECT_TRUE(suggestedConfig.channelMask.has_value());
+ EXPECT_TRUE(suggestedConfig.format.has_value());
+ EXPECT_TRUE(suggestedConfig.flags.has_value());
+ WithAudioPortConfig applied(suggestedConfig);
+ ASSERT_NO_FATAL_FAILURE(applied.SetUp(module.get()));
+ const AudioPortConfig& appliedConfig = applied.get();
+ EXPECT_NE(0, appliedConfig.id);
+ EXPECT_TRUE(appliedConfig.sampleRate.has_value());
+ EXPECT_EQ(suggestedConfig.sampleRate.value(), appliedConfig.sampleRate.value());
+ EXPECT_TRUE(appliedConfig.channelMask.has_value());
+ EXPECT_EQ(suggestedConfig.channelMask.value(), appliedConfig.channelMask.value());
+ EXPECT_TRUE(appliedConfig.format.has_value());
+ EXPECT_EQ(suggestedConfig.format.value(), appliedConfig.format.value());
+ EXPECT_TRUE(appliedConfig.flags.has_value());
+ EXPECT_EQ(suggestedConfig.flags.value(), appliedConfig.flags.value());
+}
+
+TEST_P(AudioCoreModule, SetAllAttachedDevicePortConfigs) {
+ ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+ ASSERT_NO_FATAL_FAILURE(ApplyEveryConfig(moduleConfig->getPortConfigsForAttachedDevicePorts()));
+}
+
+// Note: This test relies on simulation of external device connections by the HAL module.
+TEST_P(AudioCoreModule, SetAllExternalDevicePortConfigs) {
+ ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+ std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
+ if (ports.empty()) {
+ GTEST_SKIP() << "No external devices in the module.";
+ }
+ for (const auto& port : ports) {
+ WithDevicePortConnectedState portConnected(port, GenerateUniqueDeviceAddress());
+ ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
+ ASSERT_NO_FATAL_FAILURE(
+ ApplyEveryConfig(moduleConfig->getPortConfigsForDevicePort(portConnected.get())));
+ }
+}
+
+TEST_P(AudioCoreModule, SetAllStaticAudioPortConfigs) {
+ ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+ ASSERT_NO_FATAL_FAILURE(ApplyEveryConfig(moduleConfig->getPortConfigsForMixPorts()));
+}
+
+TEST_P(AudioCoreModule, SetAudioPortConfigInvalidPortId) {
+ std::set<int32_t> portIds;
+ ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
+ for (const auto portId : GetNonExistentIds(portIds)) {
+ AudioPortConfig portConfig, suggestedConfig;
+ bool applied;
+ portConfig.portId = portId;
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
+ module->setAudioPortConfig(portConfig, &suggestedConfig, &applied))
+ << "port ID " << portId;
+ EXPECT_FALSE(suggestedConfig.format.has_value());
+ EXPECT_FALSE(suggestedConfig.channelMask.has_value());
+ EXPECT_FALSE(suggestedConfig.sampleRate.has_value());
+ }
+}
+
+TEST_P(AudioCoreModule, SetAudioPortConfigInvalidPortConfigId) {
+ std::set<int32_t> portConfigIds;
+ ASSERT_NO_FATAL_FAILURE(GetAllPortConfigIds(&portConfigIds));
+ for (const auto portConfigId : GetNonExistentIds(portConfigIds)) {
+ AudioPortConfig portConfig, suggestedConfig;
+ bool applied;
+ portConfig.id = portConfigId;
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
+ module->setAudioPortConfig(portConfig, &suggestedConfig, &applied))
+ << "port config ID " << portConfigId;
+ EXPECT_FALSE(suggestedConfig.format.has_value());
+ EXPECT_FALSE(suggestedConfig.channelMask.has_value());
+ EXPECT_FALSE(suggestedConfig.sampleRate.has_value());
+ }
+}
+
+TEST_P(AudioCoreModule, TryConnectMissingDevice) {
+ ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+ std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
+ if (ports.empty()) {
+ GTEST_SKIP() << "No external devices in the module.";
+ }
+ AudioPort ignored;
+ WithDebugFlags doNotSimulateConnections = WithDebugFlags::createNested(debug);
+ doNotSimulateConnections.flags().simulateDeviceConnections = false;
+ ASSERT_NO_FATAL_FAILURE(doNotSimulateConnections.SetUp(module.get()));
+ for (const auto& port : ports) {
+ AudioPort portWithData = port;
+ portWithData.ext.get<AudioPortExt::Tag::device>().device.address =
+ GenerateUniqueDeviceAddress();
+ EXPECT_STATUS(EX_ILLEGAL_STATE, module->connectExternalDevice(portWithData, &ignored))
+ << "static port " << portWithData.toString();
+ }
+}
+
+TEST_P(AudioCoreModule, TryChangingConnectionSimulationMidway) {
+ ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+ std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
+ if (ports.empty()) {
+ GTEST_SKIP() << "No external devices in the module.";
+ }
+ WithDevicePortConnectedState portConnected(*ports.begin(), GenerateUniqueDeviceAddress());
+ ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
+ ModuleDebug midwayDebugChange = debug.flags();
+ midwayDebugChange.simulateDeviceConnections = false;
+ EXPECT_STATUS(EX_ILLEGAL_STATE, module->setModuleDebug(midwayDebugChange))
+ << "when trying to disable connections simulation while having a connected device";
+}
+
+TEST_P(AudioCoreModule, ConnectDisconnectExternalDeviceInvalidPorts) {
+ AudioPort ignored;
+ std::set<int32_t> portIds;
+ ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
+ for (const auto portId : GetNonExistentIds(portIds)) {
+ AudioPort invalidPort;
+ invalidPort.id = portId;
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->connectExternalDevice(invalidPort, &ignored))
+ << "port ID " << portId << ", when setting CONNECTED state";
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->disconnectExternalDevice(portId))
+ << "port ID " << portId << ", when setting DISCONNECTED state";
+ }
+
+ std::vector<AudioPort> ports;
+ ASSERT_IS_OK(module->getAudioPorts(&ports));
+ for (const auto& port : ports) {
+ if (port.ext.getTag() != AudioPortExt::Tag::device) {
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->connectExternalDevice(port, &ignored))
+ << "non-device port ID " << port.id << " when setting CONNECTED state";
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->disconnectExternalDevice(port.id))
+ << "non-device port ID " << port.id << " when setting DISCONNECTED state";
+ } else {
+ const auto& devicePort = port.ext.get<AudioPortExt::Tag::device>();
+ if (devicePort.device.type.connection.empty()) {
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->connectExternalDevice(port, &ignored))
+ << "for a permanently attached device port ID " << port.id
+ << " when setting CONNECTED state";
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->disconnectExternalDevice(port.id))
+ << "for a permanently attached device port ID " << port.id
+ << " when setting DISCONNECTED state";
+ }
+ }
+ }
+}
+
+// Note: This test relies on simulation of external device connections by the HAL module.
+TEST_P(AudioCoreModule, ConnectDisconnectExternalDeviceTwice) {
+ ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+ AudioPort ignored;
+ std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
+ if (ports.empty()) {
+ GTEST_SKIP() << "No external devices in the module.";
+ }
+ for (const auto& port : ports) {
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->disconnectExternalDevice(port.id))
+ << "when disconnecting already disconnected device port ID " << port.id;
+ AudioPort portWithData = port;
+ portWithData.ext.get<AudioPortExt::Tag::device>().device.address =
+ GenerateUniqueDeviceAddress();
+ WithDevicePortConnectedState portConnected(portWithData);
+ ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
+ module->connectExternalDevice(portConnected.get(), &ignored))
+ << "when trying to connect a connected device port "
+ << portConnected.get().toString();
+ EXPECT_STATUS(EX_ILLEGAL_STATE, module->connectExternalDevice(portWithData, &ignored))
+ << "when connecting again the external device "
+ << portWithData.ext.get<AudioPortExt::Tag::device>().device.toString()
+ << "; Returned connected port " << ignored.toString() << " for template "
+ << portWithData.toString();
+ }
+}
+
+// Note: This test relies on simulation of external device connections by the HAL module.
+TEST_P(AudioCoreModule, DisconnectExternalDeviceNonResetPortConfig) {
+ ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+ std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
+ if (ports.empty()) {
+ GTEST_SKIP() << "No external devices in the module.";
+ }
+ for (const auto& port : ports) {
+ WithDevicePortConnectedState portConnected(port, GenerateUniqueDeviceAddress());
+ ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
+ const auto portConfig = moduleConfig->getSingleConfigForDevicePort(portConnected.get());
+ {
+ WithAudioPortConfig config(portConfig);
+ // Note: if SetUp fails, check the status of 'GetAudioPortWithExternalDevices' test.
+ // Our test assumes that 'getAudioPort' returns at least one profile, and it
+ // is not a dynamic profile.
+ ASSERT_NO_FATAL_FAILURE(config.SetUp(module.get()));
+ EXPECT_STATUS(EX_ILLEGAL_STATE, module->disconnectExternalDevice(portConnected.getId()))
+ << "when trying to disconnect device port ID " << port.id
+ << " with active configuration " << config.getId();
+ }
+ }
+}
+
+TEST_P(AudioCoreModule, ExternalDevicePortRoutes) {
+ ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+ std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
+ if (ports.empty()) {
+ GTEST_SKIP() << "No external devices in the module.";
+ }
+ for (const auto& port : ports) {
+ std::vector<AudioRoute> routesBefore;
+ ASSERT_IS_OK(module->getAudioRoutes(&routesBefore));
+
+ int32_t connectedPortId;
+ {
+ WithDevicePortConnectedState portConnected(port, GenerateUniqueDeviceAddress());
+ ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
+ connectedPortId = portConnected.getId();
+ std::vector<AudioRoute> connectedPortRoutes;
+ ASSERT_IS_OK(module->getAudioRoutesForAudioPort(connectedPortId, &connectedPortRoutes))
+ << "when retrieving routes for connected port id " << connectedPortId;
+ // There must be routes for the port to be useful.
+ if (connectedPortRoutes.empty()) {
+ std::vector<AudioRoute> allRoutes;
+ ASSERT_IS_OK(module->getAudioRoutes(&allRoutes));
+ ADD_FAILURE() << " no routes returned for the connected port "
+ << portConnected.get().toString()
+ << "; all routes: " << android::internal::ToString(allRoutes);
+ }
+ }
+ std::vector<AudioRoute> ignored;
+ ASSERT_STATUS(EX_ILLEGAL_ARGUMENT,
+ module->getAudioRoutesForAudioPort(connectedPortId, &ignored))
+ << "when retrieving routes for released connected port id " << connectedPortId;
+
+ std::vector<AudioRoute> routesAfter;
+ ASSERT_IS_OK(module->getAudioRoutes(&routesAfter));
+ ASSERT_EQ(routesBefore.size(), routesAfter.size())
+ << "Sizes of audio route arrays do not match after creating and "
+ << "releasing a connected port";
+ std::sort(routesBefore.begin(), routesBefore.end());
+ std::sort(routesAfter.begin(), routesAfter.end());
+ EXPECT_EQ(routesBefore, routesAfter);
+ }
+}
+
+TEST_P(AudioCoreModule, MasterMute) {
+ bool isSupported = false;
+ EXPECT_NO_FATAL_FAILURE(TestAccessors<bool>(module.get(), &IModule::getMasterMute,
+ &IModule::setMasterMute, {false, true}, {},
+ &isSupported));
+ if (!isSupported) {
+ GTEST_SKIP() << "Master mute is not supported";
+ }
+ // TODO: Test that master mute actually mutes output.
+}
+
+TEST_P(AudioCoreModule, MasterVolume) {
+ bool isSupported = false;
+ EXPECT_NO_FATAL_FAILURE(TestAccessors<float>(
+ module.get(), &IModule::getMasterVolume, &IModule::setMasterVolume, {0.0f, 0.5f, 1.0f},
+ {-0.1, 1.1, NAN, INFINITY, -INFINITY, 1 + std::numeric_limits<float>::epsilon()},
+ &isSupported));
+ if (!isSupported) {
+ GTEST_SKIP() << "Master volume is not supported";
+ }
+ // TODO: Test that master volume actually attenuates output.
+}
+
+TEST_P(AudioCoreModule, MicMute) {
+ bool isSupported = false;
+ EXPECT_NO_FATAL_FAILURE(TestAccessors<bool>(module.get(), &IModule::getMicMute,
+ &IModule::setMicMute, {false, true}, {},
+ &isSupported));
+ if (!isSupported) {
+ GTEST_SKIP() << "Mic mute is not supported";
+ }
+ // TODO: Test that mic mute actually mutes input.
+}
+
+TEST_P(AudioCoreModule, GetMicrophones) {
+ ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+ const std::vector<AudioPort> builtInMicPorts = moduleConfig->getAttachedMicrophonePorts();
+ std::vector<MicrophoneInfo> micInfos;
+ ScopedAStatus status = module->getMicrophones(&micInfos);
+ if (!status.isOk()) {
+ EXPECT_EQ(EX_UNSUPPORTED_OPERATION, status.getExceptionCode());
+ ASSERT_FALSE(builtInMicPorts.empty())
+ << "When the HAL module does not have built-in microphones, IModule.getMicrophones"
+ << " must complete with no error and return an empty list";
+ GTEST_SKIP() << "Microphone info is not supported";
+ }
+ std::set<int32_t> micPortIdsWithInfo;
+ for (const auto& micInfo : micInfos) {
+ const auto& micDevice = micInfo.device;
+ const auto it =
+ std::find_if(builtInMicPorts.begin(), builtInMicPorts.end(), [&](const auto& port) {
+ return port.ext.template get<AudioPortExt::Tag::device>().device == micDevice;
+ });
+ if (it != builtInMicPorts.end()) {
+ micPortIdsWithInfo.insert(it->id);
+ } else {
+ ADD_FAILURE() << "No device port found with a device specified for the microphone \""
+ << micInfo.id << "\": " << micDevice.toString();
+ }
+ }
+ if (micPortIdsWithInfo.size() != builtInMicPorts.size()) {
+ std::vector<AudioPort> micPortsNoInfo;
+ std::copy_if(builtInMicPorts.begin(), builtInMicPorts.end(),
+ std::back_inserter(micPortsNoInfo),
+ [&](const auto& port) { return micPortIdsWithInfo.count(port.id) == 0; });
+ ADD_FAILURE() << "No MicrophoneInfo is provided for the following microphone device ports: "
+ << ::android::internal::ToString(micPortsNoInfo);
+ }
+}
+
+TEST_P(AudioCoreModule, UpdateAudioMode) {
+ for (const auto mode : ::ndk::enum_range<AudioMode>()) {
+ EXPECT_IS_OK(module->updateAudioMode(mode)) << toString(mode);
+ }
+ EXPECT_IS_OK(module->updateAudioMode(AudioMode::NORMAL));
+}
+
+TEST_P(AudioCoreModule, UpdateScreenRotation) {
+ for (const auto rotation : ::ndk::enum_range<IModule::ScreenRotation>()) {
+ EXPECT_IS_OK(module->updateScreenRotation(rotation)) << toString(rotation);
+ }
+ EXPECT_IS_OK(module->updateScreenRotation(IModule::ScreenRotation::DEG_0));
+}
+
+TEST_P(AudioCoreModule, UpdateScreenState) {
+ EXPECT_IS_OK(module->updateScreenState(false));
+ EXPECT_IS_OK(module->updateScreenState(true));
+}
+
+TEST_P(AudioCoreModule, GenerateHwAvSyncId) {
+ const auto kStatuses = {EX_NONE, EX_ILLEGAL_STATE};
+ int32_t id1;
+ ndk::ScopedAStatus status = module->generateHwAvSyncId(&id1);
+ if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+ GTEST_SKIP() << "HW AV Sync is not supported";
+ }
+ EXPECT_STATUS(kStatuses, status);
+ if (status.isOk()) {
+ int32_t id2;
+ ASSERT_IS_OK(module->generateHwAvSyncId(&id2));
+ EXPECT_NE(id1, id2) << "HW AV Sync IDs must be unique";
+ }
+}
+
+TEST_P(AudioCoreModule, GetVendorParameters) {
+ bool isGetterSupported = false;
+ EXPECT_NO_FATAL_FAILURE(TestGetVendorParameters(module.get(), &isGetterSupported));
+ ndk::ScopedAStatus status = module->setVendorParameters({}, false);
+ EXPECT_EQ(isGetterSupported, status.getExceptionCode() != EX_UNSUPPORTED_OPERATION)
+ << "Support for getting and setting of vendor parameters must be consistent";
+ if (!isGetterSupported) {
+ GTEST_SKIP() << "Vendor parameters are not supported";
+ }
+}
+
+TEST_P(AudioCoreModule, SetVendorParameters) {
+ bool isSupported = false;
+ EXPECT_NO_FATAL_FAILURE(TestSetVendorParameters(module.get(), &isSupported));
+ if (!isSupported) {
+ GTEST_SKIP() << "Vendor parameters are not supported";
+ }
+}
+
+// See b/262930731. In the absence of offloaded effect implementations,
+// currently we can only pass a nullptr, and the HAL module must either reject
+// it as an invalid argument, or say that offloaded effects are not supported.
+TEST_P(AudioCoreModule, AddRemoveEffectInvalidArguments) {
+ ndk::ScopedAStatus addEffectStatus = module->addDeviceEffect(-1, nullptr);
+ ndk::ScopedAStatus removeEffectStatus = module->removeDeviceEffect(-1, nullptr);
+ const bool isSupported = addEffectStatus.getExceptionCode() != EX_UNSUPPORTED_OPERATION;
+ if (isSupported) {
+ EXPECT_EQ(EX_ILLEGAL_ARGUMENT, addEffectStatus.getExceptionCode());
+ EXPECT_EQ(EX_ILLEGAL_ARGUMENT, removeEffectStatus.getExceptionCode());
+ } else if (EX_UNSUPPORTED_OPERATION != removeEffectStatus.getExceptionCode()) {
+ GTEST_FAIL() << "addEffect and removeEffect must be either supported or not supported "
+ << "together";
+ } else {
+ GTEST_SKIP() << "Offloaded effects not supported";
+ }
+ // Test rejection of a nullptr effect with a valid device port Id.
+ ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+ const auto configs = moduleConfig->getPortConfigsForAttachedDevicePorts();
+ for (const auto& config : configs) {
+ WithAudioPortConfig portConfig(config);
+ ASSERT_NO_FATAL_FAILURE(portConfig.SetUp(module.get()));
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->addDeviceEffect(portConfig.getId(), nullptr));
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->removeDeviceEffect(portConfig.getId(), nullptr));
+ }
+}
+
+class AudioCoreTelephony : public AudioCoreModuleBase, public testing::TestWithParam<std::string> {
+ public:
+ void SetUp() override {
+ ASSERT_NO_FATAL_FAILURE(SetUpImpl(GetParam()));
+ ASSERT_IS_OK(module->getTelephony(&telephony));
+ }
+
+ void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownImpl()); }
+
+ std::shared_ptr<ITelephony> telephony;
+};
+
+TEST_P(AudioCoreTelephony, GetSupportedAudioModes) {
+ if (telephony == nullptr) {
+ GTEST_SKIP() << "Telephony is not supported";
+ }
+ std::vector<AudioMode> modes1;
+ ASSERT_IS_OK(telephony->getSupportedAudioModes(&modes1));
+ const std::vector<AudioMode> kMandatoryModes = {AudioMode::NORMAL, AudioMode::RINGTONE,
+ AudioMode::IN_CALL,
+ AudioMode::IN_COMMUNICATION};
+ for (const auto mode : kMandatoryModes) {
+ EXPECT_NE(modes1.end(), std::find(modes1.begin(), modes1.end(), mode))
+ << "Mandatory mode not supported: " << toString(mode);
+ }
+ std::vector<AudioMode> modes2;
+ ASSERT_IS_OK(telephony->getSupportedAudioModes(&modes2));
+ ASSERT_EQ(modes1.size(), modes2.size())
+ << "Sizes of audio mode arrays do not match across consequent calls to "
+ << "getSupportedAudioModes";
+ std::sort(modes1.begin(), modes1.end());
+ std::sort(modes2.begin(), modes2.end());
+ EXPECT_EQ(modes1, modes2);
+};
+
+TEST_P(AudioCoreTelephony, SwitchAudioMode) {
+ if (telephony == nullptr) {
+ GTEST_SKIP() << "Telephony is not supported";
+ }
+ std::vector<AudioMode> supportedModes;
+ ASSERT_IS_OK(telephony->getSupportedAudioModes(&supportedModes));
+ std::set<AudioMode> unsupportedModes = {
+ // Start with all, remove supported ones
+ ::ndk::enum_range<AudioMode>().begin(), ::ndk::enum_range<AudioMode>().end()};
+ for (const auto mode : supportedModes) {
+ EXPECT_IS_OK(telephony->switchAudioMode(mode)) << toString(mode);
+ unsupportedModes.erase(mode);
+ }
+ for (const auto mode : unsupportedModes) {
+ EXPECT_STATUS(EX_UNSUPPORTED_OPERATION, telephony->switchAudioMode(mode)) << toString(mode);
+ }
+}
+
+using CommandSequence = std::vector<StreamDescriptor::Command>;
+class StreamLogicDriverInvalidCommand : public StreamLogicDriver {
+ public:
+ StreamLogicDriverInvalidCommand(const CommandSequence& commands) : mCommands(commands) {}
+
+ std::string getUnexpectedStatuses() {
+ // This method is intended to be called after the worker thread has joined,
+ // thus no extra synchronization is needed.
+ std::string s;
+ if (!mStatuses.empty()) {
+ s = std::string("Pairs of (command, actual status): ")
+ .append((android::internal::ToString(mStatuses)));
+ }
+ return s;
+ }
+
+ bool done() override { return mNextCommand >= mCommands.size(); }
+ TransitionTrigger getNextTrigger(int, int* actualSize) override {
+ if (actualSize != nullptr) *actualSize = 0;
+ return mCommands[mNextCommand++];
+ }
+ bool interceptRawReply(const StreamDescriptor::Reply& reply) override {
+ const size_t currentCommand = mNextCommand - 1; // increased by getNextTrigger
+ const bool isLastCommand = currentCommand == mCommands.size() - 1;
+ // All but the last command should run correctly. The last command must return 'BAD_VALUE'
+ // status.
+ if ((!isLastCommand && reply.status != STATUS_OK) ||
+ (isLastCommand && reply.status != STATUS_BAD_VALUE)) {
+ std::string s = mCommands[currentCommand].toString();
+ s.append(", ").append(statusToString(reply.status));
+ mStatuses.push_back(std::move(s));
+ // Process the reply, since the worker exits in case of an error.
+ return false;
+ }
+ return isLastCommand;
+ }
+ bool processValidReply(const StreamDescriptor::Reply&) override { return true; }
+
+ private:
+ const CommandSequence mCommands;
+ size_t mNextCommand = 0;
+ std::vector<std::string> mStatuses;
+};
+
+template <typename Stream>
+class AudioStream : public AudioCoreModule {
+ public:
+ void SetUp() override {
+ ASSERT_NO_FATAL_FAILURE(AudioCoreModule::SetUp());
+ ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+ }
+
+ void GetStreamCommon() {
+ const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
+ if (!portConfig.has_value()) {
+ GTEST_SKIP() << "No mix port for attached devices";
+ }
+ WithStream<Stream> stream(portConfig.value());
+ ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+ std::shared_ptr<IStreamCommon> streamCommon1;
+ EXPECT_IS_OK(stream.get()->getStreamCommon(&streamCommon1));
+ std::shared_ptr<IStreamCommon> streamCommon2;
+ EXPECT_IS_OK(stream.get()->getStreamCommon(&streamCommon2));
+ ASSERT_NE(nullptr, streamCommon1);
+ ASSERT_NE(nullptr, streamCommon2);
+ EXPECT_EQ(streamCommon1->asBinder(), streamCommon2->asBinder())
+ << "getStreamCommon must return the same interface instance across invocations";
+ }
+
+ void CloseTwice() {
+ const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
+ if (!portConfig.has_value()) {
+ GTEST_SKIP() << "No mix port for attached devices";
+ }
+ std::shared_ptr<Stream> heldStream;
+ {
+ WithStream<Stream> stream(portConfig.value());
+ ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+ heldStream = stream.getSharedPointer();
+ }
+ EXPECT_STATUS(EX_ILLEGAL_STATE, WithStream<Stream>::callClose(heldStream))
+ << "when closing the stream twice";
+ }
+
+ void OpenAllConfigs() {
+ const auto allPortConfigs =
+ moduleConfig->getPortConfigsForMixPorts(IOTraits<Stream>::is_input);
+ for (const auto& portConfig : allPortConfigs) {
+ WithStream<Stream> stream(portConfig);
+ ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+ }
+ }
+
+ void OpenInvalidBufferSize() {
+ const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
+ if (!portConfig.has_value()) {
+ GTEST_SKIP() << "No mix port for attached devices";
+ }
+ WithStream<Stream> stream(portConfig.value());
+ ASSERT_NO_FATAL_FAILURE(stream.SetUpPortConfig(module.get()));
+ for (long bufferSize : std::array<long, 3>{-1, 0, std::numeric_limits<long>::max()}) {
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, stream.SetUpNoChecks(module.get(), bufferSize))
+ << "for the buffer size " << bufferSize;
+ EXPECT_EQ(nullptr, stream.get());
+ }
+ }
+
+ void OpenInvalidDirection() {
+ // Important! The direction of the port config must be reversed.
+ const auto portConfig =
+ moduleConfig->getSingleConfigForMixPort(!IOTraits<Stream>::is_input);
+ if (!portConfig.has_value()) {
+ GTEST_SKIP() << "No mix port for attached devices";
+ }
+ WithStream<Stream> stream(portConfig.value());
+ ASSERT_NO_FATAL_FAILURE(stream.SetUpPortConfig(module.get()));
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
+ stream.SetUpNoChecks(module.get(), kDefaultBufferSizeFrames))
+ << "port config ID " << stream.getPortId();
+ EXPECT_EQ(nullptr, stream.get());
+ }
+
+ void OpenOverMaxCount() {
+ constexpr bool isInput = IOTraits<Stream>::is_input;
+ auto ports = moduleConfig->getMixPorts(isInput, true /*attachedOnly*/);
+ bool hasSingleRun = false;
+ for (const auto& port : ports) {
+ const size_t maxStreamCount = port.ext.get<AudioPortExt::Tag::mix>().maxOpenStreamCount;
+ if (maxStreamCount == 0) {
+ continue;
+ }
+ auto portConfigs = moduleConfig->getPortConfigsForMixPorts(isInput, port);
+ if (portConfigs.size() < maxStreamCount + 1) {
+ // Not able to open a sufficient number of streams for this port.
+ continue;
+ }
+ hasSingleRun = true;
+ std::optional<WithStream<Stream>> streamWraps[maxStreamCount + 1];
+ for (size_t i = 0; i <= maxStreamCount; ++i) {
+ streamWraps[i].emplace(portConfigs[i]);
+ WithStream<Stream>& stream = streamWraps[i].value();
+ if (i < maxStreamCount) {
+ ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+ } else {
+ ASSERT_NO_FATAL_FAILURE(stream.SetUpPortConfig(module.get()));
+ EXPECT_STATUS(EX_ILLEGAL_STATE,
+ stream.SetUpNoChecks(module.get(), kDefaultBufferSizeFrames))
+ << "port config ID " << stream.getPortId() << ", maxOpenStreamCount is "
+ << maxStreamCount;
+ }
+ }
+ }
+ if (!hasSingleRun) {
+ GTEST_SKIP() << "Not enough ports to test max open stream count";
+ }
+ }
+
+ void OpenTwiceSamePortConfig() {
+ const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
+ if (!portConfig.has_value()) {
+ GTEST_SKIP() << "No mix port for attached devices";
+ }
+ EXPECT_NO_FATAL_FAILURE(OpenTwiceSamePortConfigImpl(portConfig.value()));
+ }
+
+ void ResetPortConfigWithOpenStream() {
+ const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
+ if (!portConfig.has_value()) {
+ GTEST_SKIP() << "No mix port for attached devices";
+ }
+ WithStream<Stream> stream(portConfig.value());
+ ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+ EXPECT_STATUS(EX_ILLEGAL_STATE, module->resetAudioPortConfig(stream.getPortId()))
+ << "port config ID " << stream.getPortId();
+ }
+
+ void SendInvalidCommand() {
+ const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
+ if (!portConfig.has_value()) {
+ GTEST_SKIP() << "No mix port for attached devices";
+ }
+ EXPECT_NO_FATAL_FAILURE(SendInvalidCommandImpl(portConfig.value()));
+ }
+
+ void UpdateHwAvSyncId() {
+ const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
+ if (!portConfig.has_value()) {
+ GTEST_SKIP() << "No mix port for attached devices";
+ }
+ WithStream<Stream> stream(portConfig.value());
+ ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+ std::shared_ptr<IStreamCommon> streamCommon;
+ ASSERT_IS_OK(stream.get()->getStreamCommon(&streamCommon));
+ ASSERT_NE(nullptr, streamCommon);
+ const auto kStatuses = {EX_NONE, EX_ILLEGAL_ARGUMENT, EX_ILLEGAL_STATE};
+ for (const auto id : {-100, -1, 0, 1, 100}) {
+ ndk::ScopedAStatus status = streamCommon->updateHwAvSyncId(id);
+ if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+ GTEST_SKIP() << "HW AV Sync is not supported";
+ }
+ EXPECT_STATUS(kStatuses, status) << "id: " << id;
+ }
+ }
+
+ void GetVendorParameters() {
+ const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
+ if (!portConfig.has_value()) {
+ GTEST_SKIP() << "No mix port for attached devices";
+ }
+ WithStream<Stream> stream(portConfig.value());
+ ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+ std::shared_ptr<IStreamCommon> streamCommon;
+ ASSERT_IS_OK(stream.get()->getStreamCommon(&streamCommon));
+ ASSERT_NE(nullptr, streamCommon);
+
+ bool isGetterSupported = false;
+ EXPECT_NO_FATAL_FAILURE(TestGetVendorParameters(module.get(), &isGetterSupported));
+ ndk::ScopedAStatus status = module->setVendorParameters({}, false);
+ EXPECT_EQ(isGetterSupported, status.getExceptionCode() != EX_UNSUPPORTED_OPERATION)
+ << "Support for getting and setting of vendor parameters must be consistent";
+ if (!isGetterSupported) {
+ GTEST_SKIP() << "Vendor parameters are not supported";
+ }
+ }
+
+ void SetVendorParameters() {
+ const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
+ if (!portConfig.has_value()) {
+ GTEST_SKIP() << "No mix port for attached devices";
+ }
+ WithStream<Stream> stream(portConfig.value());
+ ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+ std::shared_ptr<IStreamCommon> streamCommon;
+ ASSERT_IS_OK(stream.get()->getStreamCommon(&streamCommon));
+ ASSERT_NE(nullptr, streamCommon);
+
+ bool isSupported = false;
+ EXPECT_NO_FATAL_FAILURE(TestSetVendorParameters(module.get(), &isSupported));
+ if (!isSupported) {
+ GTEST_SKIP() << "Vendor parameters are not supported";
+ }
+ }
+
+ void HwGainHwVolume() {
+ const auto ports =
+ moduleConfig->getMixPorts(IOTraits<Stream>::is_input, false /*attachedOnly*/);
+ if (ports.empty()) {
+ GTEST_SKIP() << "No mix ports";
+ }
+ bool atLeastOneSupports = false;
+ for (const auto& port : ports) {
+ const auto portConfig = moduleConfig->getSingleConfigForMixPort(true, port);
+ if (!portConfig.has_value()) continue;
+ WithStream<Stream> stream(portConfig.value());
+ ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+ std::vector<std::vector<float>> validValues, invalidValues;
+ bool isSupported = false;
+ if constexpr (IOTraits<Stream>::is_input) {
+ GenerateTestArrays<float>(getChannelCount(portConfig.value().channelMask.value()),
+ IStreamIn::HW_GAIN_MIN, IStreamIn::HW_GAIN_MAX,
+ &validValues, &invalidValues);
+ EXPECT_NO_FATAL_FAILURE(TestAccessors<std::vector<float>>(
+ stream.get(), &IStreamIn::getHwGain, &IStreamIn::setHwGain, validValues,
+ invalidValues, &isSupported));
+ } else {
+ GenerateTestArrays<float>(getChannelCount(portConfig.value().channelMask.value()),
+ IStreamOut::HW_VOLUME_MIN, IStreamOut::HW_VOLUME_MAX,
+ &validValues, &invalidValues);
+ EXPECT_NO_FATAL_FAILURE(TestAccessors<std::vector<float>>(
+ stream.get(), &IStreamOut::getHwVolume, &IStreamOut::setHwVolume,
+ validValues, invalidValues, &isSupported));
+ }
+ if (isSupported) atLeastOneSupports = true;
+ }
+ if (!atLeastOneSupports) {
+ GTEST_SKIP() << "Hardware gain / volume is not supported";
+ }
+ }
+
+ // See b/262930731. In the absence of offloaded effect implementations,
+ // currently we can only pass a nullptr, and the HAL module must either reject
+ // it as an invalid argument, or say that offloaded effects are not supported.
+ void AddRemoveEffectInvalidArguments() {
+ const auto ports =
+ moduleConfig->getMixPorts(IOTraits<Stream>::is_input, false /*attachedOnly*/);
+ if (ports.empty()) {
+ GTEST_SKIP() << "No mix ports";
+ }
+ bool atLeastOneSupports = false;
+ for (const auto& port : ports) {
+ const auto portConfig = moduleConfig->getSingleConfigForMixPort(true, port);
+ if (!portConfig.has_value()) continue;
+ WithStream<Stream> stream(portConfig.value());
+ ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+ std::shared_ptr<IStreamCommon> streamCommon;
+ ASSERT_IS_OK(stream.get()->getStreamCommon(&streamCommon));
+ ASSERT_NE(nullptr, streamCommon);
+ ndk::ScopedAStatus addEffectStatus = streamCommon->addEffect(nullptr);
+ ndk::ScopedAStatus removeEffectStatus = streamCommon->removeEffect(nullptr);
+ const bool isSupported = addEffectStatus.getExceptionCode() != EX_UNSUPPORTED_OPERATION;
+ if (isSupported) {
+ EXPECT_EQ(EX_ILLEGAL_ARGUMENT, addEffectStatus.getExceptionCode());
+ EXPECT_EQ(EX_ILLEGAL_ARGUMENT, removeEffectStatus.getExceptionCode());
+ atLeastOneSupports = true;
+ } else if (EX_UNSUPPORTED_OPERATION != removeEffectStatus.getExceptionCode()) {
+ ADD_FAILURE()
+ << "addEffect and removeEffect must be either supported or not supported "
+ << "together";
+ atLeastOneSupports = true;
+ }
+ }
+ if (!atLeastOneSupports) {
+ GTEST_SKIP() << "Offloaded effects not supported";
+ }
+ }
+
+ void OpenTwiceSamePortConfigImpl(const AudioPortConfig& portConfig) {
+ WithStream<Stream> stream1(portConfig);
+ ASSERT_NO_FATAL_FAILURE(stream1.SetUp(module.get(), kDefaultBufferSizeFrames));
+ WithStream<Stream> stream2;
+ EXPECT_STATUS(EX_ILLEGAL_STATE, stream2.SetUpNoChecks(module.get(), stream1.getPortConfig(),
+ kDefaultBufferSizeFrames))
+ << "when opening a stream twice for the same port config ID "
+ << stream1.getPortId();
+ }
+
+ void SendInvalidCommandImpl(const AudioPortConfig& portConfig) {
+ using TestSequence = std::pair<std::string, CommandSequence>;
+ // The last command in 'CommandSequence' is the one that must trigger
+ // an error status. All preceding commands are to put the state machine
+ // into a state which accepts the last command.
+ std::vector<TestSequence> sequences{
+ std::make_pair(std::string("HalReservedExit"),
+ std::vector{StreamDescriptor::Command::make<
+ StreamDescriptor::Command::Tag::halReservedExit>(0)}),
+ std::make_pair(std::string("BurstNeg"),
+ std::vector{kStartCommand,
+ StreamDescriptor::Command::make<
+ StreamDescriptor::Command::Tag::burst>(-1)}),
+ std::make_pair(
+ std::string("BurstMinInt"),
+ std::vector{kStartCommand, StreamDescriptor::Command::make<
+ StreamDescriptor::Command::Tag::burst>(
+ std::numeric_limits<int32_t>::min())})};
+ if (IOTraits<Stream>::is_input) {
+ sequences.emplace_back("DrainAll",
+ std::vector{kStartCommand, kBurstCommand, kDrainOutAllCommand});
+ sequences.emplace_back(
+ "DrainEarly", std::vector{kStartCommand, kBurstCommand, kDrainOutEarlyCommand});
+ } else {
+ sequences.emplace_back("DrainUnspecified",
+ std::vector{kStartCommand, kBurstCommand, kDrainInCommand});
+ }
+ for (const auto& seq : sequences) {
+ SCOPED_TRACE(std::string("Sequence ").append(seq.first));
+ LOG(DEBUG) << __func__ << ": Sequence " << seq.first;
+ WithStream<Stream> stream(portConfig);
+ ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+ StreamLogicDriverInvalidCommand driver(seq.second);
+ typename IOTraits<Stream>::Worker worker(*stream.getContext(), &driver,
+ stream.getEventReceiver());
+ LOG(DEBUG) << __func__ << ": starting worker...";
+ ASSERT_TRUE(worker.start());
+ LOG(DEBUG) << __func__ << ": joining worker...";
+ worker.join();
+ EXPECT_EQ("", driver.getUnexpectedStatuses());
+ }
+ }
+};
+using AudioStreamIn = AudioStream<IStreamIn>;
+using AudioStreamOut = AudioStream<IStreamOut>;
+
+#define TEST_IN_AND_OUT_STREAM(method_name) \
+ TEST_P(AudioStreamIn, method_name) { \
+ ASSERT_NO_FATAL_FAILURE(method_name()); \
+ } \
+ TEST_P(AudioStreamOut, method_name) { \
+ ASSERT_NO_FATAL_FAILURE(method_name()); \
+ }
+
+TEST_IN_AND_OUT_STREAM(CloseTwice);
+TEST_IN_AND_OUT_STREAM(GetStreamCommon);
+TEST_IN_AND_OUT_STREAM(OpenAllConfigs);
+TEST_IN_AND_OUT_STREAM(OpenInvalidBufferSize);
+TEST_IN_AND_OUT_STREAM(OpenInvalidDirection);
+TEST_IN_AND_OUT_STREAM(OpenOverMaxCount);
+TEST_IN_AND_OUT_STREAM(OpenTwiceSamePortConfig);
+TEST_IN_AND_OUT_STREAM(ResetPortConfigWithOpenStream);
+TEST_IN_AND_OUT_STREAM(SendInvalidCommand);
+TEST_IN_AND_OUT_STREAM(UpdateHwAvSyncId);
+TEST_IN_AND_OUT_STREAM(GetVendorParameters);
+TEST_IN_AND_OUT_STREAM(SetVendorParameters);
+TEST_IN_AND_OUT_STREAM(HwGainHwVolume);
+TEST_IN_AND_OUT_STREAM(AddRemoveEffectInvalidArguments);
+
+namespace aidl::android::hardware::audio::core {
+std::ostream& operator<<(std::ostream& os, const IStreamIn::MicrophoneDirection& md) {
+ os << toString(md);
+ return os;
+}
+} // namespace aidl::android::hardware::audio::core
+
+TEST_P(AudioStreamIn, ActiveMicrophones) {
+ std::vector<MicrophoneInfo> micInfos;
+ ScopedAStatus status = module->getMicrophones(&micInfos);
+ if (!status.isOk()) {
+ GTEST_SKIP() << "Microphone info is not supported";
+ }
+ const auto ports = moduleConfig->getInputMixPorts(true /*attachedOnly*/);
+ if (ports.empty()) {
+ GTEST_SKIP() << "No input mix ports for attached devices";
+ }
+ for (const auto& port : ports) {
+ const auto portConfig = moduleConfig->getSingleConfigForMixPort(true, port);
+ ASSERT_TRUE(portConfig.has_value()) << "No profiles specified for input mix port";
+ WithStream<IStreamIn> stream(portConfig.value());
+ ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+ {
+ // The port of the stream is not connected, thus the list of active mics must be empty.
+ std::vector<MicrophoneDynamicInfo> activeMics;
+ EXPECT_IS_OK(stream.get()->getActiveMicrophones(&activeMics));
+ EXPECT_TRUE(activeMics.empty()) << "a stream on an unconnected port returns a "
+ "non-empty list of active microphones";
+ }
+ if (auto micDevicePorts = ModuleConfig::getBuiltInMicPorts(
+ moduleConfig->getAttachedSourceDevicesPortsForMixPort(port));
+ !micDevicePorts.empty()) {
+ auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(micDevicePorts[0]);
+ WithAudioPatch patch(true /*isInput*/, stream.getPortConfig(), devicePortConfig);
+ ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
+ std::vector<MicrophoneDynamicInfo> activeMics;
+ EXPECT_IS_OK(stream.get()->getActiveMicrophones(&activeMics));
+ for (const auto& mic : activeMics) {
+ EXPECT_NE(micInfos.end(),
+ std::find_if(micInfos.begin(), micInfos.end(),
+ [&](const auto& micInfo) { return micInfo.id == mic.id; }))
+ << "active microphone \"" << mic.id << "\" is not listed in "
+ << "microphone infos returned by the module: "
+ << ::android::internal::ToString(micInfos);
+ EXPECT_NE(0UL, mic.channelMapping.size())
+ << "No channels specified for the microphone \"" << mic.id << "\"";
+ }
+ }
+ {
+ // Now the port of the stream is not connected again, re-check that there are no
+ // active microphones.
+ std::vector<MicrophoneDynamicInfo> activeMics;
+ EXPECT_IS_OK(stream.get()->getActiveMicrophones(&activeMics));
+ EXPECT_TRUE(activeMics.empty()) << "a stream on an unconnected port returns a "
+ "non-empty list of active microphones";
+ }
+ }
+}
+
+TEST_P(AudioStreamIn, MicrophoneDirection) {
+ using MD = IStreamIn::MicrophoneDirection;
+ const auto ports = moduleConfig->getInputMixPorts(true /*attachedOnly*/);
+ if (ports.empty()) {
+ GTEST_SKIP() << "No input mix ports for attached devices";
+ }
+ bool isSupported = false;
+ for (const auto& port : ports) {
+ const auto portConfig = moduleConfig->getSingleConfigForMixPort(true, port);
+ ASSERT_TRUE(portConfig.has_value()) << "No profiles specified for input mix port";
+ WithStream<IStreamIn> stream(portConfig.value());
+ ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+ EXPECT_NO_FATAL_FAILURE(
+ TestAccessors<MD>(stream.get(), &IStreamIn::getMicrophoneDirection,
+ &IStreamIn::setMicrophoneDirection,
+ std::vector<MD>(enum_range<MD>().begin(), enum_range<MD>().end()),
+ {}, &isSupported));
+ if (!isSupported) break;
+ }
+ if (!isSupported) {
+ GTEST_SKIP() << "Microphone direction is not supported";
+ }
+}
+
+TEST_P(AudioStreamIn, MicrophoneFieldDimension) {
+ const auto ports = moduleConfig->getInputMixPorts(true /*attachedOnly*/);
+ if (ports.empty()) {
+ GTEST_SKIP() << "No input mix ports for attached devices";
+ }
+ bool isSupported = false;
+ for (const auto& port : ports) {
+ const auto portConfig = moduleConfig->getSingleConfigForMixPort(true, port);
+ ASSERT_TRUE(portConfig.has_value()) << "No profiles specified for input mix port";
+ WithStream<IStreamIn> stream(portConfig.value());
+ ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+ EXPECT_NO_FATAL_FAILURE(TestAccessors<float>(
+ stream.get(), &IStreamIn::getMicrophoneFieldDimension,
+ &IStreamIn::setMicrophoneFieldDimension,
+ {IStreamIn::MIC_FIELD_DIMENSION_WIDE_ANGLE,
+ IStreamIn::MIC_FIELD_DIMENSION_WIDE_ANGLE / 2.0f,
+ IStreamIn::MIC_FIELD_DIMENSION_NO_ZOOM,
+ IStreamIn::MIC_FIELD_DIMENSION_MAX_ZOOM / 2.0f,
+ IStreamIn::MIC_FIELD_DIMENSION_MAX_ZOOM},
+ {IStreamIn::MIC_FIELD_DIMENSION_WIDE_ANGLE * 2,
+ IStreamIn::MIC_FIELD_DIMENSION_MAX_ZOOM * 2,
+ IStreamIn::MIC_FIELD_DIMENSION_WIDE_ANGLE * 1.1f,
+ IStreamIn::MIC_FIELD_DIMENSION_MAX_ZOOM * 1.1f, -INFINITY, INFINITY, -NAN, NAN},
+ &isSupported));
+ if (!isSupported) break;
+ }
+ if (!isSupported) {
+ GTEST_SKIP() << "Microphone direction is not supported";
+ }
+}
+
+TEST_P(AudioStreamOut, OpenTwicePrimary) {
+ const auto mixPorts =
+ moduleConfig->getPrimaryMixPorts(true /*attachedOnly*/, true /*singlePort*/);
+ if (mixPorts.empty()) {
+ GTEST_SKIP() << "No primary mix port which could be routed to attached devices";
+ }
+ const auto portConfig = moduleConfig->getSingleConfigForMixPort(false, *mixPorts.begin());
+ ASSERT_TRUE(portConfig.has_value()) << "No profiles specified for the primary mix port";
+ EXPECT_NO_FATAL_FAILURE(OpenTwiceSamePortConfigImpl(portConfig.value()));
+}
+
+TEST_P(AudioStreamOut, RequireOffloadInfo) {
+ const auto offloadMixPorts =
+ moduleConfig->getOffloadMixPorts(true /*attachedOnly*/, true /*singlePort*/);
+ if (offloadMixPorts.empty()) {
+ GTEST_SKIP()
+ << "No mix port for compressed offload that could be routed to attached devices";
+ }
+ const auto config = moduleConfig->getSingleConfigForMixPort(false, *offloadMixPorts.begin());
+ ASSERT_TRUE(config.has_value()) << "No profiles specified for the compressed offload mix port";
+ WithAudioPortConfig portConfig(config.value());
+ ASSERT_NO_FATAL_FAILURE(portConfig.SetUp(module.get()));
+ StreamDescriptor descriptor;
+ std::shared_ptr<IStreamOut> ignored;
+ aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
+ args.portConfigId = portConfig.getId();
+ args.sourceMetadata = GenerateSourceMetadata(portConfig.get());
+ args.bufferSizeFrames = kDefaultBufferSizeFrames;
+ aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->openOutputStream(args, &ret))
+ << "when no offload info is provided for a compressed offload mix port";
+}
+
+TEST_P(AudioStreamOut, RequireAsyncCallback) {
+ const auto nonBlockingMixPorts =
+ moduleConfig->getNonBlockingMixPorts(true /*attachedOnly*/, true /*singlePort*/);
+ if (nonBlockingMixPorts.empty()) {
+ GTEST_SKIP()
+ << "No mix port for non-blocking output that could be routed to attached devices";
+ }
+ const auto config =
+ moduleConfig->getSingleConfigForMixPort(false, *nonBlockingMixPorts.begin());
+ ASSERT_TRUE(config.has_value()) << "No profiles specified for the non-blocking mix port";
+ WithAudioPortConfig portConfig(config.value());
+ ASSERT_NO_FATAL_FAILURE(portConfig.SetUp(module.get()));
+ StreamDescriptor descriptor;
+ std::shared_ptr<IStreamOut> ignored;
+ aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
+ args.portConfigId = portConfig.getId();
+ args.sourceMetadata = GenerateSourceMetadata(portConfig.get());
+ args.offloadInfo = ModuleConfig::generateOffloadInfoIfNeeded(portConfig.get());
+ args.bufferSizeFrames = kDefaultBufferSizeFrames;
+ aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->openOutputStream(args, &ret))
+ << "when no async callback is provided for a non-blocking mix port";
+}
+
+class StreamLogicDefaultDriver : public StreamLogicDriver {
+ public:
+ explicit StreamLogicDefaultDriver(std::shared_ptr<StateSequence> commands)
+ : mCommands(commands) {
+ mCommands->rewind();
+ }
+
+ // The three methods below is intended to be called after the worker
+ // thread has joined, thus no extra synchronization is needed.
+ bool hasObservablePositionIncrease() const { return mObservablePositionIncrease; }
+ bool hasRetrogradeObservablePosition() const { return mRetrogradeObservablePosition; }
+ std::string getUnexpectedStateTransition() const { return mUnexpectedTransition; }
+
+ bool done() override { return mCommands->done(); }
+ TransitionTrigger getNextTrigger(int maxDataSize, int* actualSize) override {
+ auto trigger = mCommands->getTrigger();
+ if (StreamDescriptor::Command* command = std::get_if<StreamDescriptor::Command>(&trigger);
+ command != nullptr) {
+ if (command->getTag() == StreamDescriptor::Command::Tag::burst) {
+ if (actualSize != nullptr) {
+ // In the output scenario, reduce slightly the fmqByteCount to verify
+ // that the HAL module always consumes all data from the MQ.
+ if (maxDataSize > 1) maxDataSize--;
+ *actualSize = maxDataSize;
+ }
+ command->set<StreamDescriptor::Command::Tag::burst>(maxDataSize);
+ } else {
+ if (actualSize != nullptr) *actualSize = 0;
+ }
+ }
+ return trigger;
+ }
+ bool interceptRawReply(const StreamDescriptor::Reply&) override { return false; }
+ bool processValidReply(const StreamDescriptor::Reply& reply) override {
+ if (reply.observable.frames != StreamDescriptor::Position::UNKNOWN) {
+ if (mPreviousFrames.has_value()) {
+ if (reply.observable.frames > mPreviousFrames.value()) {
+ mObservablePositionIncrease = true;
+ } else if (reply.observable.frames < mPreviousFrames.value()) {
+ mRetrogradeObservablePosition = true;
+ }
+ }
+ mPreviousFrames = reply.observable.frames;
+ }
+
+ auto expected = mCommands->getExpectedStates();
+ if (expected.count(reply.state) == 0) {
+ std::string s =
+ std::string("Unexpected transition from the state ")
+ .append(mPreviousState.has_value() ? toString(mPreviousState.value())
+ : "<initial state>")
+ .append(" to ")
+ .append(toString(reply.state))
+ .append(" (expected one of ")
+ .append(::android::internal::ToString(expected))
+ .append(") caused by the ")
+ .append(toString(mCommands->getTrigger()));
+ LOG(ERROR) << __func__ << ": " << s;
+ mUnexpectedTransition = std::move(s);
+ return false;
+ }
+ mCommands->advance(reply.state);
+ mPreviousState = reply.state;
+ return true;
+ }
+
+ protected:
+ std::shared_ptr<StateSequence> mCommands;
+ std::optional<StreamDescriptor::State> mPreviousState;
+ std::optional<int64_t> mPreviousFrames;
+ bool mObservablePositionIncrease = false;
+ bool mRetrogradeObservablePosition = false;
+ std::string mUnexpectedTransition;
+};
+
+enum { NAMED_CMD_NAME, NAMED_CMD_DELAY_MS, NAMED_CMD_STREAM_TYPE, NAMED_CMD_CMDS };
+enum class StreamTypeFilter { ANY, SYNC, ASYNC };
+using NamedCommandSequence =
+ std::tuple<std::string, int, StreamTypeFilter, std::shared_ptr<StateSequence>>;
+enum { PARAM_MODULE_NAME, PARAM_CMD_SEQ, PARAM_SETUP_SEQ };
+using StreamIoTestParameters =
+ std::tuple<std::string /*moduleName*/, NamedCommandSequence, bool /*useSetupSequence2*/>;
+template <typename Stream>
+class AudioStreamIo : public AudioCoreModuleBase,
+ public testing::TestWithParam<StreamIoTestParameters> {
+ public:
+ void SetUp() override {
+ ASSERT_NO_FATAL_FAILURE(SetUpImpl(std::get<PARAM_MODULE_NAME>(GetParam())));
+ ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+ }
+
+ void Run() {
+ const auto allPortConfigs =
+ moduleConfig->getPortConfigsForMixPorts(IOTraits<Stream>::is_input);
+ if (allPortConfigs.empty()) {
+ GTEST_SKIP() << "No mix ports have attached devices";
+ }
+ for (const auto& portConfig : allPortConfigs) {
+ SCOPED_TRACE(portConfig.toString());
+ const bool isNonBlocking =
+ IOTraits<Stream>::is_input
+ ? false
+ :
+ // TODO: Uncomment when support for asynchronous input is implemented.
+ /*isBitPositionFlagSet(
+ portConfig.flags.value().template get<AudioIoFlags::Tag::input>(),
+ AudioInputFlags::NON_BLOCKING) :*/
+ isBitPositionFlagSet(portConfig.flags.value()
+ .template get<AudioIoFlags::Tag::output>(),
+ AudioOutputFlags::NON_BLOCKING);
+ if (auto streamType =
+ std::get<NAMED_CMD_STREAM_TYPE>(std::get<PARAM_CMD_SEQ>(GetParam()));
+ (isNonBlocking && streamType == StreamTypeFilter::SYNC) ||
+ (!isNonBlocking && streamType == StreamTypeFilter::ASYNC)) {
+ continue;
+ }
+ WithDebugFlags delayTransientStates = WithDebugFlags::createNested(debug);
+ delayTransientStates.flags().streamTransientStateDelayMs =
+ std::get<NAMED_CMD_DELAY_MS>(std::get<PARAM_CMD_SEQ>(GetParam()));
+ ASSERT_NO_FATAL_FAILURE(delayTransientStates.SetUp(module.get()));
+ const auto& commandsAndStates =
+ std::get<NAMED_CMD_CMDS>(std::get<PARAM_CMD_SEQ>(GetParam()));
+ if (!std::get<PARAM_SETUP_SEQ>(GetParam())) {
+ ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq1(portConfig, commandsAndStates));
+ } else {
+ ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq2(portConfig, commandsAndStates));
+ }
+ }
+ }
+
+ bool ValidateObservablePosition(const AudioPortConfig& devicePortConfig) {
+ return !isTelephonyDeviceType(
+ devicePortConfig.ext.get<AudioPortExt::Tag::device>().device.type.type);
+ }
+
+ // Set up a patch first, then open a stream.
+ void RunStreamIoCommandsImplSeq1(const AudioPortConfig& portConfig,
+ std::shared_ptr<StateSequence> commandsAndStates) {
+ auto devicePorts = moduleConfig->getAttachedDevicesPortsForMixPort(
+ IOTraits<Stream>::is_input, portConfig);
+ ASSERT_FALSE(devicePorts.empty());
+ auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(devicePorts[0]);
+ WithAudioPatch patch(IOTraits<Stream>::is_input, portConfig, devicePortConfig);
+ ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
+
+ WithStream<Stream> stream(patch.getPortConfig(IOTraits<Stream>::is_input));
+ ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+ StreamLogicDefaultDriver driver(commandsAndStates);
+ typename IOTraits<Stream>::Worker worker(*stream.getContext(), &driver,
+ stream.getEventReceiver());
+
+ LOG(DEBUG) << __func__ << ": starting worker...";
+ ASSERT_TRUE(worker.start());
+ LOG(DEBUG) << __func__ << ": joining worker...";
+ worker.join();
+ EXPECT_FALSE(worker.hasError()) << worker.getError();
+ EXPECT_EQ("", driver.getUnexpectedStateTransition());
+ if (ValidateObservablePosition(devicePortConfig)) {
+ EXPECT_TRUE(driver.hasObservablePositionIncrease());
+ EXPECT_FALSE(driver.hasRetrogradeObservablePosition());
+ }
+ }
+
+ // Open a stream, then set up a patch for it.
+ void RunStreamIoCommandsImplSeq2(const AudioPortConfig& portConfig,
+ std::shared_ptr<StateSequence> commandsAndStates) {
+ WithStream<Stream> stream(portConfig);
+ ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+ StreamLogicDefaultDriver driver(commandsAndStates);
+ typename IOTraits<Stream>::Worker worker(*stream.getContext(), &driver,
+ stream.getEventReceiver());
+
+ auto devicePorts = moduleConfig->getAttachedDevicesPortsForMixPort(
+ IOTraits<Stream>::is_input, portConfig);
+ ASSERT_FALSE(devicePorts.empty());
+ auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(devicePorts[0]);
+ WithAudioPatch patch(IOTraits<Stream>::is_input, stream.getPortConfig(), devicePortConfig);
+ ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
+
+ LOG(DEBUG) << __func__ << ": starting worker...";
+ ASSERT_TRUE(worker.start());
+ LOG(DEBUG) << __func__ << ": joining worker...";
+ worker.join();
+ EXPECT_FALSE(worker.hasError()) << worker.getError();
+ EXPECT_EQ("", driver.getUnexpectedStateTransition());
+ if (ValidateObservablePosition(devicePortConfig)) {
+ EXPECT_TRUE(driver.hasObservablePositionIncrease());
+ EXPECT_FALSE(driver.hasRetrogradeObservablePosition());
+ }
+ }
+};
+using AudioStreamIoIn = AudioStreamIo<IStreamIn>;
+using AudioStreamIoOut = AudioStreamIo<IStreamOut>;
+
+#define TEST_IN_AND_OUT_STREAM_IO(method_name) \
+ TEST_P(AudioStreamIoIn, method_name) { \
+ ASSERT_NO_FATAL_FAILURE(method_name()); \
+ } \
+ TEST_P(AudioStreamIoOut, method_name) { \
+ ASSERT_NO_FATAL_FAILURE(method_name()); \
+ }
+
+TEST_IN_AND_OUT_STREAM_IO(Run);
+
+// Tests specific to audio patches. The fixure class is named 'AudioModulePatch'
+// to avoid clashing with 'AudioPatch' class.
+class AudioModulePatch : public AudioCoreModule {
+ public:
+ static std::string direction(bool isInput, bool capitalize) {
+ return isInput ? (capitalize ? "Input" : "input") : (capitalize ? "Output" : "output");
+ }
+
+ void SetUp() override {
+ ASSERT_NO_FATAL_FAILURE(AudioCoreModule::SetUp());
+ ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+ }
+
+ void SetInvalidPatchHelper(int32_t expectedException, const std::vector<int32_t>& sources,
+ const std::vector<int32_t>& sinks) {
+ AudioPatch patch;
+ patch.sourcePortConfigIds = sources;
+ patch.sinkPortConfigIds = sinks;
+ ASSERT_STATUS(expectedException, module->setAudioPatch(patch, &patch))
+ << "patch source ids: " << android::internal::ToString(sources)
+ << "; sink ids: " << android::internal::ToString(sinks);
+ }
+
+ void ResetPortConfigUsedByPatch(bool isInput) {
+ auto srcSinkGroups = moduleConfig->getRoutableSrcSinkGroups(isInput);
+ if (srcSinkGroups.empty()) {
+ GTEST_SKIP() << "No routes to any attached " << direction(isInput, false) << " devices";
+ }
+ auto srcSinkGroup = *srcSinkGroups.begin();
+ auto srcSink = *srcSinkGroup.second.begin();
+ WithAudioPatch patch(srcSink.first, srcSink.second);
+ ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
+ std::vector<int32_t> sourceAndSinkPortConfigIds(patch.get().sourcePortConfigIds);
+ sourceAndSinkPortConfigIds.insert(sourceAndSinkPortConfigIds.end(),
+ patch.get().sinkPortConfigIds.begin(),
+ patch.get().sinkPortConfigIds.end());
+ for (const auto portConfigId : sourceAndSinkPortConfigIds) {
+ EXPECT_STATUS(EX_ILLEGAL_STATE, module->resetAudioPortConfig(portConfigId))
+ << "port config ID " << portConfigId;
+ }
+ }
+
+ void SetInvalidPatch(bool isInput) {
+ auto srcSinkPair = moduleConfig->getRoutableSrcSinkPair(isInput);
+ if (!srcSinkPair.has_value()) {
+ GTEST_SKIP() << "No routes to any attached " << direction(isInput, false) << " devices";
+ }
+ WithAudioPortConfig srcPortConfig(srcSinkPair.value().first);
+ ASSERT_NO_FATAL_FAILURE(srcPortConfig.SetUp(module.get()));
+ WithAudioPortConfig sinkPortConfig(srcSinkPair.value().second);
+ ASSERT_NO_FATAL_FAILURE(sinkPortConfig.SetUp(module.get()));
+ { // Check that the pair can actually be used for setting up a patch.
+ WithAudioPatch patch(srcPortConfig.get(), sinkPortConfig.get());
+ ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
+ }
+ EXPECT_NO_FATAL_FAILURE(
+ SetInvalidPatchHelper(EX_ILLEGAL_ARGUMENT, {}, {sinkPortConfig.getId()}));
+ EXPECT_NO_FATAL_FAILURE(SetInvalidPatchHelper(
+ EX_ILLEGAL_ARGUMENT, {srcPortConfig.getId(), srcPortConfig.getId()},
+ {sinkPortConfig.getId()}));
+ EXPECT_NO_FATAL_FAILURE(
+ SetInvalidPatchHelper(EX_ILLEGAL_ARGUMENT, {srcPortConfig.getId()}, {}));
+ EXPECT_NO_FATAL_FAILURE(
+ SetInvalidPatchHelper(EX_ILLEGAL_ARGUMENT, {srcPortConfig.getId()},
+ {sinkPortConfig.getId(), sinkPortConfig.getId()}));
+
+ std::set<int32_t> portConfigIds;
+ ASSERT_NO_FATAL_FAILURE(GetAllPortConfigIds(&portConfigIds));
+ for (const auto portConfigId : GetNonExistentIds(portConfigIds)) {
+ EXPECT_NO_FATAL_FAILURE(SetInvalidPatchHelper(EX_ILLEGAL_ARGUMENT, {portConfigId},
+ {sinkPortConfig.getId()}));
+ EXPECT_NO_FATAL_FAILURE(SetInvalidPatchHelper(EX_ILLEGAL_ARGUMENT,
+ {srcPortConfig.getId()}, {portConfigId}));
+ }
+ }
+
+ void SetNonRoutablePatch(bool isInput) {
+ auto srcSinkPair = moduleConfig->getNonRoutableSrcSinkPair(isInput);
+ if (!srcSinkPair.has_value()) {
+ GTEST_SKIP() << "All possible source/sink pairs are routable";
+ }
+ WithAudioPatch patch(srcSinkPair.value().first, srcSinkPair.value().second);
+ ASSERT_NO_FATAL_FAILURE(patch.SetUpPortConfigs(module.get()));
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, patch.SetUpNoChecks(module.get()))
+ << "when setting up a patch from " << srcSinkPair.value().first.toString() << " to "
+ << srcSinkPair.value().second.toString() << " that does not have a route";
+ }
+
+ void SetPatch(bool isInput) {
+ auto srcSinkGroups = moduleConfig->getRoutableSrcSinkGroups(isInput);
+ if (srcSinkGroups.empty()) {
+ GTEST_SKIP() << "No routes to any attached " << direction(isInput, false) << " devices";
+ }
+ for (const auto& srcSinkGroup : srcSinkGroups) {
+ const auto& route = srcSinkGroup.first;
+ std::vector<std::unique_ptr<WithAudioPatch>> patches;
+ for (const auto& srcSink : srcSinkGroup.second) {
+ if (!route.isExclusive) {
+ patches.push_back(
+ std::make_unique<WithAudioPatch>(srcSink.first, srcSink.second));
+ EXPECT_NO_FATAL_FAILURE(patches[patches.size() - 1]->SetUp(module.get()));
+ } else {
+ WithAudioPatch patch(srcSink.first, srcSink.second);
+ EXPECT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
+ }
+ }
+ }
+ }
+
+ void UpdatePatch(bool isInput) {
+ auto srcSinkGroups = moduleConfig->getRoutableSrcSinkGroups(isInput);
+ if (srcSinkGroups.empty()) {
+ GTEST_SKIP() << "No routes to any attached " << direction(isInput, false) << " devices";
+ }
+ for (const auto& srcSinkGroup : srcSinkGroups) {
+ for (const auto& srcSink : srcSinkGroup.second) {
+ WithAudioPatch patch(srcSink.first, srcSink.second);
+ ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
+ AudioPatch ignored;
+ EXPECT_NO_FATAL_FAILURE(module->setAudioPatch(patch.get(), &ignored));
+ }
+ }
+ }
+
+ void UpdateInvalidPatchId(bool isInput) {
+ auto srcSinkGroups = moduleConfig->getRoutableSrcSinkGroups(isInput);
+ if (srcSinkGroups.empty()) {
+ GTEST_SKIP() << "No routes to any attached " << direction(isInput, false) << " devices";
+ }
+ // First, set up a patch to ensure that its settings are accepted.
+ auto srcSinkGroup = *srcSinkGroups.begin();
+ auto srcSink = *srcSinkGroup.second.begin();
+ WithAudioPatch patch(srcSink.first, srcSink.second);
+ ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
+ // Then use the same patch setting, except for having an invalid ID.
+ std::set<int32_t> patchIds;
+ ASSERT_NO_FATAL_FAILURE(GetAllPatchIds(&patchIds));
+ for (const auto patchId : GetNonExistentIds(patchIds)) {
+ AudioPatch patchWithNonExistendId = patch.get();
+ patchWithNonExistendId.id = patchId;
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
+ module->setAudioPatch(patchWithNonExistendId, &patchWithNonExistendId))
+ << "patch ID " << patchId;
+ }
+ }
+};
+
+// Not all tests require both directions, so parametrization would require
+// more abstractions.
+#define TEST_PATCH_BOTH_DIRECTIONS(method_name) \
+ TEST_P(AudioModulePatch, method_name##Input) { \
+ ASSERT_NO_FATAL_FAILURE(method_name(true)); \
+ } \
+ TEST_P(AudioModulePatch, method_name##Output) { \
+ ASSERT_NO_FATAL_FAILURE(method_name(false)); \
+ }
+
+TEST_PATCH_BOTH_DIRECTIONS(ResetPortConfigUsedByPatch);
+TEST_PATCH_BOTH_DIRECTIONS(SetInvalidPatch);
+TEST_PATCH_BOTH_DIRECTIONS(SetNonRoutablePatch);
+TEST_PATCH_BOTH_DIRECTIONS(SetPatch);
+TEST_PATCH_BOTH_DIRECTIONS(UpdateInvalidPatchId);
+TEST_PATCH_BOTH_DIRECTIONS(UpdatePatch);
+
+TEST_P(AudioModulePatch, ResetInvalidPatchId) {
+ std::set<int32_t> patchIds;
+ ASSERT_NO_FATAL_FAILURE(GetAllPatchIds(&patchIds));
+ for (const auto patchId : GetNonExistentIds(patchIds)) {
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->resetAudioPatch(patchId))
+ << "patch ID " << patchId;
+ }
+}
+
+class AudioCoreSoundDose : public AudioCoreModuleBase, public testing::TestWithParam<std::string> {
+ public:
+ class NoOpHalSoundDoseCallback : public ISoundDose::BnHalSoundDoseCallback {
+ public:
+ ndk::ScopedAStatus onMomentaryExposureWarning(float in_currentDbA,
+ const AudioDevice& in_audioDevice) override;
+ ndk::ScopedAStatus onNewMelValues(
+ const ISoundDose::IHalSoundDoseCallback::MelRecord& in_melRecord,
+ const AudioDevice& in_audioDevice) override;
+ };
+
+ void SetUp() override {
+ ASSERT_NO_FATAL_FAILURE(SetUpImpl(GetParam()));
+ ASSERT_IS_OK(module->getSoundDose(&soundDose));
+ callback = ndk::SharedRefBase::make<NoOpHalSoundDoseCallback>();
+ }
+
+ void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownImpl()); }
+
+ std::shared_ptr<ISoundDose> soundDose;
+ std::shared_ptr<ISoundDose::IHalSoundDoseCallback> callback;
+};
+
+ndk::ScopedAStatus AudioCoreSoundDose::NoOpHalSoundDoseCallback::onMomentaryExposureWarning(
+ float in_currentDbA, const AudioDevice& in_audioDevice) {
+ // Do nothing
+ (void)in_currentDbA;
+ (void)in_audioDevice;
+ LOG(INFO) << "NoOpHalSoundDoseCallback::onMomentaryExposureWarning called";
+
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus AudioCoreSoundDose::NoOpHalSoundDoseCallback::onNewMelValues(
+ const ISoundDose::IHalSoundDoseCallback::MelRecord& in_melRecord,
+ const AudioDevice& in_audioDevice) {
+ // Do nothing
+ (void)in_melRecord;
+ (void)in_audioDevice;
+ LOG(INFO) << "NoOpHalSoundDoseCallback::onNewMelValues called";
+
+ return ndk::ScopedAStatus::ok();
+}
+
+TEST_P(AudioCoreSoundDose, GetSetOutputRs2) {
+ if (soundDose == nullptr) {
+ GTEST_SKIP() << "SoundDose is not supported";
+ }
+
+ bool isSupported = false;
+ EXPECT_NO_FATAL_FAILURE(TestAccessors<float>(soundDose.get(), &ISoundDose::getOutputRs2,
+ &ISoundDose::setOutputRs2,
+ /*validValues=*/{80.f, 90.f, 100.f},
+ /*invalidValues=*/{79.f, 101.f}, &isSupported));
+ EXPECT_TRUE(isSupported) << "Getting/Setting RS2 must be supported";
+}
+
+TEST_P(AudioCoreSoundDose, CheckDefaultRs2Value) {
+ if (soundDose == nullptr) {
+ GTEST_SKIP() << "SoundDose is not supported";
+ }
+
+ float rs2Value;
+ ASSERT_IS_OK(soundDose->getOutputRs2(&rs2Value));
+ EXPECT_EQ(rs2Value, ISoundDose::DEFAULT_MAX_RS2);
+}
+
+TEST_P(AudioCoreSoundDose, RegisterSoundDoseCallbackTwiceThrowsException) {
+ if (soundDose == nullptr) {
+ GTEST_SKIP() << "SoundDose is not supported";
+ }
+
+ ASSERT_IS_OK(soundDose->registerSoundDoseCallback(callback));
+ EXPECT_STATUS(EX_ILLEGAL_STATE, soundDose->registerSoundDoseCallback(callback))
+ << "Registering sound dose callback twice should throw EX_ILLEGAL_STATE";
+}
+
+TEST_P(AudioCoreSoundDose, RegisterSoundDoseNullCallbackThrowsException) {
+ if (soundDose == nullptr) {
+ GTEST_SKIP() << "SoundDose is not supported";
+ }
+
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, soundDose->registerSoundDoseCallback(nullptr))
+ << "Registering nullptr sound dose callback should throw EX_ILLEGAL_ARGUMENT";
+}
+
+INSTANTIATE_TEST_SUITE_P(AudioCoreModuleTest, AudioCoreModule,
+ testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
+ android::PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioCoreModule);
+INSTANTIATE_TEST_SUITE_P(AudioCoreTelephonyTest, AudioCoreTelephony,
+ testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
+ android::PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioCoreTelephony);
+INSTANTIATE_TEST_SUITE_P(AudioStreamInTest, AudioStreamIn,
+ testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
+ android::PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioStreamIn);
+INSTANTIATE_TEST_SUITE_P(AudioStreamOutTest, AudioStreamOut,
+ testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
+ android::PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioStreamOut);
+INSTANTIATE_TEST_SUITE_P(AudioCoreSoundDoseTest, AudioCoreSoundDose,
+ testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
+ android::PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioCoreSoundDose);
+
+// This is the value used in test sequences for which the test needs to ensure
+// that the HAL stays in a transient state long enough to receive the next command.
+static const int kStreamTransientStateTransitionDelayMs = 3000;
+
+// TODO: Add async test cases for input once it is implemented.
+
+std::shared_ptr<StateSequence> makeBurstCommands(bool isSync, size_t burstCount) {
+ const auto burst =
+ isSync ? std::vector<StateTransition>{std::make_pair(kBurstCommand,
+ StreamDescriptor::State::ACTIVE)}
+ : std::vector<StateTransition>{
+ std::make_pair(kBurstCommand, StreamDescriptor::State::TRANSFERRING),
+ std::make_pair(kTransferReadyEvent, StreamDescriptor::State::ACTIVE)};
+ std::vector<StateTransition> result{
+ std::make_pair(kStartCommand, StreamDescriptor::State::IDLE)};
+ for (size_t i = 0; i < burstCount; ++i) {
+ result.insert(result.end(), burst.begin(), burst.end());
+ }
+ return std::make_shared<SmartStateSequence>(result);
+}
+static const NamedCommandSequence kReadSeq =
+ std::make_tuple(std::string("Read"), 0, StreamTypeFilter::ANY, makeBurstCommands(true, 3));
+static const NamedCommandSequence kWriteSyncSeq = std::make_tuple(
+ std::string("Write"), 0, StreamTypeFilter::SYNC, makeBurstCommands(true, 3));
+static const NamedCommandSequence kWriteAsyncSeq = std::make_tuple(
+ std::string("Write"), 0, StreamTypeFilter::ASYNC, makeBurstCommands(false, 3));
+
+std::shared_ptr<StateSequence> makeAsyncDrainCommands(bool isInput) {
+ return std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
+ std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+ std::make_pair(kBurstCommand, isInput ? StreamDescriptor::State::ACTIVE
+ : StreamDescriptor::State::TRANSFERRING),
+ std::make_pair(isInput ? kDrainInCommand : kDrainOutAllCommand,
+ StreamDescriptor::State::DRAINING),
+ isInput ? std::make_pair(kStartCommand, StreamDescriptor::State::ACTIVE)
+ : std::make_pair(kBurstCommand, StreamDescriptor::State::TRANSFERRING),
+ std::make_pair(isInput ? kDrainInCommand : kDrainOutAllCommand,
+ StreamDescriptor::State::DRAINING)});
+}
+static const NamedCommandSequence kWriteDrainAsyncSeq =
+ std::make_tuple(std::string("WriteDrain"), kStreamTransientStateTransitionDelayMs,
+ StreamTypeFilter::ASYNC, makeAsyncDrainCommands(false));
+static const NamedCommandSequence kDrainInSeq = std::make_tuple(
+ std::string("Drain"), 0, StreamTypeFilter::ANY, makeAsyncDrainCommands(true));
+
+std::shared_ptr<StateSequence> makeDrainOutCommands(bool isSync) {
+ return std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
+ std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+ std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
+ std::make_pair(kDrainOutAllCommand, StreamDescriptor::State::DRAINING),
+ std::make_pair(isSync ? TransitionTrigger(kGetStatusCommand)
+ : TransitionTrigger(kDrainReadyEvent),
+ StreamDescriptor::State::IDLE)});
+}
+static const NamedCommandSequence kDrainOutSyncSeq = std::make_tuple(
+ std::string("Drain"), 0, StreamTypeFilter::SYNC, makeDrainOutCommands(true));
+static const NamedCommandSequence kDrainOutAsyncSeq = std::make_tuple(
+ std::string("Drain"), 0, StreamTypeFilter::ASYNC, makeDrainOutCommands(false));
+
+std::shared_ptr<StateSequence> makeDrainOutPauseCommands(bool isSync) {
+ return std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
+ std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+ std::make_pair(kBurstCommand, isSync ? StreamDescriptor::State::ACTIVE
+ : StreamDescriptor::State::TRANSFERRING),
+ std::make_pair(kDrainOutAllCommand, StreamDescriptor::State::DRAINING),
+ std::make_pair(kPauseCommand, StreamDescriptor::State::DRAIN_PAUSED),
+ std::make_pair(kStartCommand, StreamDescriptor::State::DRAINING),
+ std::make_pair(kPauseCommand, StreamDescriptor::State::DRAIN_PAUSED),
+ std::make_pair(kBurstCommand, isSync ? StreamDescriptor::State::PAUSED
+ : StreamDescriptor::State::TRANSFER_PAUSED)});
+}
+static const NamedCommandSequence kDrainPauseOutSyncSeq =
+ std::make_tuple(std::string("DrainPause"), kStreamTransientStateTransitionDelayMs,
+ StreamTypeFilter::SYNC, makeDrainOutPauseCommands(true));
+static const NamedCommandSequence kDrainPauseOutAsyncSeq =
+ std::make_tuple(std::string("DrainPause"), kStreamTransientStateTransitionDelayMs,
+ StreamTypeFilter::ASYNC, makeDrainOutPauseCommands(false));
+
+// This sequence also verifies that the capture / presentation position is not reset on standby.
+std::shared_ptr<StateSequence> makeStandbyCommands(bool isInput, bool isSync) {
+ return std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
+ std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+ std::make_pair(kStandbyCommand, StreamDescriptor::State::STANDBY),
+ std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+ std::make_pair(kBurstCommand, isInput || isSync
+ ? StreamDescriptor::State::ACTIVE
+ : StreamDescriptor::State::TRANSFERRING),
+ std::make_pair(kPauseCommand, isInput || isSync
+ ? StreamDescriptor::State::PAUSED
+ : StreamDescriptor::State::TRANSFER_PAUSED),
+ std::make_pair(kFlushCommand, isInput ? StreamDescriptor::State::STANDBY
+ : StreamDescriptor::State::IDLE),
+ std::make_pair(isInput ? kGetStatusCommand : kStandbyCommand, // no-op for input
+ StreamDescriptor::State::STANDBY),
+ std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+ std::make_pair(kBurstCommand, isInput || isSync
+ ? StreamDescriptor::State::ACTIVE
+ : StreamDescriptor::State::TRANSFERRING)});
+}
+static const NamedCommandSequence kStandbyInSeq = std::make_tuple(
+ std::string("Standby"), 0, StreamTypeFilter::ANY, makeStandbyCommands(true, false));
+static const NamedCommandSequence kStandbyOutSyncSeq = std::make_tuple(
+ std::string("Standby"), 0, StreamTypeFilter::SYNC, makeStandbyCommands(false, true));
+static const NamedCommandSequence kStandbyOutAsyncSeq =
+ std::make_tuple(std::string("Standby"), kStreamTransientStateTransitionDelayMs,
+ StreamTypeFilter::ASYNC, makeStandbyCommands(false, false));
+
+static const NamedCommandSequence kPauseInSeq =
+ std::make_tuple(std::string("Pause"), 0, StreamTypeFilter::ANY,
+ std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
+ std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+ std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
+ std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
+ std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
+ std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
+ std::make_pair(kFlushCommand, StreamDescriptor::State::STANDBY)}));
+static const NamedCommandSequence kPauseOutSyncSeq =
+ std::make_tuple(std::string("Pause"), 0, StreamTypeFilter::SYNC,
+ std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
+ std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+ std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
+ std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
+ std::make_pair(kStartCommand, StreamDescriptor::State::ACTIVE),
+ std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
+ std::make_pair(kBurstCommand, StreamDescriptor::State::PAUSED),
+ std::make_pair(kStartCommand, StreamDescriptor::State::ACTIVE),
+ std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED)}));
+/* TODO: Figure out a better way for testing sync/async bursts
+static const NamedCommandSequence kPauseOutAsyncSeq = std::make_tuple(
+ std::string("Pause"), kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC,
+ std::make_shared<StaticStateSequence>(std::vector<StateTransition>{
+ std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+ std::make_pair(kBurstCommand, StreamDescriptor::State::TRANSFERRING),
+ std::make_pair(kPauseCommand, StreamDescriptor::State::TRANSFER_PAUSED),
+ std::make_pair(kStartCommand, StreamDescriptor::State::TRANSFERRING),
+ std::make_pair(kPauseCommand, StreamDescriptor::State::TRANSFER_PAUSED),
+ std::make_pair(kDrainOutAllCommand, StreamDescriptor::State::DRAIN_PAUSED),
+ std::make_pair(kBurstCommand, StreamDescriptor::State::TRANSFER_PAUSED)}));
+*/
+
+std::shared_ptr<StateSequence> makeFlushCommands(bool isInput, bool isSync) {
+ return std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
+ std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+ std::make_pair(kBurstCommand, isInput || isSync
+ ? StreamDescriptor::State::ACTIVE
+ : StreamDescriptor::State::TRANSFERRING),
+ std::make_pair(kPauseCommand, isInput || isSync
+ ? StreamDescriptor::State::PAUSED
+ : StreamDescriptor::State::TRANSFER_PAUSED),
+ std::make_pair(kFlushCommand, isInput ? StreamDescriptor::State::STANDBY
+ : StreamDescriptor::State::IDLE)});
+}
+static const NamedCommandSequence kFlushInSeq = std::make_tuple(
+ std::string("Flush"), 0, StreamTypeFilter::ANY, makeFlushCommands(true, false));
+static const NamedCommandSequence kFlushOutSyncSeq = std::make_tuple(
+ std::string("Flush"), 0, StreamTypeFilter::SYNC, makeFlushCommands(false, true));
+static const NamedCommandSequence kFlushOutAsyncSeq =
+ std::make_tuple(std::string("Flush"), kStreamTransientStateTransitionDelayMs,
+ StreamTypeFilter::ASYNC, makeFlushCommands(false, false));
+
+std::shared_ptr<StateSequence> makeDrainPauseFlushOutCommands(bool isSync) {
+ return std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
+ std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+ std::make_pair(kBurstCommand, isSync ? StreamDescriptor::State::ACTIVE
+ : StreamDescriptor::State::TRANSFERRING),
+ std::make_pair(kDrainOutAllCommand, StreamDescriptor::State::DRAINING),
+ std::make_pair(kPauseCommand, StreamDescriptor::State::DRAIN_PAUSED),
+ std::make_pair(kFlushCommand, StreamDescriptor::State::IDLE)});
+}
+static const NamedCommandSequence kDrainPauseFlushOutSyncSeq =
+ std::make_tuple(std::string("DrainPauseFlush"), kStreamTransientStateTransitionDelayMs,
+ StreamTypeFilter::SYNC, makeDrainPauseFlushOutCommands(true));
+static const NamedCommandSequence kDrainPauseFlushOutAsyncSeq =
+ std::make_tuple(std::string("DrainPauseFlush"), kStreamTransientStateTransitionDelayMs,
+ StreamTypeFilter::ASYNC, makeDrainPauseFlushOutCommands(false));
+
+// Note, this isn't the "official" enum printer, it is only used to make the test name suffix.
+std::string PrintStreamFilterToString(StreamTypeFilter filter) {
+ switch (filter) {
+ case StreamTypeFilter::ANY:
+ return "";
+ case StreamTypeFilter::SYNC:
+ return "Sync";
+ case StreamTypeFilter::ASYNC:
+ return "Async";
+ }
+ return std::string("Unknown").append(std::to_string(static_cast<int32_t>(filter)));
+}
+std::string GetStreamIoTestName(const testing::TestParamInfo<StreamIoTestParameters>& info) {
+ return android::PrintInstanceNameToString(
+ testing::TestParamInfo<std::string>{std::get<PARAM_MODULE_NAME>(info.param),
+ info.index})
+ .append("_")
+ .append(std::get<NAMED_CMD_NAME>(std::get<PARAM_CMD_SEQ>(info.param)))
+ .append(PrintStreamFilterToString(
+ std::get<NAMED_CMD_STREAM_TYPE>(std::get<PARAM_CMD_SEQ>(info.param))))
+ .append("_SetupSeq")
+ .append(std::get<PARAM_SETUP_SEQ>(info.param) ? "2" : "1");
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ AudioStreamIoInTest, AudioStreamIoIn,
+ testing::Combine(testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
+ testing::Values(kReadSeq, kDrainInSeq, kStandbyInSeq, kPauseInSeq,
+ kFlushInSeq),
+ testing::Values(false, true)),
+ GetStreamIoTestName);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioStreamIoIn);
+INSTANTIATE_TEST_SUITE_P(
+ AudioStreamIoOutTest, AudioStreamIoOut,
+ testing::Combine(testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
+ testing::Values(kWriteSyncSeq, kWriteAsyncSeq, kWriteDrainAsyncSeq,
+ kDrainOutSyncSeq, kDrainPauseOutSyncSeq,
+ kDrainPauseOutAsyncSeq, kStandbyOutSyncSeq,
+ kStandbyOutAsyncSeq,
+ kPauseOutSyncSeq, // kPauseOutAsyncSeq,
+ kFlushOutSyncSeq, kFlushOutAsyncSeq,
+ kDrainPauseFlushOutSyncSeq, kDrainPauseFlushOutAsyncSeq),
+ testing::Values(false, true)),
+ GetStreamIoTestName);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioStreamIoOut);
+
+INSTANTIATE_TEST_SUITE_P(AudioPatchTest, AudioModulePatch,
+ testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
+ android::PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioModulePatch);
+
+class TestExecutionTracer : public ::testing::EmptyTestEventListener {
+ public:
+ void OnTestStart(const ::testing::TestInfo& test_info) override {
+ TraceTestState("Started", test_info);
+ }
+ void OnTestEnd(const ::testing::TestInfo& test_info) override {
+ TraceTestState("Completed", test_info);
+ }
+
+ private:
+ static void TraceTestState(const std::string& state, const ::testing::TestInfo& test_info) {
+ LOG(INFO) << state << " " << test_info.test_suite_name() << "::" << test_info.name();
+ }
+};
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
+ android::base::SetMinimumLogSeverity(::android::base::DEBUG);
+ ABinderProcess_setThreadPoolMaxThreadCount(1);
+ ABinderProcess_startThreadPool();
+ return RUN_ALL_TESTS();
+}
diff --git a/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp
deleted file mode 100644
index 5e9aa7f..0000000
--- a/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp
+++ /dev/null
@@ -1,2115 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <algorithm>
-#include <cmath>
-#include <limits>
-#include <memory>
-#include <optional>
-#include <set>
-#include <string>
-#include <vector>
-
-#define LOG_TAG "VtsHalAudioCore"
-#include <android-base/logging.h>
-
-#include <StreamWorker.h>
-#include <Utils.h>
-#include <aidl/Gtest.h>
-#include <aidl/Vintf.h>
-#include <aidl/android/hardware/audio/core/IModule.h>
-#include <aidl/android/hardware/audio/core/ITelephony.h>
-#include <aidl/android/media/audio/common/AudioIoFlags.h>
-#include <aidl/android/media/audio/common/AudioOutputFlags.h>
-#include <android-base/chrono_utils.h>
-#include <android/binder_enums.h>
-#include <fmq/AidlMessageQueue.h>
-
-#include "AudioHalBinderServiceUtil.h"
-#include "ModuleConfig.h"
-#include "TestUtils.h"
-
-using namespace android;
-using aidl::android::hardware::audio::common::PlaybackTrackMetadata;
-using aidl::android::hardware::audio::common::RecordTrackMetadata;
-using aidl::android::hardware::audio::common::SinkMetadata;
-using aidl::android::hardware::audio::common::SourceMetadata;
-using aidl::android::hardware::audio::core::AudioMode;
-using aidl::android::hardware::audio::core::AudioPatch;
-using aidl::android::hardware::audio::core::AudioRoute;
-using aidl::android::hardware::audio::core::IModule;
-using aidl::android::hardware::audio::core::IStreamIn;
-using aidl::android::hardware::audio::core::IStreamOut;
-using aidl::android::hardware::audio::core::ITelephony;
-using aidl::android::hardware::audio::core::ModuleDebug;
-using aidl::android::hardware::audio::core::StreamDescriptor;
-using aidl::android::hardware::common::fmq::SynchronizedReadWrite;
-using aidl::android::media::audio::common::AudioContentType;
-using aidl::android::media::audio::common::AudioDevice;
-using aidl::android::media::audio::common::AudioDeviceAddress;
-using aidl::android::media::audio::common::AudioDeviceType;
-using aidl::android::media::audio::common::AudioFormatType;
-using aidl::android::media::audio::common::AudioIoFlags;
-using aidl::android::media::audio::common::AudioOutputFlags;
-using aidl::android::media::audio::common::AudioPort;
-using aidl::android::media::audio::common::AudioPortConfig;
-using aidl::android::media::audio::common::AudioPortDeviceExt;
-using aidl::android::media::audio::common::AudioPortExt;
-using aidl::android::media::audio::common::AudioSource;
-using aidl::android::media::audio::common::AudioUsage;
-using aidl::android::media::audio::common::Void;
-using android::hardware::audio::common::isBitPositionFlagSet;
-using android::hardware::audio::common::StreamLogic;
-using android::hardware::audio::common::StreamWorker;
-using ndk::enum_range;
-using ndk::ScopedAStatus;
-
-template <typename T>
-auto findById(std::vector<T>& v, int32_t id) {
- return std::find_if(v.begin(), v.end(), [&](const auto& e) { return e.id == id; });
-}
-
-template <typename C>
-std::vector<int32_t> GetNonExistentIds(const C& allIds) {
- if (allIds.empty()) {
- return std::vector<int32_t>{-1, 0, 1};
- }
- std::vector<int32_t> nonExistentIds;
- nonExistentIds.push_back(*std::min_element(allIds.begin(), allIds.end()) - 1);
- nonExistentIds.push_back(*std::max_element(allIds.begin(), allIds.end()) + 1);
- return nonExistentIds;
-}
-
-AudioDeviceAddress GenerateUniqueDeviceAddress() {
- static int nextId = 1;
- // TODO: Use connection-specific ID.
- return AudioDeviceAddress::make<AudioDeviceAddress::Tag::id>(std::to_string(++nextId));
-}
-
-// All 'With*' classes are move-only because they are associated with some
-// resource or state of a HAL module.
-class WithDebugFlags {
- public:
- static WithDebugFlags createNested(const WithDebugFlags& parent) {
- return WithDebugFlags(parent.mFlags);
- }
-
- WithDebugFlags() {}
- explicit WithDebugFlags(const ModuleDebug& initial) : mInitial(initial), mFlags(initial) {}
- WithDebugFlags(const WithDebugFlags&) = delete;
- WithDebugFlags& operator=(const WithDebugFlags&) = delete;
- ~WithDebugFlags() {
- if (mModule != nullptr) {
- EXPECT_IS_OK(mModule->setModuleDebug(mInitial));
- }
- }
- void SetUp(IModule* module) { ASSERT_IS_OK(module->setModuleDebug(mFlags)); }
- ModuleDebug& flags() { return mFlags; }
-
- private:
- ModuleDebug mInitial;
- ModuleDebug mFlags;
- IModule* mModule = nullptr;
-};
-
-// For consistency, WithAudioPortConfig can start both with a non-existent
-// port config, and with an existing one. Existence is determined by the
-// id of the provided config. If it's not 0, then WithAudioPortConfig is
-// essentially a no-op wrapper.
-class WithAudioPortConfig {
- public:
- WithAudioPortConfig() {}
- explicit WithAudioPortConfig(const AudioPortConfig& config) : mInitialConfig(config) {}
- WithAudioPortConfig(const WithAudioPortConfig&) = delete;
- WithAudioPortConfig& operator=(const WithAudioPortConfig&) = delete;
- ~WithAudioPortConfig() {
- if (mModule != nullptr) {
- EXPECT_IS_OK(mModule->resetAudioPortConfig(getId())) << "port config id " << getId();
- }
- }
- void SetUp(IModule* module) {
- ASSERT_NE(AudioPortExt::Tag::unspecified, mInitialConfig.ext.getTag())
- << "config: " << mInitialConfig.toString();
- // Negotiation is allowed for device ports because the HAL module is
- // allowed to provide an empty profiles list for attached devices.
- ASSERT_NO_FATAL_FAILURE(
- SetUpImpl(module, mInitialConfig.ext.getTag() == AudioPortExt::Tag::device));
- }
- int32_t getId() const { return mConfig.id; }
- const AudioPortConfig& get() const { return mConfig; }
-
- private:
- void SetUpImpl(IModule* module, bool negotiate) {
- if (mInitialConfig.id == 0) {
- AudioPortConfig suggested;
- bool applied = false;
- ASSERT_IS_OK(module->setAudioPortConfig(mInitialConfig, &suggested, &applied))
- << "Config: " << mInitialConfig.toString();
- if (!applied && negotiate) {
- mInitialConfig = suggested;
- ASSERT_NO_FATAL_FAILURE(SetUpImpl(module, false))
- << " while applying suggested config: " << suggested.toString();
- } else {
- ASSERT_TRUE(applied) << "Suggested: " << suggested.toString();
- mConfig = suggested;
- mModule = module;
- }
- } else {
- mConfig = mInitialConfig;
- }
- }
-
- AudioPortConfig mInitialConfig;
- IModule* mModule = nullptr;
- AudioPortConfig mConfig;
-};
-
-template <typename PropType, class Instance, typename Getter, typename Setter>
-void TestAccessors(Instance* inst, Getter getter, Setter setter,
- const std::vector<PropType>& validValues,
- const std::vector<PropType>& invalidValues, bool* isSupported) {
- PropType initialValue{};
- ScopedAStatus status = (inst->*getter)(&initialValue);
- if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
- *isSupported = false;
- return;
- }
- *isSupported = true;
- for (const auto v : validValues) {
- EXPECT_IS_OK((inst->*setter)(v)) << "for valid value: " << v;
- PropType currentValue{};
- EXPECT_IS_OK((inst->*getter)(¤tValue));
- EXPECT_EQ(v, currentValue);
- }
- for (const auto v : invalidValues) {
- EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, (inst->*setter)(v)) << "for invalid value: " << v;
- }
- EXPECT_IS_OK((inst->*setter)(initialValue)) << "Failed to restore the initial value";
-}
-
-// Can be used as a base for any test here, does not depend on the fixture GTest parameters.
-class AudioCoreModuleBase {
- public:
- // The default buffer size is used mostly for negative tests.
- static constexpr int kDefaultBufferSizeFrames = 256;
-
- void SetUpImpl(const std::string& moduleName) {
- ASSERT_NO_FATAL_FAILURE(ConnectToService(moduleName));
- debug.flags().simulateDeviceConnections = true;
- ASSERT_NO_FATAL_FAILURE(debug.SetUp(module.get()));
- }
-
- void TearDownImpl() {
- if (module != nullptr) {
- EXPECT_IS_OK(module->setModuleDebug(ModuleDebug{}));
- }
- }
-
- void ConnectToService(const std::string& moduleName) {
- module = IModule::fromBinder(binderUtil.connectToService(moduleName));
- ASSERT_NE(module, nullptr);
- }
-
- void RestartService() {
- ASSERT_NE(module, nullptr);
- moduleConfig.reset();
- module = IModule::fromBinder(binderUtil.restartService());
- ASSERT_NE(module, nullptr);
- }
-
- void ApplyEveryConfig(const std::vector<AudioPortConfig>& configs) {
- for (const auto& config : configs) {
- ASSERT_NE(0, config.portId);
- WithAudioPortConfig portConfig(config);
- ASSERT_NO_FATAL_FAILURE(portConfig.SetUp(module.get())); // calls setAudioPortConfig
- EXPECT_EQ(config.portId, portConfig.get().portId);
- std::vector<AudioPortConfig> retrievedPortConfigs;
- ASSERT_IS_OK(module->getAudioPortConfigs(&retrievedPortConfigs));
- const int32_t portConfigId = portConfig.getId();
- auto configIt = std::find_if(
- retrievedPortConfigs.begin(), retrievedPortConfigs.end(),
- [&portConfigId](const auto& retrConf) { return retrConf.id == portConfigId; });
- EXPECT_NE(configIt, retrievedPortConfigs.end())
- << "Port config id returned by setAudioPortConfig: " << portConfigId
- << " is not found in the list returned by getAudioPortConfigs";
- if (configIt != retrievedPortConfigs.end()) {
- EXPECT_EQ(portConfig.get(), *configIt)
- << "Applied port config returned by setAudioPortConfig: "
- << portConfig.get().toString()
- << " is not the same as retrieved via getAudioPortConfigs: "
- << configIt->toString();
- }
- }
- }
-
- template <typename Entity>
- void GetAllEntityIds(std::set<int32_t>* entityIds,
- ScopedAStatus (IModule::*getter)(std::vector<Entity>*),
- const std::string& errorMessage) {
- std::vector<Entity> entities;
- { ASSERT_IS_OK((module.get()->*getter)(&entities)); }
- std::transform(entities.begin(), entities.end(),
- std::inserter(*entityIds, entityIds->begin()),
- [](const auto& entity) { return entity.id; });
- EXPECT_EQ(entities.size(), entityIds->size()) << errorMessage;
- }
-
- void GetAllPatchIds(std::set<int32_t>* patchIds) {
- return GetAllEntityIds<AudioPatch>(
- patchIds, &IModule::getAudioPatches,
- "IDs of audio patches returned by IModule.getAudioPatches are not unique");
- }
-
- void GetAllPortIds(std::set<int32_t>* portIds) {
- return GetAllEntityIds<AudioPort>(
- portIds, &IModule::getAudioPorts,
- "IDs of audio ports returned by IModule.getAudioPorts are not unique");
- }
-
- void GetAllPortConfigIds(std::set<int32_t>* portConfigIds) {
- return GetAllEntityIds<AudioPortConfig>(
- portConfigIds, &IModule::getAudioPortConfigs,
- "IDs of audio port configs returned by IModule.getAudioPortConfigs are not unique");
- }
-
- void SetUpModuleConfig() {
- if (moduleConfig == nullptr) {
- moduleConfig = std::make_unique<ModuleConfig>(module.get());
- ASSERT_EQ(EX_NONE, moduleConfig->getStatus().getExceptionCode())
- << "ModuleConfig init error: " << moduleConfig->getError();
- }
- }
-
- std::shared_ptr<IModule> module;
- std::unique_ptr<ModuleConfig> moduleConfig;
- AudioHalBinderServiceUtil binderUtil;
- WithDebugFlags debug;
-};
-
-class AudioCoreModule : public AudioCoreModuleBase, public testing::TestWithParam<std::string> {
- public:
- void SetUp() override { ASSERT_NO_FATAL_FAILURE(SetUpImpl(GetParam())); }
-
- void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownImpl()); }
-};
-
-class WithDevicePortConnectedState {
- public:
- explicit WithDevicePortConnectedState(const AudioPort& idAndData) : mIdAndData(idAndData) {}
- WithDevicePortConnectedState(const AudioPort& id, const AudioDeviceAddress& address)
- : mIdAndData(setAudioPortAddress(id, address)) {}
- WithDevicePortConnectedState(const WithDevicePortConnectedState&) = delete;
- WithDevicePortConnectedState& operator=(const WithDevicePortConnectedState&) = delete;
- ~WithDevicePortConnectedState() {
- if (mModule != nullptr) {
- EXPECT_IS_OK(mModule->disconnectExternalDevice(getId()))
- << "when disconnecting device port ID " << getId();
- }
- }
- void SetUp(IModule* module) {
- ASSERT_IS_OK(module->connectExternalDevice(mIdAndData, &mConnectedPort))
- << "when connecting device port ID & data " << mIdAndData.toString();
- ASSERT_NE(mIdAndData.id, getId())
- << "ID of the connected port must not be the same as the ID of the template port";
- mModule = module;
- }
- int32_t getId() const { return mConnectedPort.id; }
- const AudioPort& get() { return mConnectedPort; }
-
- private:
- static AudioPort setAudioPortAddress(const AudioPort& id, const AudioDeviceAddress& address) {
- AudioPort result = id;
- result.ext.get<AudioPortExt::Tag::device>().device.address = address;
- return result;
- }
-
- const AudioPort mIdAndData;
- IModule* mModule = nullptr;
- AudioPort mConnectedPort;
-};
-
-class StreamContext {
- public:
- typedef AidlMessageQueue<StreamDescriptor::Command, SynchronizedReadWrite> CommandMQ;
- typedef AidlMessageQueue<StreamDescriptor::Reply, SynchronizedReadWrite> ReplyMQ;
- typedef AidlMessageQueue<int8_t, SynchronizedReadWrite> DataMQ;
-
- explicit StreamContext(const StreamDescriptor& descriptor)
- : mFrameSizeBytes(descriptor.frameSizeBytes),
- mCommandMQ(new CommandMQ(descriptor.command)),
- mReplyMQ(new ReplyMQ(descriptor.reply)),
- mBufferSizeFrames(descriptor.bufferSizeFrames),
- mDataMQ(maybeCreateDataMQ(descriptor)) {}
- void checkIsValid() const {
- EXPECT_NE(0UL, mFrameSizeBytes);
- ASSERT_NE(nullptr, mCommandMQ);
- EXPECT_TRUE(mCommandMQ->isValid());
- ASSERT_NE(nullptr, mReplyMQ);
- EXPECT_TRUE(mReplyMQ->isValid());
- if (mDataMQ != nullptr) {
- EXPECT_TRUE(mDataMQ->isValid());
- EXPECT_GE(mDataMQ->getQuantumCount() * mDataMQ->getQuantumSize(),
- mFrameSizeBytes * mBufferSizeFrames)
- << "Data MQ actual buffer size is "
- "less than the buffer size as specified by the descriptor";
- }
- }
- size_t getBufferSizeBytes() const { return mFrameSizeBytes * mBufferSizeFrames; }
- size_t getBufferSizeFrames() const { return mBufferSizeFrames; }
- CommandMQ* getCommandMQ() const { return mCommandMQ.get(); }
- DataMQ* getDataMQ() const { return mDataMQ.get(); }
- ReplyMQ* getReplyMQ() const { return mReplyMQ.get(); }
-
- private:
- static std::unique_ptr<DataMQ> maybeCreateDataMQ(const StreamDescriptor& descriptor) {
- using Tag = StreamDescriptor::AudioBuffer::Tag;
- if (descriptor.audio.getTag() == Tag::fmq) {
- return std::make_unique<DataMQ>(descriptor.audio.get<Tag::fmq>());
- }
- return nullptr;
- }
-
- const size_t mFrameSizeBytes;
- std::unique_ptr<CommandMQ> mCommandMQ;
- std::unique_ptr<ReplyMQ> mReplyMQ;
- const size_t mBufferSizeFrames;
- std::unique_ptr<DataMQ> mDataMQ;
-};
-
-class StreamLogicDriver {
- public:
- virtual ~StreamLogicDriver() = default;
- // Return 'true' to stop the worker.
- virtual bool done() = 0;
- // For 'Writer' logic, if the 'actualSize' is 0, write is skipped.
- // The 'fmqByteCount' from the returned command is passed as is to the HAL.
- virtual StreamDescriptor::Command getNextCommand(int maxDataSize,
- int* actualSize = nullptr) = 0;
- // Return 'true' to indicate that no further processing is needed,
- // for example, the driver is expecting a bad status to be returned.
- // The logic cycle will return with 'CONTINUE' status. Otherwise,
- // the reply will be validated and then passed to 'processValidReply'.
- virtual bool interceptRawReply(const StreamDescriptor::Reply& reply) = 0;
- // Return 'false' to indicate that the contents of the reply are unexpected.
- // Will abort the logic cycle.
- virtual bool processValidReply(const StreamDescriptor::Reply& reply) = 0;
-};
-
-class StreamCommonLogic : public StreamLogic {
- protected:
- StreamCommonLogic(const StreamContext& context, StreamLogicDriver* driver)
- : mCommandMQ(context.getCommandMQ()),
- mReplyMQ(context.getReplyMQ()),
- mDataMQ(context.getDataMQ()),
- mData(context.getBufferSizeBytes()),
- mDriver(driver) {}
- StreamContext::CommandMQ* getCommandMQ() const { return mCommandMQ; }
- StreamContext::ReplyMQ* getReplyMQ() const { return mReplyMQ; }
- StreamLogicDriver* getDriver() const { return mDriver; }
-
- std::string init() override { return ""; }
-
- StreamContext::CommandMQ* mCommandMQ;
- StreamContext::ReplyMQ* mReplyMQ;
- StreamContext::DataMQ* mDataMQ;
- std::vector<int8_t> mData;
- StreamLogicDriver* const mDriver;
-};
-
-class StreamReaderLogic : public StreamCommonLogic {
- public:
- StreamReaderLogic(const StreamContext& context, StreamLogicDriver* driver)
- : StreamCommonLogic(context, driver) {}
-
- protected:
- Status cycle() override {
- if (getDriver()->done()) {
- return Status::EXIT;
- }
- StreamDescriptor::Command command = getDriver()->getNextCommand(mData.size());
- if (!mCommandMQ->writeBlocking(&command, 1)) {
- LOG(ERROR) << __func__ << ": writing of command into MQ failed";
- return Status::ABORT;
- }
- StreamDescriptor::Reply reply{};
- if (!mReplyMQ->readBlocking(&reply, 1)) {
- LOG(ERROR) << __func__ << ": reading of reply from MQ failed";
- return Status::ABORT;
- }
- if (getDriver()->interceptRawReply(reply)) {
- return Status::CONTINUE;
- }
- if (reply.status != STATUS_OK) {
- LOG(ERROR) << __func__ << ": received error status: " << statusToString(reply.status);
- return Status::ABORT;
- }
- if (reply.fmqByteCount < 0 ||
- (command.getTag() == StreamDescriptor::Command::Tag::burst &&
- reply.fmqByteCount > command.get<StreamDescriptor::Command::Tag::burst>())) {
- LOG(ERROR) << __func__
- << ": received invalid byte count in the reply: " << reply.fmqByteCount;
- return Status::ABORT;
- }
- if (static_cast<size_t>(reply.fmqByteCount) != mDataMQ->availableToRead()) {
- LOG(ERROR) << __func__
- << ": the byte count in the reply is not the same as the amount of "
- << "data available in the MQ: " << reply.fmqByteCount
- << " != " << mDataMQ->availableToRead();
- }
- if (reply.latencyMs < 0 && reply.latencyMs != StreamDescriptor::LATENCY_UNKNOWN) {
- LOG(ERROR) << __func__ << ": received invalid latency value: " << reply.latencyMs;
- return Status::ABORT;
- }
- if (reply.xrunFrames < 0) {
- LOG(ERROR) << __func__ << ": received invalid xrunFrames value: " << reply.xrunFrames;
- return Status::ABORT;
- }
- if (std::find(enum_range<StreamDescriptor::State>().begin(),
- enum_range<StreamDescriptor::State>().end(),
- reply.state) == enum_range<StreamDescriptor::State>().end()) {
- LOG(ERROR) << __func__ << ": received invalid stream state: " << toString(reply.state);
- return Status::ABORT;
- }
- const bool acceptedReply = getDriver()->processValidReply(reply);
- if (const size_t readCount = mDataMQ->availableToRead(); readCount > 0) {
- std::vector<int8_t> data(readCount);
- if (mDataMQ->read(data.data(), readCount)) {
- memcpy(mData.data(), data.data(), std::min(mData.size(), data.size()));
- goto checkAcceptedReply;
- }
- LOG(ERROR) << __func__ << ": reading of " << readCount << " data bytes from MQ failed";
- return Status::ABORT;
- } // readCount == 0
- checkAcceptedReply:
- if (acceptedReply) {
- return Status::CONTINUE;
- }
- LOG(ERROR) << __func__ << ": unacceptable reply: " << reply.toString();
- return Status::ABORT;
- }
-};
-using StreamReader = StreamWorker<StreamReaderLogic>;
-
-class StreamWriterLogic : public StreamCommonLogic {
- public:
- StreamWriterLogic(const StreamContext& context, StreamLogicDriver* driver)
- : StreamCommonLogic(context, driver) {}
-
- protected:
- Status cycle() override {
- if (getDriver()->done()) {
- return Status::EXIT;
- }
- int actualSize = 0;
- StreamDescriptor::Command command = getDriver()->getNextCommand(mData.size(), &actualSize);
- if (actualSize != 0 && !mDataMQ->write(mData.data(), mData.size())) {
- LOG(ERROR) << __func__ << ": writing of " << mData.size() << " bytes to MQ failed";
- return Status::ABORT;
- }
- if (!mCommandMQ->writeBlocking(&command, 1)) {
- LOG(ERROR) << __func__ << ": writing of command into MQ failed";
- return Status::ABORT;
- }
- StreamDescriptor::Reply reply{};
- if (!mReplyMQ->readBlocking(&reply, 1)) {
- LOG(ERROR) << __func__ << ": reading of reply from MQ failed";
- return Status::ABORT;
- }
- if (getDriver()->interceptRawReply(reply)) {
- return Status::CONTINUE;
- }
- if (reply.status != STATUS_OK) {
- LOG(ERROR) << __func__ << ": received error status: " << statusToString(reply.status);
- return Status::ABORT;
- }
- if (reply.fmqByteCount < 0 ||
- (command.getTag() == StreamDescriptor::Command::Tag::burst &&
- reply.fmqByteCount > command.get<StreamDescriptor::Command::Tag::burst>())) {
- LOG(ERROR) << __func__
- << ": received invalid byte count in the reply: " << reply.fmqByteCount;
- return Status::ABORT;
- }
- if (mDataMQ->availableToWrite() != mDataMQ->getQuantumCount()) {
- LOG(ERROR) << __func__ << ": the HAL module did not consume all data from the data MQ: "
- << "available to write " << mDataMQ->availableToWrite()
- << ", total size: " << mDataMQ->getQuantumCount();
- return Status::ABORT;
- }
- if (reply.latencyMs < 0 && reply.latencyMs != StreamDescriptor::LATENCY_UNKNOWN) {
- LOG(ERROR) << __func__ << ": received invalid latency value: " << reply.latencyMs;
- return Status::ABORT;
- }
- if (reply.xrunFrames < 0) {
- LOG(ERROR) << __func__ << ": received invalid xrunFrames value: " << reply.xrunFrames;
- return Status::ABORT;
- }
- if (std::find(enum_range<StreamDescriptor::State>().begin(),
- enum_range<StreamDescriptor::State>().end(),
- reply.state) == enum_range<StreamDescriptor::State>().end()) {
- LOG(ERROR) << __func__ << ": received invalid stream state: " << toString(reply.state);
- return Status::ABORT;
- }
- if (getDriver()->processValidReply(reply)) {
- return Status::CONTINUE;
- }
- LOG(ERROR) << __func__ << ": unacceptable reply: " << reply.toString();
- return Status::ABORT;
- }
-};
-using StreamWriter = StreamWorker<StreamWriterLogic>;
-
-template <typename T>
-struct IOTraits {
- static constexpr bool is_input = std::is_same_v<T, IStreamIn>;
- using Worker = std::conditional_t<is_input, StreamReader, StreamWriter>;
-};
-
-template <typename Stream>
-class WithStream {
- public:
- WithStream() {}
- explicit WithStream(const AudioPortConfig& portConfig) : mPortConfig(portConfig) {}
- WithStream(const WithStream&) = delete;
- WithStream& operator=(const WithStream&) = delete;
- ~WithStream() {
- if (mStream != nullptr) {
- mContext.reset();
- EXPECT_IS_OK(mStream->close()) << "port config id " << getPortId();
- }
- }
- void SetUpPortConfig(IModule* module) { ASSERT_NO_FATAL_FAILURE(mPortConfig.SetUp(module)); }
- ScopedAStatus SetUpNoChecks(IModule* module, long bufferSizeFrames) {
- return SetUpNoChecks(module, mPortConfig.get(), bufferSizeFrames);
- }
- ScopedAStatus SetUpNoChecks(IModule* module, const AudioPortConfig& portConfig,
- long bufferSizeFrames);
- void SetUp(IModule* module, long bufferSizeFrames) {
- ASSERT_NO_FATAL_FAILURE(SetUpPortConfig(module));
- ASSERT_IS_OK(SetUpNoChecks(module, bufferSizeFrames)) << "port config id " << getPortId();
- ASSERT_NE(nullptr, mStream) << "port config id " << getPortId();
- EXPECT_GE(mDescriptor.bufferSizeFrames, bufferSizeFrames)
- << "actual buffer size must be no less than requested";
- mContext.emplace(mDescriptor);
- ASSERT_NO_FATAL_FAILURE(mContext.value().checkIsValid());
- }
- Stream* get() const { return mStream.get(); }
- const StreamContext* getContext() const { return mContext ? &(mContext.value()) : nullptr; }
- std::shared_ptr<Stream> getSharedPointer() const { return mStream; }
- const AudioPortConfig& getPortConfig() const { return mPortConfig.get(); }
- int32_t getPortId() const { return mPortConfig.getId(); }
-
- private:
- WithAudioPortConfig mPortConfig;
- std::shared_ptr<Stream> mStream;
- StreamDescriptor mDescriptor;
- std::optional<StreamContext> mContext;
-};
-
-SinkMetadata GenerateSinkMetadata(const AudioPortConfig& portConfig) {
- RecordTrackMetadata trackMeta;
- trackMeta.source = AudioSource::MIC;
- trackMeta.gain = 1.0;
- trackMeta.channelMask = portConfig.channelMask.value();
- SinkMetadata metadata;
- metadata.tracks.push_back(trackMeta);
- return metadata;
-}
-
-template <>
-ScopedAStatus WithStream<IStreamIn>::SetUpNoChecks(IModule* module,
- const AudioPortConfig& portConfig,
- long bufferSizeFrames) {
- aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments args;
- args.portConfigId = portConfig.id;
- args.sinkMetadata = GenerateSinkMetadata(portConfig);
- args.bufferSizeFrames = bufferSizeFrames;
- aidl::android::hardware::audio::core::IModule::OpenInputStreamReturn ret;
- ScopedAStatus status = module->openInputStream(args, &ret);
- if (status.isOk()) {
- mStream = std::move(ret.stream);
- mDescriptor = std::move(ret.desc);
- }
- return status;
-}
-
-SourceMetadata GenerateSourceMetadata(const AudioPortConfig& portConfig) {
- PlaybackTrackMetadata trackMeta;
- trackMeta.usage = AudioUsage::MEDIA;
- trackMeta.contentType = AudioContentType::MUSIC;
- trackMeta.gain = 1.0;
- trackMeta.channelMask = portConfig.channelMask.value();
- SourceMetadata metadata;
- metadata.tracks.push_back(trackMeta);
- return metadata;
-}
-
-template <>
-ScopedAStatus WithStream<IStreamOut>::SetUpNoChecks(IModule* module,
- const AudioPortConfig& portConfig,
- long bufferSizeFrames) {
- aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
- args.portConfigId = portConfig.id;
- args.sourceMetadata = GenerateSourceMetadata(portConfig);
- args.offloadInfo = ModuleConfig::generateOffloadInfoIfNeeded(portConfig);
- args.bufferSizeFrames = bufferSizeFrames;
- aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
- ScopedAStatus status = module->openOutputStream(args, &ret);
- if (status.isOk()) {
- mStream = std::move(ret.stream);
- mDescriptor = std::move(ret.desc);
- }
- return status;
-}
-
-class WithAudioPatch {
- public:
- WithAudioPatch() {}
- WithAudioPatch(const AudioPortConfig& srcPortConfig, const AudioPortConfig& sinkPortConfig)
- : mSrcPortConfig(srcPortConfig), mSinkPortConfig(sinkPortConfig) {}
- WithAudioPatch(bool sinkIsCfg1, const AudioPortConfig& portConfig1,
- const AudioPortConfig& portConfig2)
- : mSrcPortConfig(sinkIsCfg1 ? portConfig2 : portConfig1),
- mSinkPortConfig(sinkIsCfg1 ? portConfig1 : portConfig2) {}
- WithAudioPatch(const WithAudioPatch&) = delete;
- WithAudioPatch& operator=(const WithAudioPatch&) = delete;
- ~WithAudioPatch() {
- if (mModule != nullptr && mPatch.id != 0) {
- EXPECT_IS_OK(mModule->resetAudioPatch(mPatch.id)) << "patch id " << getId();
- }
- }
- void SetUpPortConfigs(IModule* module) {
- ASSERT_NO_FATAL_FAILURE(mSrcPortConfig.SetUp(module));
- ASSERT_NO_FATAL_FAILURE(mSinkPortConfig.SetUp(module));
- }
- ScopedAStatus SetUpNoChecks(IModule* module) {
- mModule = module;
- mPatch.sourcePortConfigIds = std::vector<int32_t>{mSrcPortConfig.getId()};
- mPatch.sinkPortConfigIds = std::vector<int32_t>{mSinkPortConfig.getId()};
- return mModule->setAudioPatch(mPatch, &mPatch);
- }
- void SetUp(IModule* module) {
- ASSERT_NO_FATAL_FAILURE(SetUpPortConfigs(module));
- ASSERT_IS_OK(SetUpNoChecks(module)) << "source port config id " << mSrcPortConfig.getId()
- << "; sink port config id " << mSinkPortConfig.getId();
- EXPECT_GT(mPatch.minimumStreamBufferSizeFrames, 0) << "patch id " << getId();
- for (auto latencyMs : mPatch.latenciesMs) {
- EXPECT_GT(latencyMs, 0) << "patch id " << getId();
- }
- }
- int32_t getId() const { return mPatch.id; }
- const AudioPatch& get() const { return mPatch; }
- const AudioPortConfig& getSinkPortConfig() const { return mSinkPortConfig.get(); }
- const AudioPortConfig& getSrcPortConfig() const { return mSrcPortConfig.get(); }
- const AudioPortConfig& getPortConfig(bool getSink) const {
- return getSink ? getSinkPortConfig() : getSrcPortConfig();
- }
-
- private:
- WithAudioPortConfig mSrcPortConfig;
- WithAudioPortConfig mSinkPortConfig;
- IModule* mModule = nullptr;
- AudioPatch mPatch;
-};
-
-TEST_P(AudioCoreModule, Published) {
- // SetUp must complete with no failures.
-}
-
-TEST_P(AudioCoreModule, CanBeRestarted) {
- ASSERT_NO_FATAL_FAILURE(RestartService());
-}
-
-TEST_P(AudioCoreModule, PortIdsAreUnique) {
- std::set<int32_t> portIds;
- ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
-}
-
-TEST_P(AudioCoreModule, GetAudioPortsIsStable) {
- std::vector<AudioPort> ports1;
- ASSERT_IS_OK(module->getAudioPorts(&ports1));
- std::vector<AudioPort> ports2;
- ASSERT_IS_OK(module->getAudioPorts(&ports2));
- ASSERT_EQ(ports1.size(), ports2.size())
- << "Sizes of audio port arrays do not match across consequent calls to getAudioPorts";
- std::sort(ports1.begin(), ports1.end());
- std::sort(ports2.begin(), ports2.end());
- EXPECT_EQ(ports1, ports2);
-}
-
-TEST_P(AudioCoreModule, GetAudioRoutesIsStable) {
- std::vector<AudioRoute> routes1;
- ASSERT_IS_OK(module->getAudioRoutes(&routes1));
- std::vector<AudioRoute> routes2;
- ASSERT_IS_OK(module->getAudioRoutes(&routes2));
- ASSERT_EQ(routes1.size(), routes2.size())
- << "Sizes of audio route arrays do not match across consequent calls to getAudioRoutes";
- std::sort(routes1.begin(), routes1.end());
- std::sort(routes2.begin(), routes2.end());
- EXPECT_EQ(routes1, routes2);
-}
-
-TEST_P(AudioCoreModule, GetAudioRoutesAreValid) {
- std::vector<AudioRoute> routes;
- ASSERT_IS_OK(module->getAudioRoutes(&routes));
- for (const auto& route : routes) {
- std::set<int32_t> sources(route.sourcePortIds.begin(), route.sourcePortIds.end());
- EXPECT_NE(0UL, sources.size())
- << "empty audio port sinks in the audio route: " << route.toString();
- EXPECT_EQ(sources.size(), route.sourcePortIds.size())
- << "IDs of audio port sinks are not unique in the audio route: "
- << route.toString();
- }
-}
-
-TEST_P(AudioCoreModule, GetAudioRoutesPortIdsAreValid) {
- std::set<int32_t> portIds;
- ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
- std::vector<AudioRoute> routes;
- ASSERT_IS_OK(module->getAudioRoutes(&routes));
- for (const auto& route : routes) {
- EXPECT_EQ(1UL, portIds.count(route.sinkPortId))
- << route.sinkPortId << " sink port id is unknown";
- for (const auto& source : route.sourcePortIds) {
- EXPECT_EQ(1UL, portIds.count(source)) << source << " source port id is unknown";
- }
- }
-}
-
-TEST_P(AudioCoreModule, GetAudioRoutesForAudioPort) {
- std::set<int32_t> portIds;
- ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
- if (portIds.empty()) {
- GTEST_SKIP() << "No ports in the module.";
- }
- for (const auto portId : portIds) {
- std::vector<AudioRoute> routes;
- EXPECT_IS_OK(module->getAudioRoutesForAudioPort(portId, &routes));
- for (const auto& r : routes) {
- if (r.sinkPortId != portId) {
- const auto& srcs = r.sourcePortIds;
- EXPECT_TRUE(std::find(srcs.begin(), srcs.end(), portId) != srcs.end())
- << " port ID " << portId << " does not used by the route " << r.toString();
- }
- }
- }
- for (const auto portId : GetNonExistentIds(portIds)) {
- std::vector<AudioRoute> routes;
- EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->getAudioRoutesForAudioPort(portId, &routes))
- << "port ID " << portId;
- }
-}
-
-TEST_P(AudioCoreModule, CheckDevicePorts) {
- std::vector<AudioPort> ports;
- ASSERT_IS_OK(module->getAudioPorts(&ports));
- std::optional<int32_t> defaultOutput, defaultInput;
- std::set<AudioDevice> inputs, outputs;
- const int defaultDeviceFlag = 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE;
- for (const auto& port : ports) {
- if (port.ext.getTag() != AudioPortExt::Tag::device) continue;
- const auto& devicePort = port.ext.get<AudioPortExt::Tag::device>();
- EXPECT_NE(AudioDeviceType::NONE, devicePort.device.type.type);
- EXPECT_NE(AudioDeviceType::IN_DEFAULT, devicePort.device.type.type);
- EXPECT_NE(AudioDeviceType::OUT_DEFAULT, devicePort.device.type.type);
- if (devicePort.device.type.type > AudioDeviceType::IN_DEFAULT &&
- devicePort.device.type.type < AudioDeviceType::OUT_DEFAULT) {
- EXPECT_EQ(AudioIoFlags::Tag::input, port.flags.getTag());
- } else if (devicePort.device.type.type > AudioDeviceType::OUT_DEFAULT) {
- EXPECT_EQ(AudioIoFlags::Tag::output, port.flags.getTag());
- }
- EXPECT_FALSE((devicePort.flags & defaultDeviceFlag) != 0 &&
- !devicePort.device.type.connection.empty())
- << "Device port " << port.id
- << " must be permanently attached to be set as default";
- if ((devicePort.flags & defaultDeviceFlag) != 0) {
- if (port.flags.getTag() == AudioIoFlags::Tag::output) {
- EXPECT_FALSE(defaultOutput.has_value())
- << "At least two output device ports are declared as default: "
- << defaultOutput.value() << " and " << port.id;
- defaultOutput = port.id;
- EXPECT_EQ(0UL, outputs.count(devicePort.device))
- << "Non-unique output device: " << devicePort.device.toString();
- outputs.insert(devicePort.device);
- } else if (port.flags.getTag() == AudioIoFlags::Tag::input) {
- EXPECT_FALSE(defaultInput.has_value())
- << "At least two input device ports are declared as default: "
- << defaultInput.value() << " and " << port.id;
- defaultInput = port.id;
- EXPECT_EQ(0UL, inputs.count(devicePort.device))
- << "Non-unique input device: " << devicePort.device.toString();
- inputs.insert(devicePort.device);
- } else {
- FAIL() << "Invalid AudioIoFlags Tag: " << toString(port.flags.getTag());
- }
- }
- }
-}
-
-TEST_P(AudioCoreModule, CheckMixPorts) {
- std::vector<AudioPort> ports;
- ASSERT_IS_OK(module->getAudioPorts(&ports));
- std::optional<int32_t> primaryMixPort;
- for (const auto& port : ports) {
- if (port.ext.getTag() != AudioPortExt::Tag::mix) continue;
- const auto& mixPort = port.ext.get<AudioPortExt::Tag::mix>();
- if (port.flags.getTag() == AudioIoFlags::Tag::output &&
- isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::output>(),
- AudioOutputFlags::PRIMARY)) {
- EXPECT_FALSE(primaryMixPort.has_value())
- << "At least two mix ports have PRIMARY flag set: " << primaryMixPort.value()
- << " and " << port.id;
- primaryMixPort = port.id;
- EXPECT_EQ(1, mixPort.maxOpenStreamCount)
- << "Primary mix port " << port.id << " can not have maxOpenStreamCount "
- << mixPort.maxOpenStreamCount;
- }
- }
-}
-
-TEST_P(AudioCoreModule, GetAudioPort) {
- std::set<int32_t> portIds;
- ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
- if (portIds.empty()) {
- GTEST_SKIP() << "No ports in the module.";
- }
- for (const auto portId : portIds) {
- AudioPort port;
- EXPECT_IS_OK(module->getAudioPort(portId, &port));
- EXPECT_EQ(portId, port.id);
- }
- for (const auto portId : GetNonExistentIds(portIds)) {
- AudioPort port;
- EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->getAudioPort(portId, &port))
- << "port ID " << portId;
- }
-}
-
-TEST_P(AudioCoreModule, SetUpModuleConfig) {
- ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
- // Send the module config to logcat to facilitate failures investigation.
- LOG(INFO) << "SetUpModuleConfig: " << moduleConfig->toString();
-}
-
-// Verify that HAL module reports for a connected device port at least one non-dynamic profile,
-// that is, a profile with actual supported configuration.
-// Note: This test relies on simulation of external device connections by the HAL module.
-TEST_P(AudioCoreModule, GetAudioPortWithExternalDevices) {
- ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
- std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
- if (ports.empty()) {
- GTEST_SKIP() << "No external devices in the module.";
- }
- for (const auto& port : ports) {
- AudioPort portWithData = port;
- portWithData.ext.get<AudioPortExt::Tag::device>().device.address =
- GenerateUniqueDeviceAddress();
- WithDevicePortConnectedState portConnected(portWithData);
- ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
- const int32_t connectedPortId = portConnected.getId();
- ASSERT_NE(portWithData.id, connectedPortId);
- ASSERT_EQ(portWithData.ext.getTag(), portConnected.get().ext.getTag());
- EXPECT_EQ(portWithData.ext.get<AudioPortExt::Tag::device>().device,
- portConnected.get().ext.get<AudioPortExt::Tag::device>().device);
- // Verify that 'getAudioPort' and 'getAudioPorts' return the same connected port.
- AudioPort connectedPort;
- EXPECT_IS_OK(module->getAudioPort(connectedPortId, &connectedPort))
- << "port ID " << connectedPortId;
- EXPECT_EQ(portConnected.get(), connectedPort);
- const auto& portProfiles = connectedPort.profiles;
- EXPECT_NE(0UL, portProfiles.size())
- << "Connected port has no profiles: " << connectedPort.toString();
- const auto dynamicProfileIt =
- std::find_if(portProfiles.begin(), portProfiles.end(), [](const auto& profile) {
- return profile.format.type == AudioFormatType::DEFAULT;
- });
- EXPECT_EQ(portProfiles.end(), dynamicProfileIt) << "Connected port contains dynamic "
- << "profiles: " << connectedPort.toString();
-
- std::vector<AudioPort> allPorts;
- ASSERT_IS_OK(module->getAudioPorts(&allPorts));
- const auto allPortsIt = findById(allPorts, connectedPortId);
- EXPECT_NE(allPorts.end(), allPortsIt);
- if (allPortsIt != allPorts.end()) {
- EXPECT_EQ(portConnected.get(), *allPortsIt);
- }
- }
-}
-
-TEST_P(AudioCoreModule, OpenStreamInvalidPortConfigId) {
- std::set<int32_t> portConfigIds;
- ASSERT_NO_FATAL_FAILURE(GetAllPortConfigIds(&portConfigIds));
- for (const auto portConfigId : GetNonExistentIds(portConfigIds)) {
- {
- aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments args;
- args.portConfigId = portConfigId;
- args.bufferSizeFrames = kDefaultBufferSizeFrames;
- aidl::android::hardware::audio::core::IModule::OpenInputStreamReturn ret;
- EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->openInputStream(args, &ret))
- << "port config ID " << portConfigId;
- EXPECT_EQ(nullptr, ret.stream);
- }
- {
- aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
- args.portConfigId = portConfigId;
- args.bufferSizeFrames = kDefaultBufferSizeFrames;
- aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
- EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->openOutputStream(args, &ret))
- << "port config ID " << portConfigId;
- EXPECT_EQ(nullptr, ret.stream);
- }
- }
-}
-
-TEST_P(AudioCoreModule, PortConfigIdsAreUnique) {
- std::set<int32_t> portConfigIds;
- ASSERT_NO_FATAL_FAILURE(GetAllPortConfigIds(&portConfigIds));
-}
-
-TEST_P(AudioCoreModule, PortConfigPortIdsAreValid) {
- std::set<int32_t> portIds;
- ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
- std::vector<AudioPortConfig> portConfigs;
- ASSERT_IS_OK(module->getAudioPortConfigs(&portConfigs));
- for (const auto& config : portConfigs) {
- EXPECT_EQ(1UL, portIds.count(config.portId))
- << config.portId << " port id is unknown, config id " << config.id;
- }
-}
-
-TEST_P(AudioCoreModule, ResetAudioPortConfigInvalidId) {
- std::set<int32_t> portConfigIds;
- ASSERT_NO_FATAL_FAILURE(GetAllPortConfigIds(&portConfigIds));
- for (const auto portConfigId : GetNonExistentIds(portConfigIds)) {
- EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->resetAudioPortConfig(portConfigId))
- << "port config ID " << portConfigId;
- }
-}
-
-// Verify that for the audio port configs provided by the HAL after init, resetting
-// the config does not delete it, but brings it back to the initial config.
-TEST_P(AudioCoreModule, ResetAudioPortConfigToInitialValue) {
- std::vector<AudioPortConfig> portConfigsBefore;
- ASSERT_IS_OK(module->getAudioPortConfigs(&portConfigsBefore));
- // TODO: Change port configs according to port profiles.
- for (const auto& c : portConfigsBefore) {
- EXPECT_IS_OK(module->resetAudioPortConfig(c.id)) << "port config ID " << c.id;
- }
- std::vector<AudioPortConfig> portConfigsAfter;
- ASSERT_IS_OK(module->getAudioPortConfigs(&portConfigsAfter));
- for (const auto& c : portConfigsBefore) {
- auto afterIt = findById<AudioPortConfig>(portConfigsAfter, c.id);
- EXPECT_NE(portConfigsAfter.end(), afterIt)
- << " port config ID " << c.id << " was removed by reset";
- if (afterIt != portConfigsAfter.end()) {
- EXPECT_EQ(c, *afterIt);
- }
- }
-}
-
-TEST_P(AudioCoreModule, SetAudioPortConfigSuggestedConfig) {
- ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
- auto srcMixPort = moduleConfig->getSourceMixPortForAttachedDevice();
- if (!srcMixPort.has_value()) {
- GTEST_SKIP() << "No mix port for attached output devices";
- }
- AudioPortConfig portConfig;
- AudioPortConfig suggestedConfig;
- portConfig.portId = srcMixPort.value().id;
- {
- bool applied = true;
- ASSERT_IS_OK(module->setAudioPortConfig(portConfig, &suggestedConfig, &applied))
- << "Config: " << portConfig.toString();
- EXPECT_FALSE(applied);
- }
- EXPECT_EQ(0, suggestedConfig.id);
- EXPECT_TRUE(suggestedConfig.sampleRate.has_value());
- EXPECT_TRUE(suggestedConfig.channelMask.has_value());
- EXPECT_TRUE(suggestedConfig.format.has_value());
- EXPECT_TRUE(suggestedConfig.flags.has_value());
- WithAudioPortConfig applied(suggestedConfig);
- ASSERT_NO_FATAL_FAILURE(applied.SetUp(module.get()));
- const AudioPortConfig& appliedConfig = applied.get();
- EXPECT_NE(0, appliedConfig.id);
- EXPECT_TRUE(appliedConfig.sampleRate.has_value());
- EXPECT_EQ(suggestedConfig.sampleRate.value(), appliedConfig.sampleRate.value());
- EXPECT_TRUE(appliedConfig.channelMask.has_value());
- EXPECT_EQ(suggestedConfig.channelMask.value(), appliedConfig.channelMask.value());
- EXPECT_TRUE(appliedConfig.format.has_value());
- EXPECT_EQ(suggestedConfig.format.value(), appliedConfig.format.value());
- EXPECT_TRUE(appliedConfig.flags.has_value());
- EXPECT_EQ(suggestedConfig.flags.value(), appliedConfig.flags.value());
-}
-
-TEST_P(AudioCoreModule, SetAllAttachedDevicePortConfigs) {
- ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
- ASSERT_NO_FATAL_FAILURE(ApplyEveryConfig(moduleConfig->getPortConfigsForAttachedDevicePorts()));
-}
-
-// Note: This test relies on simulation of external device connections by the HAL module.
-TEST_P(AudioCoreModule, SetAllExternalDevicePortConfigs) {
- ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
- std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
- if (ports.empty()) {
- GTEST_SKIP() << "No external devices in the module.";
- }
- for (const auto& port : ports) {
- WithDevicePortConnectedState portConnected(port, GenerateUniqueDeviceAddress());
- ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
- ASSERT_NO_FATAL_FAILURE(
- ApplyEveryConfig(moduleConfig->getPortConfigsForDevicePort(portConnected.get())));
- }
-}
-
-TEST_P(AudioCoreModule, SetAllStaticAudioPortConfigs) {
- ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
- ASSERT_NO_FATAL_FAILURE(ApplyEveryConfig(moduleConfig->getPortConfigsForMixPorts()));
-}
-
-TEST_P(AudioCoreModule, SetAudioPortConfigInvalidPortId) {
- std::set<int32_t> portIds;
- ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
- for (const auto portId : GetNonExistentIds(portIds)) {
- AudioPortConfig portConfig, suggestedConfig;
- bool applied;
- portConfig.portId = portId;
- EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
- module->setAudioPortConfig(portConfig, &suggestedConfig, &applied))
- << "port ID " << portId;
- EXPECT_FALSE(suggestedConfig.format.has_value());
- EXPECT_FALSE(suggestedConfig.channelMask.has_value());
- EXPECT_FALSE(suggestedConfig.sampleRate.has_value());
- }
-}
-
-TEST_P(AudioCoreModule, SetAudioPortConfigInvalidPortConfigId) {
- std::set<int32_t> portConfigIds;
- ASSERT_NO_FATAL_FAILURE(GetAllPortConfigIds(&portConfigIds));
- for (const auto portConfigId : GetNonExistentIds(portConfigIds)) {
- AudioPortConfig portConfig, suggestedConfig;
- bool applied;
- portConfig.id = portConfigId;
- EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
- module->setAudioPortConfig(portConfig, &suggestedConfig, &applied))
- << "port config ID " << portConfigId;
- EXPECT_FALSE(suggestedConfig.format.has_value());
- EXPECT_FALSE(suggestedConfig.channelMask.has_value());
- EXPECT_FALSE(suggestedConfig.sampleRate.has_value());
- }
-}
-
-TEST_P(AudioCoreModule, TryConnectMissingDevice) {
- ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
- std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
- if (ports.empty()) {
- GTEST_SKIP() << "No external devices in the module.";
- }
- AudioPort ignored;
- WithDebugFlags doNotSimulateConnections = WithDebugFlags::createNested(debug);
- doNotSimulateConnections.flags().simulateDeviceConnections = false;
- ASSERT_NO_FATAL_FAILURE(doNotSimulateConnections.SetUp(module.get()));
- for (const auto& port : ports) {
- AudioPort portWithData = port;
- portWithData.ext.get<AudioPortExt::Tag::device>().device.address =
- GenerateUniqueDeviceAddress();
- EXPECT_STATUS(EX_ILLEGAL_STATE, module->connectExternalDevice(portWithData, &ignored))
- << "static port " << portWithData.toString();
- }
-}
-
-TEST_P(AudioCoreModule, TryChangingConnectionSimulationMidway) {
- ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
- std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
- if (ports.empty()) {
- GTEST_SKIP() << "No external devices in the module.";
- }
- WithDevicePortConnectedState portConnected(*ports.begin(), GenerateUniqueDeviceAddress());
- ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
- ModuleDebug midwayDebugChange = debug.flags();
- midwayDebugChange.simulateDeviceConnections = false;
- EXPECT_STATUS(EX_ILLEGAL_STATE, module->setModuleDebug(midwayDebugChange))
- << "when trying to disable connections simulation while having a connected device";
-}
-
-TEST_P(AudioCoreModule, ConnectDisconnectExternalDeviceInvalidPorts) {
- AudioPort ignored;
- std::set<int32_t> portIds;
- ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
- for (const auto portId : GetNonExistentIds(portIds)) {
- AudioPort invalidPort;
- invalidPort.id = portId;
- EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->connectExternalDevice(invalidPort, &ignored))
- << "port ID " << portId << ", when setting CONNECTED state";
- EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->disconnectExternalDevice(portId))
- << "port ID " << portId << ", when setting DISCONNECTED state";
- }
-
- std::vector<AudioPort> ports;
- ASSERT_IS_OK(module->getAudioPorts(&ports));
- for (const auto& port : ports) {
- if (port.ext.getTag() != AudioPortExt::Tag::device) {
- EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->connectExternalDevice(port, &ignored))
- << "non-device port ID " << port.id << " when setting CONNECTED state";
- EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->disconnectExternalDevice(port.id))
- << "non-device port ID " << port.id << " when setting DISCONNECTED state";
- } else {
- const auto& devicePort = port.ext.get<AudioPortExt::Tag::device>();
- if (devicePort.device.type.connection.empty()) {
- EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->connectExternalDevice(port, &ignored))
- << "for a permanently attached device port ID " << port.id
- << " when setting CONNECTED state";
- EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->disconnectExternalDevice(port.id))
- << "for a permanently attached device port ID " << port.id
- << " when setting DISCONNECTED state";
- }
- }
- }
-}
-
-// Note: This test relies on simulation of external device connections by the HAL module.
-TEST_P(AudioCoreModule, ConnectDisconnectExternalDeviceTwice) {
- ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
- AudioPort ignored;
- std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
- if (ports.empty()) {
- GTEST_SKIP() << "No external devices in the module.";
- }
- for (const auto& port : ports) {
- EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->disconnectExternalDevice(port.id))
- << "when disconnecting already disconnected device port ID " << port.id;
- AudioPort portWithData = port;
- portWithData.ext.get<AudioPortExt::Tag::device>().device.address =
- GenerateUniqueDeviceAddress();
- WithDevicePortConnectedState portConnected(portWithData);
- ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
- EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
- module->connectExternalDevice(portConnected.get(), &ignored))
- << "when trying to connect a connected device port "
- << portConnected.get().toString();
- EXPECT_STATUS(EX_ILLEGAL_STATE, module->connectExternalDevice(portWithData, &ignored))
- << "when connecting again the external device "
- << portWithData.ext.get<AudioPortExt::Tag::device>().device.toString()
- << "; Returned connected port " << ignored.toString() << " for template "
- << portWithData.toString();
- }
-}
-
-// Note: This test relies on simulation of external device connections by the HAL module.
-TEST_P(AudioCoreModule, DisconnectExternalDeviceNonResetPortConfig) {
- ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
- std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
- if (ports.empty()) {
- GTEST_SKIP() << "No external devices in the module.";
- }
- for (const auto& port : ports) {
- WithDevicePortConnectedState portConnected(port, GenerateUniqueDeviceAddress());
- ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
- const auto portConfig = moduleConfig->getSingleConfigForDevicePort(portConnected.get());
- {
- WithAudioPortConfig config(portConfig);
- // Note: if SetUp fails, check the status of 'GetAudioPortWithExternalDevices' test.
- // Our test assumes that 'getAudioPort' returns at least one profile, and it
- // is not a dynamic profile.
- ASSERT_NO_FATAL_FAILURE(config.SetUp(module.get()));
- EXPECT_STATUS(EX_ILLEGAL_STATE, module->disconnectExternalDevice(portConnected.getId()))
- << "when trying to disconnect device port ID " << port.id
- << " with active configuration " << config.getId();
- }
- }
-}
-
-TEST_P(AudioCoreModule, ExternalDevicePortRoutes) {
- ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
- std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
- if (ports.empty()) {
- GTEST_SKIP() << "No external devices in the module.";
- }
- for (const auto& port : ports) {
- std::vector<AudioRoute> routesBefore;
- ASSERT_IS_OK(module->getAudioRoutes(&routesBefore));
-
- int32_t connectedPortId;
- {
- WithDevicePortConnectedState portConnected(port, GenerateUniqueDeviceAddress());
- ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
- connectedPortId = portConnected.getId();
- std::vector<AudioRoute> connectedPortRoutes;
- ASSERT_IS_OK(module->getAudioRoutesForAudioPort(connectedPortId, &connectedPortRoutes))
- << "when retrieving routes for connected port id " << connectedPortId;
- // There must be routes for the port to be useful.
- if (connectedPortRoutes.empty()) {
- std::vector<AudioRoute> allRoutes;
- ASSERT_IS_OK(module->getAudioRoutes(&allRoutes));
- ADD_FAILURE() << " no routes returned for the connected port "
- << portConnected.get().toString()
- << "; all routes: " << android::internal::ToString(allRoutes);
- }
- }
- std::vector<AudioRoute> ignored;
- ASSERT_STATUS(EX_ILLEGAL_ARGUMENT,
- module->getAudioRoutesForAudioPort(connectedPortId, &ignored))
- << "when retrieving routes for released connected port id " << connectedPortId;
-
- std::vector<AudioRoute> routesAfter;
- ASSERT_IS_OK(module->getAudioRoutes(&routesAfter));
- ASSERT_EQ(routesBefore.size(), routesAfter.size())
- << "Sizes of audio route arrays do not match after creating and "
- << "releasing a connected port";
- std::sort(routesBefore.begin(), routesBefore.end());
- std::sort(routesAfter.begin(), routesAfter.end());
- EXPECT_EQ(routesBefore, routesAfter);
- }
-}
-
-TEST_P(AudioCoreModule, MasterMute) {
- bool isSupported = false;
- EXPECT_NO_FATAL_FAILURE(TestAccessors<bool>(module.get(), &IModule::getMasterMute,
- &IModule::setMasterMute, {false, true}, {},
- &isSupported));
- if (!isSupported) {
- GTEST_SKIP() << "Master mute is not supported";
- }
- // TODO: Test that master mute actually mutes output.
-}
-
-TEST_P(AudioCoreModule, MasterVolume) {
- bool isSupported = false;
- EXPECT_NO_FATAL_FAILURE(TestAccessors<float>(
- module.get(), &IModule::getMasterVolume, &IModule::setMasterVolume, {0.0f, 0.5f, 1.0f},
- {-0.1, 1.1, NAN, INFINITY, -INFINITY, 1 + std::numeric_limits<float>::epsilon()},
- &isSupported));
- if (!isSupported) {
- GTEST_SKIP() << "Master volume is not supported";
- }
- // TODO: Test that master volume actually attenuates output.
-}
-
-TEST_P(AudioCoreModule, MicMute) {
- bool isSupported = false;
- EXPECT_NO_FATAL_FAILURE(TestAccessors<bool>(module.get(), &IModule::getMicMute,
- &IModule::setMicMute, {false, true}, {},
- &isSupported));
- if (!isSupported) {
- GTEST_SKIP() << "Mic mute is not supported";
- }
- // TODO: Test that mic mute actually mutes input.
-}
-
-TEST_P(AudioCoreModule, UpdateAudioMode) {
- for (const auto mode : ::ndk::enum_range<AudioMode>()) {
- EXPECT_IS_OK(module->updateAudioMode(mode)) << toString(mode);
- }
- EXPECT_IS_OK(module->updateAudioMode(AudioMode::NORMAL));
-}
-
-TEST_P(AudioCoreModule, UpdateScreenRotation) {
- for (const auto rotation : ::ndk::enum_range<IModule::ScreenRotation>()) {
- EXPECT_IS_OK(module->updateScreenRotation(rotation)) << toString(rotation);
- }
- EXPECT_IS_OK(module->updateScreenRotation(IModule::ScreenRotation::DEG_0));
-}
-
-TEST_P(AudioCoreModule, UpdateScreenState) {
- EXPECT_IS_OK(module->updateScreenState(false));
- EXPECT_IS_OK(module->updateScreenState(true));
-}
-
-class AudioCoreTelephony : public AudioCoreModuleBase, public testing::TestWithParam<std::string> {
- public:
- void SetUp() override {
- ASSERT_NO_FATAL_FAILURE(SetUpImpl(GetParam()));
- ASSERT_IS_OK(module->getTelephony(&telephony));
- }
-
- void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownImpl()); }
-
- std::shared_ptr<ITelephony> telephony;
-};
-
-TEST_P(AudioCoreTelephony, GetSupportedAudioModes) {
- if (telephony == nullptr) {
- GTEST_SKIP() << "Telephony is not supported";
- }
- std::vector<AudioMode> modes1;
- ASSERT_IS_OK(telephony->getSupportedAudioModes(&modes1));
- const std::vector<AudioMode> kMandatoryModes = {AudioMode::NORMAL, AudioMode::RINGTONE,
- AudioMode::IN_CALL,
- AudioMode::IN_COMMUNICATION};
- for (const auto mode : kMandatoryModes) {
- EXPECT_NE(modes1.end(), std::find(modes1.begin(), modes1.end(), mode))
- << "Mandatory mode not supported: " << toString(mode);
- }
- std::vector<AudioMode> modes2;
- ASSERT_IS_OK(telephony->getSupportedAudioModes(&modes2));
- ASSERT_EQ(modes1.size(), modes2.size())
- << "Sizes of audio mode arrays do not match across consequent calls to "
- << "getSupportedAudioModes";
- std::sort(modes1.begin(), modes1.end());
- std::sort(modes2.begin(), modes2.end());
- EXPECT_EQ(modes1, modes2);
-};
-
-TEST_P(AudioCoreTelephony, SwitchAudioMode) {
- if (telephony == nullptr) {
- GTEST_SKIP() << "Telephony is not supported";
- }
- std::vector<AudioMode> supportedModes;
- ASSERT_IS_OK(telephony->getSupportedAudioModes(&supportedModes));
- std::set<AudioMode> unsupportedModes = {
- // Start with all, remove supported ones
- ::ndk::enum_range<AudioMode>().begin(), ::ndk::enum_range<AudioMode>().end()};
- for (const auto mode : supportedModes) {
- EXPECT_IS_OK(telephony->switchAudioMode(mode)) << toString(mode);
- unsupportedModes.erase(mode);
- }
- for (const auto mode : unsupportedModes) {
- EXPECT_STATUS(EX_UNSUPPORTED_OPERATION, telephony->switchAudioMode(mode)) << toString(mode);
- }
-}
-
-class StreamLogicDriverInvalidCommand : public StreamLogicDriver {
- public:
- StreamLogicDriverInvalidCommand(const std::vector<StreamDescriptor::Command>& commands)
- : mCommands(commands) {}
-
- std::string getUnexpectedStatuses() {
- // This method is intended to be called after the worker thread has joined,
- // thus no extra synchronization is needed.
- std::string s;
- if (!mStatuses.empty()) {
- s = std::string("Pairs of (command, actual status): ")
- .append((android::internal::ToString(mStatuses)));
- }
- return s;
- }
-
- bool done() override { return mNextCommand >= mCommands.size(); }
- StreamDescriptor::Command getNextCommand(int, int* actualSize) override {
- if (actualSize != nullptr) *actualSize = 0;
- return mCommands[mNextCommand++];
- }
- bool interceptRawReply(const StreamDescriptor::Reply& reply) override {
- if (reply.status != STATUS_BAD_VALUE) {
- std::string s = mCommands[mNextCommand - 1].toString();
- s.append(", ").append(statusToString(reply.status));
- mStatuses.push_back(std::move(s));
- // If the HAL does not recognize the command as invalid,
- // retrieve the data etc.
- return reply.status != STATUS_OK;
- }
- return true;
- }
- bool processValidReply(const StreamDescriptor::Reply&) override { return true; }
-
- private:
- const std::vector<StreamDescriptor::Command> mCommands;
- size_t mNextCommand = 0;
- std::vector<std::string> mStatuses;
-};
-
-template <typename Stream>
-class AudioStream : public AudioCoreModule {
- public:
- void SetUp() override {
- ASSERT_NO_FATAL_FAILURE(AudioCoreModule::SetUp());
- ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
- }
-
- void CloseTwice() {
- const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
- if (!portConfig.has_value()) {
- GTEST_SKIP() << "No mix port for attached devices";
- }
- std::shared_ptr<Stream> heldStream;
- {
- WithStream<Stream> stream(portConfig.value());
- ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
- heldStream = stream.getSharedPointer();
- }
- EXPECT_STATUS(EX_ILLEGAL_STATE, heldStream->close()) << "when closing the stream twice";
- }
-
- void OpenAllConfigs() {
- const auto allPortConfigs =
- moduleConfig->getPortConfigsForMixPorts(IOTraits<Stream>::is_input);
- for (const auto& portConfig : allPortConfigs) {
- WithStream<Stream> stream(portConfig);
- ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
- }
- }
-
- void OpenInvalidBufferSize() {
- const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
- if (!portConfig.has_value()) {
- GTEST_SKIP() << "No mix port for attached devices";
- }
- WithStream<Stream> stream(portConfig.value());
- ASSERT_NO_FATAL_FAILURE(stream.SetUpPortConfig(module.get()));
- // The buffer size of 1 frame should be impractically small, and thus
- // less than any minimum buffer size suggested by any HAL.
- for (long bufferSize : std::array<long, 4>{-1, 0, 1, std::numeric_limits<long>::max()}) {
- EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, stream.SetUpNoChecks(module.get(), bufferSize))
- << "for the buffer size " << bufferSize;
- EXPECT_EQ(nullptr, stream.get());
- }
- }
-
- void OpenInvalidDirection() {
- // Important! The direction of the port config must be reversed.
- const auto portConfig =
- moduleConfig->getSingleConfigForMixPort(!IOTraits<Stream>::is_input);
- if (!portConfig.has_value()) {
- GTEST_SKIP() << "No mix port for attached devices";
- }
- WithStream<Stream> stream(portConfig.value());
- ASSERT_NO_FATAL_FAILURE(stream.SetUpPortConfig(module.get()));
- EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
- stream.SetUpNoChecks(module.get(), kDefaultBufferSizeFrames))
- << "port config ID " << stream.getPortId();
- EXPECT_EQ(nullptr, stream.get());
- }
-
- void OpenOverMaxCount() {
- constexpr bool isInput = IOTraits<Stream>::is_input;
- auto ports = moduleConfig->getMixPorts(isInput);
- bool hasSingleRun = false;
- for (const auto& port : ports) {
- const size_t maxStreamCount = port.ext.get<AudioPortExt::Tag::mix>().maxOpenStreamCount;
- if (maxStreamCount == 0 ||
- moduleConfig->getAttachedDevicesPortsForMixPort(isInput, port).empty()) {
- // No restrictions or no permanently attached devices.
- continue;
- }
- auto portConfigs = moduleConfig->getPortConfigsForMixPorts(isInput, port);
- if (portConfigs.size() < maxStreamCount + 1) {
- // Not able to open a sufficient number of streams for this port.
- continue;
- }
- hasSingleRun = true;
- std::optional<WithStream<Stream>> streamWraps[maxStreamCount + 1];
- for (size_t i = 0; i <= maxStreamCount; ++i) {
- streamWraps[i].emplace(portConfigs[i]);
- WithStream<Stream>& stream = streamWraps[i].value();
- if (i < maxStreamCount) {
- ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
- } else {
- ASSERT_NO_FATAL_FAILURE(stream.SetUpPortConfig(module.get()));
- EXPECT_STATUS(EX_ILLEGAL_STATE,
- stream.SetUpNoChecks(module.get(), kDefaultBufferSizeFrames))
- << "port config ID " << stream.getPortId() << ", maxOpenStreamCount is "
- << maxStreamCount;
- }
- }
- }
- if (!hasSingleRun) {
- GTEST_SKIP() << "Not enough ports to test max open stream count";
- }
- }
-
- void OpenTwiceSamePortConfig() {
- const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
- if (!portConfig.has_value()) {
- GTEST_SKIP() << "No mix port for attached devices";
- }
- EXPECT_NO_FATAL_FAILURE(OpenTwiceSamePortConfigImpl(portConfig.value()));
- }
-
- void ResetPortConfigWithOpenStream() {
- const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
- if (!portConfig.has_value()) {
- GTEST_SKIP() << "No mix port for attached devices";
- }
- WithStream<Stream> stream(portConfig.value());
- ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
- EXPECT_STATUS(EX_ILLEGAL_STATE, module->resetAudioPortConfig(stream.getPortId()))
- << "port config ID " << stream.getPortId();
- }
-
- void SendInvalidCommand() {
- const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
- if (!portConfig.has_value()) {
- GTEST_SKIP() << "No mix port for attached devices";
- }
- EXPECT_NO_FATAL_FAILURE(SendInvalidCommandImpl(portConfig.value()));
- }
-
- void OpenTwiceSamePortConfigImpl(const AudioPortConfig& portConfig) {
- WithStream<Stream> stream1(portConfig);
- ASSERT_NO_FATAL_FAILURE(stream1.SetUp(module.get(), kDefaultBufferSizeFrames));
- WithStream<Stream> stream2;
- EXPECT_STATUS(EX_ILLEGAL_STATE, stream2.SetUpNoChecks(module.get(), stream1.getPortConfig(),
- kDefaultBufferSizeFrames))
- << "when opening a stream twice for the same port config ID "
- << stream1.getPortId();
- }
-
- void SendInvalidCommandImpl(const AudioPortConfig& portConfig) {
- std::vector<StreamDescriptor::Command> commands = {
- StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::hal_reserved_exit>(
- 0),
- // TODO: For proper testing of input streams, need to put the stream into
- // a state which accepts BURST commands.
- StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::burst>(-1),
- StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::burst>(
- std::numeric_limits<int32_t>::min()),
- };
- WithStream<Stream> stream(portConfig);
- ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
- StreamLogicDriverInvalidCommand driver(commands);
- typename IOTraits<Stream>::Worker worker(*stream.getContext(), &driver);
- ASSERT_TRUE(worker.start());
- worker.join();
- EXPECT_EQ("", driver.getUnexpectedStatuses());
- }
-};
-using AudioStreamIn = AudioStream<IStreamIn>;
-using AudioStreamOut = AudioStream<IStreamOut>;
-
-#define TEST_IN_AND_OUT_STREAM(method_name) \
- TEST_P(AudioStreamIn, method_name) { ASSERT_NO_FATAL_FAILURE(method_name()); } \
- TEST_P(AudioStreamOut, method_name) { ASSERT_NO_FATAL_FAILURE(method_name()); }
-
-TEST_IN_AND_OUT_STREAM(CloseTwice);
-TEST_IN_AND_OUT_STREAM(OpenAllConfigs);
-TEST_IN_AND_OUT_STREAM(OpenInvalidBufferSize);
-TEST_IN_AND_OUT_STREAM(OpenInvalidDirection);
-TEST_IN_AND_OUT_STREAM(OpenOverMaxCount);
-TEST_IN_AND_OUT_STREAM(OpenTwiceSamePortConfig);
-TEST_IN_AND_OUT_STREAM(ResetPortConfigWithOpenStream);
-TEST_IN_AND_OUT_STREAM(SendInvalidCommand);
-
-TEST_P(AudioStreamOut, OpenTwicePrimary) {
- const auto mixPorts = moduleConfig->getMixPorts(false);
- auto primaryPortIt = std::find_if(mixPorts.begin(), mixPorts.end(), [](const AudioPort& port) {
- return port.flags.getTag() == AudioIoFlags::Tag::output &&
- isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::output>(),
- AudioOutputFlags::PRIMARY);
- });
- if (primaryPortIt == mixPorts.end()) {
- GTEST_SKIP() << "No primary mix port";
- }
- if (moduleConfig->getAttachedSinkDevicesPortsForMixPort(*primaryPortIt).empty()) {
- GTEST_SKIP() << "Primary mix port can not be routed to any of attached devices";
- }
- const auto portConfig = moduleConfig->getSingleConfigForMixPort(false, *primaryPortIt);
- ASSERT_TRUE(portConfig.has_value()) << "No profiles specified for the primary mix port";
- EXPECT_NO_FATAL_FAILURE(OpenTwiceSamePortConfigImpl(portConfig.value()));
-}
-
-TEST_P(AudioStreamOut, RequireOffloadInfo) {
- const auto offloadMixPorts =
- moduleConfig->getOffloadMixPorts(true /*attachedOnly*/, true /*singlePort*/);
- if (offloadMixPorts.empty()) {
- GTEST_SKIP()
- << "No mix port for compressed offload that could be routed to attached devices";
- }
- const auto portConfig =
- moduleConfig->getSingleConfigForMixPort(false, *offloadMixPorts.begin());
- ASSERT_TRUE(portConfig.has_value())
- << "No profiles specified for the compressed offload mix port";
- StreamDescriptor descriptor;
- std::shared_ptr<IStreamOut> ignored;
- aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
- args.portConfigId = portConfig.value().id;
- args.sourceMetadata = GenerateSourceMetadata(portConfig.value());
- args.bufferSizeFrames = kDefaultBufferSizeFrames;
- aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
- EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->openOutputStream(args, &ret))
- << "when no offload info is provided for a compressed offload mix port";
-}
-
-using CommandAndState = std::pair<StreamDescriptor::Command, StreamDescriptor::State>;
-
-class StreamLogicDefaultDriver : public StreamLogicDriver {
- public:
- explicit StreamLogicDefaultDriver(const std::vector<CommandAndState>& commands)
- : mCommands(commands) {}
-
- // The three methods below is intended to be called after the worker
- // thread has joined, thus no extra synchronization is needed.
- bool hasObservablePositionIncrease() const { return mObservablePositionIncrease; }
- bool hasRetrogradeObservablePosition() const { return mRetrogradeObservablePosition; }
- std::string getUnexpectedStateTransition() const { return mUnexpectedTransition; }
-
- bool done() override { return mNextCommand >= mCommands.size(); }
- StreamDescriptor::Command getNextCommand(int maxDataSize, int* actualSize) override {
- auto command = mCommands[mNextCommand++].first;
- if (command.getTag() == StreamDescriptor::Command::Tag::burst) {
- if (actualSize != nullptr) {
- // In the output scenario, reduce slightly the fmqByteCount to verify
- // that the HAL module always consumes all data from the MQ.
- if (maxDataSize > 1) maxDataSize--;
- *actualSize = maxDataSize;
- }
- command.set<StreamDescriptor::Command::Tag::burst>(maxDataSize);
- } else {
- if (actualSize != nullptr) *actualSize = 0;
- }
- return command;
- }
- bool interceptRawReply(const StreamDescriptor::Reply&) override { return false; }
- bool processValidReply(const StreamDescriptor::Reply& reply) override {
- if (mPreviousFrames.has_value()) {
- if (reply.observable.frames > mPreviousFrames.value()) {
- mObservablePositionIncrease = true;
- } else if (reply.observable.frames < mPreviousFrames.value()) {
- mRetrogradeObservablePosition = true;
- }
- }
- mPreviousFrames = reply.observable.frames;
-
- const auto& lastCommandState = mCommands[mNextCommand - 1];
- if (lastCommandState.second != reply.state) {
- std::string s = std::string("Unexpected transition from the state ")
- .append(mPreviousState)
- .append(" to ")
- .append(toString(reply.state))
- .append(" caused by the command ")
- .append(lastCommandState.first.toString());
- LOG(ERROR) << __func__ << ": " << s;
- mUnexpectedTransition = std::move(s);
- return false;
- }
- return true;
- }
-
- protected:
- const std::vector<CommandAndState>& mCommands;
- size_t mNextCommand = 0;
- std::optional<int64_t> mPreviousFrames;
- std::string mPreviousState = "<initial state>";
- bool mObservablePositionIncrease = false;
- bool mRetrogradeObservablePosition = false;
- std::string mUnexpectedTransition;
-};
-
-using NamedCommandSequence = std::pair<std::string, std::vector<CommandAndState>>;
-enum { PARAM_MODULE_NAME, PARAM_CMD_SEQ, PARAM_SETUP_SEQ };
-using StreamIoTestParameters =
- std::tuple<std::string /*moduleName*/, NamedCommandSequence, bool /*useSetupSequence2*/>;
-template <typename Stream>
-class AudioStreamIo : public AudioCoreModuleBase,
- public testing::TestWithParam<StreamIoTestParameters> {
- public:
- void SetUp() override {
- ASSERT_NO_FATAL_FAILURE(SetUpImpl(std::get<PARAM_MODULE_NAME>(GetParam())));
- ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
- }
-
- void Run() {
- const auto allPortConfigs =
- moduleConfig->getPortConfigsForMixPorts(IOTraits<Stream>::is_input);
- if (allPortConfigs.empty()) {
- GTEST_SKIP() << "No mix ports have attached devices";
- }
- for (const auto& portConfig : allPortConfigs) {
- SCOPED_TRACE(portConfig.toString());
- const auto& commandsAndStates = std::get<PARAM_CMD_SEQ>(GetParam()).second;
- if (!std::get<PARAM_SETUP_SEQ>(GetParam())) {
- ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq1(portConfig, commandsAndStates));
- } else {
- ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq2(portConfig, commandsAndStates));
- }
- }
- }
-
- bool ValidateObservablePosition(const AudioPortConfig& /*portConfig*/) {
- // May return false based on the portConfig, e.g. for telephony ports.
- return true;
- }
-
- // Set up a patch first, then open a stream.
- void RunStreamIoCommandsImplSeq1(const AudioPortConfig& portConfig,
- const std::vector<CommandAndState>& commandsAndStates) {
- auto devicePorts = moduleConfig->getAttachedDevicesPortsForMixPort(
- IOTraits<Stream>::is_input, portConfig);
- ASSERT_FALSE(devicePorts.empty());
- auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(devicePorts[0]);
- WithAudioPatch patch(IOTraits<Stream>::is_input, portConfig, devicePortConfig);
- ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
-
- WithStream<Stream> stream(patch.getPortConfig(IOTraits<Stream>::is_input));
- ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
- StreamLogicDefaultDriver driver(commandsAndStates);
- typename IOTraits<Stream>::Worker worker(*stream.getContext(), &driver);
-
- ASSERT_TRUE(worker.start());
- worker.join();
- EXPECT_FALSE(worker.hasError()) << worker.getError();
- EXPECT_EQ("", driver.getUnexpectedStateTransition());
- if (ValidateObservablePosition(portConfig)) {
- EXPECT_TRUE(driver.hasObservablePositionIncrease());
- EXPECT_FALSE(driver.hasRetrogradeObservablePosition());
- }
- }
-
- // Open a stream, then set up a patch for it.
- void RunStreamIoCommandsImplSeq2(const AudioPortConfig& portConfig,
- const std::vector<CommandAndState>& commandsAndStates) {
- WithStream<Stream> stream(portConfig);
- ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
- StreamLogicDefaultDriver driver(commandsAndStates);
- typename IOTraits<Stream>::Worker worker(*stream.getContext(), &driver);
-
- auto devicePorts = moduleConfig->getAttachedDevicesPortsForMixPort(
- IOTraits<Stream>::is_input, portConfig);
- ASSERT_FALSE(devicePorts.empty());
- auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(devicePorts[0]);
- WithAudioPatch patch(IOTraits<Stream>::is_input, stream.getPortConfig(), devicePortConfig);
- ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
-
- ASSERT_TRUE(worker.start());
- worker.join();
- EXPECT_FALSE(worker.hasError()) << worker.getError();
- EXPECT_EQ("", driver.getUnexpectedStateTransition());
- if (ValidateObservablePosition(portConfig)) {
- EXPECT_TRUE(driver.hasObservablePositionIncrease());
- EXPECT_FALSE(driver.hasRetrogradeObservablePosition());
- }
- }
-};
-using AudioStreamIoIn = AudioStreamIo<IStreamIn>;
-using AudioStreamIoOut = AudioStreamIo<IStreamOut>;
-
-#define TEST_IN_AND_OUT_STREAM_IO(method_name) \
- TEST_P(AudioStreamIoIn, method_name) { ASSERT_NO_FATAL_FAILURE(method_name()); } \
- TEST_P(AudioStreamIoOut, method_name) { ASSERT_NO_FATAL_FAILURE(method_name()); }
-
-TEST_IN_AND_OUT_STREAM_IO(Run);
-
-// Tests specific to audio patches. The fixure class is named 'AudioModulePatch'
-// to avoid clashing with 'AudioPatch' class.
-class AudioModulePatch : public AudioCoreModule {
- public:
- static std::string direction(bool isInput, bool capitalize) {
- return isInput ? (capitalize ? "Input" : "input") : (capitalize ? "Output" : "output");
- }
-
- void SetUp() override {
- ASSERT_NO_FATAL_FAILURE(AudioCoreModule::SetUp());
- ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
- }
-
- void SetInvalidPatchHelper(int32_t expectedException, const std::vector<int32_t>& sources,
- const std::vector<int32_t>& sinks) {
- AudioPatch patch;
- patch.sourcePortConfigIds = sources;
- patch.sinkPortConfigIds = sinks;
- ASSERT_STATUS(expectedException, module->setAudioPatch(patch, &patch))
- << "patch source ids: " << android::internal::ToString(sources)
- << "; sink ids: " << android::internal::ToString(sinks);
- }
-
- void ResetPortConfigUsedByPatch(bool isInput) {
- auto srcSinkGroups = moduleConfig->getRoutableSrcSinkGroups(isInput);
- if (srcSinkGroups.empty()) {
- GTEST_SKIP() << "No routes to any attached " << direction(isInput, false) << " devices";
- }
- auto srcSinkGroup = *srcSinkGroups.begin();
- auto srcSink = *srcSinkGroup.second.begin();
- WithAudioPatch patch(srcSink.first, srcSink.second);
- ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
- std::vector<int32_t> sourceAndSinkPortConfigIds(patch.get().sourcePortConfigIds);
- sourceAndSinkPortConfigIds.insert(sourceAndSinkPortConfigIds.end(),
- patch.get().sinkPortConfigIds.begin(),
- patch.get().sinkPortConfigIds.end());
- for (const auto portConfigId : sourceAndSinkPortConfigIds) {
- EXPECT_STATUS(EX_ILLEGAL_STATE, module->resetAudioPortConfig(portConfigId))
- << "port config ID " << portConfigId;
- }
- }
-
- void SetInvalidPatch(bool isInput) {
- auto srcSinkPair = moduleConfig->getRoutableSrcSinkPair(isInput);
- if (!srcSinkPair.has_value()) {
- GTEST_SKIP() << "No routes to any attached " << direction(isInput, false) << " devices";
- }
- WithAudioPortConfig srcPortConfig(srcSinkPair.value().first);
- ASSERT_NO_FATAL_FAILURE(srcPortConfig.SetUp(module.get()));
- WithAudioPortConfig sinkPortConfig(srcSinkPair.value().second);
- ASSERT_NO_FATAL_FAILURE(sinkPortConfig.SetUp(module.get()));
- { // Check that the pair can actually be used for setting up a patch.
- WithAudioPatch patch(srcPortConfig.get(), sinkPortConfig.get());
- ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
- }
- EXPECT_NO_FATAL_FAILURE(
- SetInvalidPatchHelper(EX_ILLEGAL_ARGUMENT, {}, {sinkPortConfig.getId()}));
- EXPECT_NO_FATAL_FAILURE(SetInvalidPatchHelper(
- EX_ILLEGAL_ARGUMENT, {srcPortConfig.getId(), srcPortConfig.getId()},
- {sinkPortConfig.getId()}));
- EXPECT_NO_FATAL_FAILURE(
- SetInvalidPatchHelper(EX_ILLEGAL_ARGUMENT, {srcPortConfig.getId()}, {}));
- EXPECT_NO_FATAL_FAILURE(
- SetInvalidPatchHelper(EX_ILLEGAL_ARGUMENT, {srcPortConfig.getId()},
- {sinkPortConfig.getId(), sinkPortConfig.getId()}));
-
- std::set<int32_t> portConfigIds;
- ASSERT_NO_FATAL_FAILURE(GetAllPortConfigIds(&portConfigIds));
- for (const auto portConfigId : GetNonExistentIds(portConfigIds)) {
- EXPECT_NO_FATAL_FAILURE(SetInvalidPatchHelper(EX_ILLEGAL_ARGUMENT, {portConfigId},
- {sinkPortConfig.getId()}));
- EXPECT_NO_FATAL_FAILURE(SetInvalidPatchHelper(EX_ILLEGAL_ARGUMENT,
- {srcPortConfig.getId()}, {portConfigId}));
- }
- }
-
- void SetNonRoutablePatch(bool isInput) {
- auto srcSinkPair = moduleConfig->getNonRoutableSrcSinkPair(isInput);
- if (!srcSinkPair.has_value()) {
- GTEST_SKIP() << "All possible source/sink pairs are routable";
- }
- WithAudioPatch patch(srcSinkPair.value().first, srcSinkPair.value().second);
- ASSERT_NO_FATAL_FAILURE(patch.SetUpPortConfigs(module.get()));
- EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, patch.SetUpNoChecks(module.get()))
- << "when setting up a patch from " << srcSinkPair.value().first.toString() << " to "
- << srcSinkPair.value().second.toString() << " that does not have a route";
- }
-
- void SetPatch(bool isInput) {
- auto srcSinkGroups = moduleConfig->getRoutableSrcSinkGroups(isInput);
- if (srcSinkGroups.empty()) {
- GTEST_SKIP() << "No routes to any attached " << direction(isInput, false) << " devices";
- }
- for (const auto& srcSinkGroup : srcSinkGroups) {
- const auto& route = srcSinkGroup.first;
- std::vector<std::unique_ptr<WithAudioPatch>> patches;
- for (const auto& srcSink : srcSinkGroup.second) {
- if (!route.isExclusive) {
- patches.push_back(
- std::make_unique<WithAudioPatch>(srcSink.first, srcSink.second));
- EXPECT_NO_FATAL_FAILURE(patches[patches.size() - 1]->SetUp(module.get()));
- } else {
- WithAudioPatch patch(srcSink.first, srcSink.second);
- EXPECT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
- }
- }
- }
- }
-
- void UpdatePatch(bool isInput) {
- auto srcSinkGroups = moduleConfig->getRoutableSrcSinkGroups(isInput);
- if (srcSinkGroups.empty()) {
- GTEST_SKIP() << "No routes to any attached " << direction(isInput, false) << " devices";
- }
- for (const auto& srcSinkGroup : srcSinkGroups) {
- for (const auto& srcSink : srcSinkGroup.second) {
- WithAudioPatch patch(srcSink.first, srcSink.second);
- ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
- AudioPatch ignored;
- EXPECT_NO_FATAL_FAILURE(module->setAudioPatch(patch.get(), &ignored));
- }
- }
- }
-
- void UpdateInvalidPatchId(bool isInput) {
- auto srcSinkGroups = moduleConfig->getRoutableSrcSinkGroups(isInput);
- if (srcSinkGroups.empty()) {
- GTEST_SKIP() << "No routes to any attached " << direction(isInput, false) << " devices";
- }
- // First, set up a patch to ensure that its settings are accepted.
- auto srcSinkGroup = *srcSinkGroups.begin();
- auto srcSink = *srcSinkGroup.second.begin();
- WithAudioPatch patch(srcSink.first, srcSink.second);
- ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
- // Then use the same patch setting, except for having an invalid ID.
- std::set<int32_t> patchIds;
- ASSERT_NO_FATAL_FAILURE(GetAllPatchIds(&patchIds));
- for (const auto patchId : GetNonExistentIds(patchIds)) {
- AudioPatch patchWithNonExistendId = patch.get();
- patchWithNonExistendId.id = patchId;
- EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
- module->setAudioPatch(patchWithNonExistendId, &patchWithNonExistendId))
- << "patch ID " << patchId;
- }
- }
-};
-
-// Not all tests require both directions, so parametrization would require
-// more abstractions.
-#define TEST_PATCH_BOTH_DIRECTIONS(method_name) \
- TEST_P(AudioModulePatch, method_name##Input) { ASSERT_NO_FATAL_FAILURE(method_name(true)); } \
- TEST_P(AudioModulePatch, method_name##Output) { ASSERT_NO_FATAL_FAILURE(method_name(false)); }
-
-TEST_PATCH_BOTH_DIRECTIONS(ResetPortConfigUsedByPatch);
-TEST_PATCH_BOTH_DIRECTIONS(SetInvalidPatch);
-TEST_PATCH_BOTH_DIRECTIONS(SetNonRoutablePatch);
-TEST_PATCH_BOTH_DIRECTIONS(SetPatch);
-TEST_PATCH_BOTH_DIRECTIONS(UpdateInvalidPatchId);
-TEST_PATCH_BOTH_DIRECTIONS(UpdatePatch);
-
-TEST_P(AudioModulePatch, ResetInvalidPatchId) {
- std::set<int32_t> patchIds;
- ASSERT_NO_FATAL_FAILURE(GetAllPatchIds(&patchIds));
- for (const auto patchId : GetNonExistentIds(patchIds)) {
- EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->resetAudioPatch(patchId))
- << "patch ID " << patchId;
- }
-}
-
-INSTANTIATE_TEST_SUITE_P(AudioCoreModuleTest, AudioCoreModule,
- testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
- android::PrintInstanceNameToString);
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioCoreModule);
-INSTANTIATE_TEST_SUITE_P(AudioCoreTelephonyTest, AudioCoreTelephony,
- testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
- android::PrintInstanceNameToString);
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioCoreTelephony);
-INSTANTIATE_TEST_SUITE_P(AudioStreamInTest, AudioStreamIn,
- testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
- android::PrintInstanceNameToString);
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioStreamIn);
-INSTANTIATE_TEST_SUITE_P(AudioStreamOutTest, AudioStreamOut,
- testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
- android::PrintInstanceNameToString);
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioStreamOut);
-
-static const StreamDescriptor::Command kStartCommand =
- StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::start>(Void{});
-static const StreamDescriptor::Command kBurstCommand =
- StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::burst>(0);
-static const StreamDescriptor::Command kDrainCommand =
- StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::drain>(Void{});
-static const StreamDescriptor::Command kStandbyCommand =
- StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::standby>(Void{});
-static const StreamDescriptor::Command kPauseCommand =
- StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::pause>(Void{});
-static const StreamDescriptor::Command kFlushCommand =
- StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::flush>(Void{});
-static const NamedCommandSequence kReadOrWriteSeq =
- std::make_pair(std::string("ReadOrWrite"),
- std::vector<CommandAndState>{
- std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
- std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
- std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
- std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE)});
-static const NamedCommandSequence kDrainInSeq =
- std::make_pair(std::string("Drain"),
- std::vector<CommandAndState>{
- std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
- std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
- std::make_pair(kDrainCommand, StreamDescriptor::State::DRAINING),
- std::make_pair(kStartCommand, StreamDescriptor::State::ACTIVE),
- std::make_pair(kDrainCommand, StreamDescriptor::State::DRAINING),
- // TODO: This will need to be changed once DRAIN starts taking time.
- std::make_pair(kBurstCommand, StreamDescriptor::State::STANDBY)});
-static const NamedCommandSequence kDrainOutSeq =
- std::make_pair(std::string("Drain"),
- std::vector<CommandAndState>{
- std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
- std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
- // TODO: This will need to be changed once DRAIN starts taking time.
- std::make_pair(kDrainCommand, StreamDescriptor::State::IDLE)});
-// TODO: This will need to be changed once DRAIN starts taking time so we can pause it.
-static const NamedCommandSequence kDrainPauseOutSeq = std::make_pair(
- std::string("DrainPause"),
- std::vector<CommandAndState>{std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
- std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
- std::make_pair(kDrainCommand, StreamDescriptor::State::IDLE)});
-static const NamedCommandSequence kStandbySeq =
- std::make_pair(std::string("Standby"),
- std::vector<CommandAndState>{
- std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
- std::make_pair(kStandbyCommand, StreamDescriptor::State::STANDBY),
- // Perform a read or write in order to advance observable position
- // (this is verified by tests).
- std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
- std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE)});
-static const NamedCommandSequence kPauseInSeq =
- std::make_pair(std::string("Pause"),
- std::vector<CommandAndState>{
- std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
- std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
- std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
- std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
- std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
- std::make_pair(kFlushCommand, StreamDescriptor::State::STANDBY)});
-static const NamedCommandSequence kPauseOutSeq =
- std::make_pair(std::string("Pause"),
- std::vector<CommandAndState>{
- std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
- std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
- std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
- std::make_pair(kStartCommand, StreamDescriptor::State::ACTIVE),
- std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
- std::make_pair(kBurstCommand, StreamDescriptor::State::PAUSED),
- std::make_pair(kStartCommand, StreamDescriptor::State::ACTIVE),
- std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED)});
-static const NamedCommandSequence kFlushInSeq =
- std::make_pair(std::string("Flush"),
- std::vector<CommandAndState>{
- std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
- std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
- std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
- std::make_pair(kFlushCommand, StreamDescriptor::State::STANDBY)});
-static const NamedCommandSequence kFlushOutSeq = std::make_pair(
- std::string("Flush"),
- std::vector<CommandAndState>{std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
- std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
- std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
- std::make_pair(kFlushCommand, StreamDescriptor::State::IDLE)});
-std::string GetStreamIoTestName(const testing::TestParamInfo<StreamIoTestParameters>& info) {
- return android::PrintInstanceNameToString(
- testing::TestParamInfo<std::string>{std::get<PARAM_MODULE_NAME>(info.param),
- info.index})
- .append("_")
- .append(std::get<PARAM_CMD_SEQ>(info.param).first)
- .append("_SetupSeq")
- .append(std::get<PARAM_SETUP_SEQ>(info.param) ? "2" : "1");
-}
-INSTANTIATE_TEST_SUITE_P(
- AudioStreamIoInTest, AudioStreamIoIn,
- testing::Combine(testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
- testing::Values(kReadOrWriteSeq, kDrainInSeq, kStandbySeq, kPauseInSeq,
- kFlushInSeq),
- testing::Values(false, true)),
- GetStreamIoTestName);
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioStreamIoIn);
-INSTANTIATE_TEST_SUITE_P(
- AudioStreamIoOutTest, AudioStreamIoOut,
- testing::Combine(testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
- testing::Values(kReadOrWriteSeq, kDrainOutSeq, kDrainPauseOutSeq,
- kStandbySeq, kPauseOutSeq, kFlushOutSeq),
- testing::Values(false, true)),
- GetStreamIoTestName);
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioStreamIoOut);
-
-INSTANTIATE_TEST_SUITE_P(AudioPatchTest, AudioModulePatch,
- testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
- android::PrintInstanceNameToString);
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioModulePatch);
-
-class TestExecutionTracer : public ::testing::EmptyTestEventListener {
- public:
- void OnTestStart(const ::testing::TestInfo& test_info) override {
- TraceTestState("Started", test_info);
- }
-
- void OnTestEnd(const ::testing::TestInfo& test_info) override {
- TraceTestState("Completed", test_info);
- }
-
- private:
- static void TraceTestState(const std::string& state, const ::testing::TestInfo& test_info) {
- LOG(INFO) << state << " " << test_info.test_suite_name() << "::" << test_info.name();
- }
-};
-
-int main(int argc, char** argv) {
- ::testing::InitGoogleTest(&argc, argv);
- ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
- ABinderProcess_setThreadPoolMaxThreadCount(1);
- ABinderProcess_startThreadPool();
- return RUN_ALL_TESTS();
-}
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..8938618 100644
--- a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
@@ -49,18 +49,30 @@
using aidl::android::hardware::audio::effect::State;
enum ParamName { PARAM_INSTANCE_NAME };
-using EffectTestParam = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor::Identity>>;
+using EffectTestParam = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>>;
class AudioEffectTest : public testing::TestWithParam<EffectTestParam>, public EffectHelper {
public:
- AudioEffectTest() { std::tie(mFactory, mIdentity) = std::get<PARAM_INSTANCE_NAME>(GetParam()); }
+ AudioEffectTest() {
+ std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
+ }
void SetUp() override {}
- void TearDown() override {}
+
+ void TearDown() override {
+ // Do the cleanup for every test case
+ if (mEffect) {
+ ASSERT_NO_FATAL_FAILURE(commandIgnoreRet(mEffect, CommandId::STOP));
+ ASSERT_NO_FATAL_FAILURE(closeIgnoreRet(mEffect));
+ ASSERT_NO_FATAL_FAILURE(destroyIgnoreRet(mFactory, mEffect));
+ mEffect.reset();
+ }
+ }
static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
std::shared_ptr<IFactory> mFactory;
- Descriptor::Identity mIdentity;
+ std::shared_ptr<IEffect> mEffect;
+ Descriptor mDescriptor;
};
TEST_P(AudioEffectTest, SetupAndTearDown) {
@@ -68,30 +80,27 @@
}
TEST_P(AudioEffectTest, CreateAndDestroy) {
- std::shared_ptr<IEffect> effect;
- ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
- ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
}
TEST_P(AudioEffectTest, OpenAndClose) {
- std::shared_ptr<IEffect> effect;
- ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
- ASSERT_NO_FATAL_FAILURE(open(effect));
- ASSERT_NO_FATAL_FAILURE(close(effect));
- ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+ ASSERT_NO_FATAL_FAILURE(open(mEffect));
+ ASSERT_NO_FATAL_FAILURE(close(mEffect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
}
TEST_P(AudioEffectTest, CloseUnopenedEffect) {
- std::shared_ptr<IEffect> effect;
- ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
- ASSERT_NO_FATAL_FAILURE(close(effect));
- ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+ ASSERT_NO_FATAL_FAILURE(close(mEffect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
}
TEST_P(AudioEffectTest, DoubleOpenAndClose) {
std::shared_ptr<IEffect> effect1, effect2;
- ASSERT_NO_FATAL_FAILURE(create(mFactory, effect1, mIdentity));
- ASSERT_NO_FATAL_FAILURE(create(mFactory, effect2, mIdentity));
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, effect1, mDescriptor));
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, effect2, mDescriptor));
ASSERT_NO_FATAL_FAILURE(open(effect1));
ASSERT_NO_FATAL_FAILURE(open(effect2, 1 /* session */));
ASSERT_NO_FATAL_FAILURE(close(effect1));
@@ -102,9 +111,9 @@
TEST_P(AudioEffectTest, TripleOpenAndClose) {
std::shared_ptr<IEffect> effect1, effect2, effect3;
- ASSERT_NO_FATAL_FAILURE(create(mFactory, effect1, mIdentity));
- ASSERT_NO_FATAL_FAILURE(create(mFactory, effect2, mIdentity));
- ASSERT_NO_FATAL_FAILURE(create(mFactory, effect3, mIdentity));
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, effect1, mDescriptor));
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, effect2, mDescriptor));
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, effect3, mDescriptor));
ASSERT_NO_FATAL_FAILURE(open(effect1));
ASSERT_NO_FATAL_FAILURE(open(effect2, 1 /* session */));
ASSERT_NO_FATAL_FAILURE(open(effect3, 2 /* session */));
@@ -117,513 +126,505 @@
}
TEST_P(AudioEffectTest, GetDescritorBeforeOpen) {
- std::shared_ptr<IEffect> effect;
Descriptor desc;
- ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
- ASSERT_NO_FATAL_FAILURE(getDescriptor(effect, desc));
- EXPECT_EQ(mIdentity.toString(), desc.common.id.toString());
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+ ASSERT_NO_FATAL_FAILURE(getDescriptor(mEffect, desc));
+ EXPECT_EQ(mDescriptor.common, desc.common);
+ // Effect implementation Must fill in implementor and name
EXPECT_NE("", desc.common.name);
EXPECT_NE("", desc.common.implementor);
- ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
}
TEST_P(AudioEffectTest, GetDescritorAfterOpen) {
- std::shared_ptr<IEffect> effect;
Descriptor beforeOpen, afterOpen, afterClose;
- ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
- ASSERT_NO_FATAL_FAILURE(getDescriptor(effect, beforeOpen));
- ASSERT_NO_FATAL_FAILURE(open(effect));
- ASSERT_NO_FATAL_FAILURE(getDescriptor(effect, afterOpen));
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+ ASSERT_NO_FATAL_FAILURE(getDescriptor(mEffect, beforeOpen));
+ ASSERT_NO_FATAL_FAILURE(open(mEffect));
+ ASSERT_NO_FATAL_FAILURE(getDescriptor(mEffect, afterOpen));
EXPECT_EQ(beforeOpen.toString(), afterOpen.toString()) << "\n"
<< beforeOpen.toString() << "\n"
<< afterOpen.toString();
- ASSERT_NO_FATAL_FAILURE(close(effect));
- ASSERT_NO_FATAL_FAILURE(getDescriptor(effect, afterClose));
+ ASSERT_NO_FATAL_FAILURE(close(mEffect));
+ ASSERT_NO_FATAL_FAILURE(getDescriptor(mEffect, afterClose));
EXPECT_EQ(beforeOpen.toString(), afterClose.toString()) << "\n"
<< beforeOpen.toString() << "\n"
<< afterClose.toString();
- ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
}
TEST_P(AudioEffectTest, DescriptorExistAndUnique) {
- std::shared_ptr<IEffect> effect;
Descriptor desc;
auto descList = EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor);
std::set<Descriptor::Identity> idSet;
for (const auto& it : descList) {
- auto& id = it.second;
+ auto& id = it.second.common.id;
EXPECT_EQ(0ul, idSet.count(id));
idSet.insert(id);
}
- ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
- ASSERT_NO_FATAL_FAILURE(getDescriptor(effect, desc));
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+ ASSERT_NO_FATAL_FAILURE(getDescriptor(mEffect, desc));
EXPECT_EQ(1ul, idSet.count(desc.common.id));
- ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
}
/// State testing.
// An effect instance is in INIT state by default after it was created.
TEST_P(AudioEffectTest, InitStateAfterCreation) {
- std::shared_ptr<IEffect> effect;
- ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::INIT));
- ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::INIT));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
}
// An effect instance transfer to IDLE state after IEffect.ASSERT_NO_FATAL_FAILURE(open().
TEST_P(AudioEffectTest, IdleStateAfterOpen) {
- std::shared_ptr<IEffect> effect;
- ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
- ASSERT_NO_FATAL_FAILURE(open(effect));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
- ASSERT_NO_FATAL_FAILURE(close(effect));
- ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+ ASSERT_NO_FATAL_FAILURE(open(mEffect));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(close(mEffect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
}
// An effect instance is in PROCESSING state after it receive an START command.
TEST_P(AudioEffectTest, ProcessingStateAfterStart) {
- std::shared_ptr<IEffect> effect;
- ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::INIT));
- ASSERT_NO_FATAL_FAILURE(open(effect));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
- ASSERT_NO_FATAL_FAILURE(close(effect));
- ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::INIT));
+ ASSERT_NO_FATAL_FAILURE(open(mEffect));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+ ASSERT_NO_FATAL_FAILURE(close(mEffect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
}
// An effect instance transfer to IDLE state after Command.Id.STOP in PROCESSING state.
TEST_P(AudioEffectTest, IdleStateAfterStop) {
- std::shared_ptr<IEffect> effect;
- ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
- ASSERT_NO_FATAL_FAILURE(open(effect));
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
- ASSERT_NO_FATAL_FAILURE(close(effect));
- ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+ ASSERT_NO_FATAL_FAILURE(open(mEffect));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(close(mEffect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
}
// An effect instance transfer to IDLE state after Command.Id.RESET in PROCESSING state.
TEST_P(AudioEffectTest, IdleStateAfterReset) {
- std::shared_ptr<IEffect> effect;
- ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
- ASSERT_NO_FATAL_FAILURE(open(effect));
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
- ASSERT_NO_FATAL_FAILURE(close(effect));
- ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+ ASSERT_NO_FATAL_FAILURE(open(mEffect));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::RESET));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(close(mEffect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
}
// An effect instance transfer to INIT after IEffect.ASSERT_NO_FATAL_FAILURE(close().
TEST_P(AudioEffectTest, InitStateAfterClose) {
- std::shared_ptr<IEffect> effect;
- ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
- ASSERT_NO_FATAL_FAILURE(open(effect));
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
- ASSERT_NO_FATAL_FAILURE(close(effect));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::INIT));
- ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+ ASSERT_NO_FATAL_FAILURE(open(mEffect));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+ ASSERT_NO_FATAL_FAILURE(close(mEffect));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::INIT));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
}
// An effect instance shouldn't accept any command before open.
TEST_P(AudioEffectTest, NoCommandAcceptedBeforeOpen) {
- std::shared_ptr<IEffect> effect;
- ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START, EX_ILLEGAL_STATE));
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP, EX_ILLEGAL_STATE));
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET, EX_ILLEGAL_STATE));
- ASSERT_NO_FATAL_FAILURE(open(effect));
- ASSERT_NO_FATAL_FAILURE(close(effect));
- ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START, EX_ILLEGAL_STATE));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP, EX_ILLEGAL_STATE));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::RESET, EX_ILLEGAL_STATE));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
}
// No-op when receive STOP command in IDLE state.
TEST_P(AudioEffectTest, StopCommandInIdleStateNoOp) {
- std::shared_ptr<IEffect> effect;
- ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
- ASSERT_NO_FATAL_FAILURE(open(effect));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
- ASSERT_NO_FATAL_FAILURE(close(effect));
- ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+ ASSERT_NO_FATAL_FAILURE(open(mEffect));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(close(mEffect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
}
// No-op when receive RESET command in IDLE state.
TEST_P(AudioEffectTest, ResetCommandInIdleStateNoOp) {
- std::shared_ptr<IEffect> effect;
- ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
- ASSERT_NO_FATAL_FAILURE(open(effect));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
- ASSERT_NO_FATAL_FAILURE(close(effect));
- ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+ ASSERT_NO_FATAL_FAILURE(open(mEffect));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::RESET));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(close(mEffect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
}
// Repeat START and STOP command.
TEST_P(AudioEffectTest, RepeatStartAndStop) {
- std::shared_ptr<IEffect> effect;
- ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
- ASSERT_NO_FATAL_FAILURE(open(effect));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+ ASSERT_NO_FATAL_FAILURE(open(mEffect));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
- ASSERT_NO_FATAL_FAILURE(close(effect));
- ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(close(mEffect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
}
// Repeat START and RESET command.
TEST_P(AudioEffectTest, RepeatStartAndReset) {
- std::shared_ptr<IEffect> effect;
- ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
- ASSERT_NO_FATAL_FAILURE(open(effect));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+ ASSERT_NO_FATAL_FAILURE(open(mEffect));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::RESET));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
- ASSERT_NO_FATAL_FAILURE(close(effect));
- ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::RESET));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(close(mEffect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
}
// Try to close an effect instance at PROCESSING state.
TEST_P(AudioEffectTest, CloseProcessingStateEffects) {
- std::shared_ptr<IEffect> effect;
- ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
- ASSERT_NO_FATAL_FAILURE(open(effect));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+ ASSERT_NO_FATAL_FAILURE(open(mEffect));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
- ASSERT_NO_FATAL_FAILURE(close(effect, EX_ILLEGAL_STATE));
+ ASSERT_NO_FATAL_FAILURE(close(mEffect, EX_ILLEGAL_STATE));
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
- ASSERT_NO_FATAL_FAILURE(close(effect));
- ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(close(mEffect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
}
// Expect EX_ILLEGAL_STATE if the effect instance is not in a proper state to be destroyed.
TEST_P(AudioEffectTest, DestroyOpenEffects) {
- std::shared_ptr<IEffect> effect;
- ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
- ASSERT_NO_FATAL_FAILURE(open(effect));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+ ASSERT_NO_FATAL_FAILURE(open(mEffect));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
- ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect, EX_ILLEGAL_STATE));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect, EX_ILLEGAL_STATE));
+
+ // cleanup
+ ASSERT_NO_FATAL_FAILURE(close(mEffect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
}
// Expect EX_ILLEGAL_STATE if the effect instance is not in a proper state to be destroyed.
TEST_P(AudioEffectTest, DestroyProcessingEffects) {
- std::shared_ptr<IEffect> effect;
- ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
- ASSERT_NO_FATAL_FAILURE(open(effect));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+ ASSERT_NO_FATAL_FAILURE(open(mEffect));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
- ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect, EX_ILLEGAL_STATE));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect, EX_ILLEGAL_STATE));
+
+ // cleanup
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(close(mEffect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
}
TEST_P(AudioEffectTest, NormalSequenceStates) {
- std::shared_ptr<IEffect> effect;
- ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::INIT));
- ASSERT_NO_FATAL_FAILURE(open(effect));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
- ASSERT_NO_FATAL_FAILURE(close(effect));
- ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::INIT));
+ ASSERT_NO_FATAL_FAILURE(open(mEffect));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::RESET));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(close(mEffect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
}
/// Parameter testing.
// Verify parameters pass in open can be successfully get.
TEST_P(AudioEffectTest, VerifyCommonParametersAfterOpen) {
- std::shared_ptr<IEffect> effect;
- ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
Parameter::Common common = EffectHelper::createParamCommon();
IEffect::OpenEffectReturn ret;
- ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, EX_NONE));
+ ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt /* specific */, &ret, EX_NONE));
Parameter get = Parameter(), expect = Parameter();
expect.set<Parameter::common>(common);
Parameter::Id id;
id.set<Parameter::Id::commonTag>(Parameter::common);
- EXPECT_IS_OK(effect->getParameter(id, &get));
+ EXPECT_IS_OK(mEffect->getParameter(id, &get));
EXPECT_EQ(expect, get) << expect.toString() << " vs " << get.toString();
- ASSERT_NO_FATAL_FAILURE(close(effect));
- ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+ ASSERT_NO_FATAL_FAILURE(close(mEffect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
}
// Verify parameters pass in set can be successfully get.
TEST_P(AudioEffectTest, SetAndGetCommonParameter) {
- std::shared_ptr<IEffect> effect;
- ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
- ASSERT_NO_FATAL_FAILURE(open(effect));
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+ ASSERT_NO_FATAL_FAILURE(open(mEffect));
Parameter::Common common = EffectHelper::createParamCommon(
0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */);
Parameter get = Parameter(), set = Parameter();
set.set<Parameter::common>(common);
- EXPECT_IS_OK(effect->setParameter(set));
+ EXPECT_IS_OK(mEffect->setParameter(set));
Parameter::Id id;
id.set<Parameter::Id::commonTag>(Parameter::common);
- EXPECT_IS_OK(effect->getParameter(id, &get));
+ EXPECT_IS_OK(mEffect->getParameter(id, &get));
EXPECT_EQ(set, get) << set.toString() << " vs " << get.toString();
- ASSERT_NO_FATAL_FAILURE(close(effect));
- ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+ ASSERT_NO_FATAL_FAILURE(close(mEffect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
}
// Verify parameters set and get in PROCESSING state.
TEST_P(AudioEffectTest, SetAndGetParameterInProcessing) {
- std::shared_ptr<IEffect> effect;
- ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
- ASSERT_NO_FATAL_FAILURE(open(effect));
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+ ASSERT_NO_FATAL_FAILURE(open(mEffect));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
Parameter::Common common = EffectHelper::createParamCommon(
0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */);
Parameter get = Parameter(), set = Parameter();
set.set<Parameter::common>(common);
- EXPECT_IS_OK(effect->setParameter(set));
+ EXPECT_IS_OK(mEffect->setParameter(set));
Parameter::Id id;
id.set<Parameter::Id::commonTag>(Parameter::common);
- EXPECT_IS_OK(effect->getParameter(id, &get));
+ EXPECT_IS_OK(mEffect->getParameter(id, &get));
EXPECT_EQ(set, get) << set.toString() << " vs " << get.toString();
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
- ASSERT_NO_FATAL_FAILURE(close(effect));
- ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+ ASSERT_NO_FATAL_FAILURE(close(mEffect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
}
// Verify parameters set and get in IDLE state.
TEST_P(AudioEffectTest, SetAndGetParameterInIdle) {
- std::shared_ptr<IEffect> effect;
- ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
- ASSERT_NO_FATAL_FAILURE(open(effect));
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+ ASSERT_NO_FATAL_FAILURE(open(mEffect));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
Parameter::Common common = EffectHelper::createParamCommon(
0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */);
Parameter get = Parameter(), set = Parameter();
set.set<Parameter::common>(common);
- EXPECT_IS_OK(effect->setParameter(set));
+ EXPECT_IS_OK(mEffect->setParameter(set));
Parameter::Id id;
id.set<Parameter::Id::commonTag>(Parameter::common);
- EXPECT_IS_OK(effect->getParameter(id, &get));
+ EXPECT_IS_OK(mEffect->getParameter(id, &get));
EXPECT_EQ(set, get) << set.toString() << " vs " << get.toString();
- ASSERT_NO_FATAL_FAILURE(close(effect));
- ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+ ASSERT_NO_FATAL_FAILURE(close(mEffect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
}
// Verify Parameters kept after stop.
TEST_P(AudioEffectTest, SetAndGetParameterAfterStop) {
- std::shared_ptr<IEffect> effect;
- ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
- ASSERT_NO_FATAL_FAILURE(open(effect));
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+ ASSERT_NO_FATAL_FAILURE(open(mEffect));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
Parameter::Common common = EffectHelper::createParamCommon(
0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */);
Parameter get = Parameter(), set = Parameter();
set.set<Parameter::common>(common);
- EXPECT_IS_OK(effect->setParameter(set));
+ EXPECT_IS_OK(mEffect->setParameter(set));
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
Parameter::Id id;
id.set<Parameter::Id::commonTag>(Parameter::common);
- EXPECT_IS_OK(effect->getParameter(id, &get));
+ EXPECT_IS_OK(mEffect->getParameter(id, &get));
EXPECT_EQ(set, get) << set.toString() << " vs " << get.toString();
- ASSERT_NO_FATAL_FAILURE(close(effect));
- ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+ ASSERT_NO_FATAL_FAILURE(close(mEffect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
}
// Verify Parameters kept after reset.
TEST_P(AudioEffectTest, SetAndGetParameterAfterReset) {
- std::shared_ptr<IEffect> effect;
- ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
- ASSERT_NO_FATAL_FAILURE(open(effect));
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+ ASSERT_NO_FATAL_FAILURE(open(mEffect));
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
Parameter::Common common = EffectHelper::createParamCommon(
0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */);
Parameter get = Parameter(), set = Parameter();
set.set<Parameter::common>(common);
- EXPECT_IS_OK(effect->setParameter(set));
+ EXPECT_IS_OK(mEffect->setParameter(set));
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::RESET));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
Parameter::Id id;
id.set<Parameter::Id::commonTag>(Parameter::common);
- EXPECT_IS_OK(effect->getParameter(id, &get));
+ EXPECT_IS_OK(mEffect->getParameter(id, &get));
EXPECT_EQ(set, get) << set.toString() << " vs " << get.toString();
- ASSERT_NO_FATAL_FAILURE(close(effect));
- ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+ ASSERT_NO_FATAL_FAILURE(close(mEffect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
}
-
/// Data processing test
// Send data to effects and expect it to be consumed by checking statusMQ.
TEST_P(AudioEffectTest, ConsumeDataInProcessingState) {
- std::shared_ptr<IEffect> effect;
- ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
Parameter::Common common = EffectHelper::createParamCommon(
0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
IEffect::OpenEffectReturn ret;
- ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, EX_NONE));
+ ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt /* specific */, &ret, EX_NONE));
auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
+ ASSERT_TRUE(statusMQ->isValid());
auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
+ ASSERT_TRUE(inputMQ->isValid());
auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
+ ASSERT_TRUE(outputMQ->isValid());
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
std::vector<float> buffer;
EffectHelper::allocateInputData(common, inputMQ, buffer);
EffectHelper::writeToFmq(inputMQ, buffer);
EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer);
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
- ASSERT_NO_FATAL_FAILURE(close(effect));
- ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+ ASSERT_NO_FATAL_FAILURE(close(mEffect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
}
// Send data to effects and expect it to be consumed after effect restart.
TEST_P(AudioEffectTest, ConsumeDataAfterRestart) {
- std::shared_ptr<IEffect> effect;
- ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
Parameter::Common common = EffectHelper::createParamCommon(
0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
IEffect::OpenEffectReturn ret;
- ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, EX_NONE));
+ ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt /* specific */, &ret, EX_NONE));
auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
+ ASSERT_TRUE(statusMQ->isValid());
auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
+ ASSERT_TRUE(inputMQ->isValid());
auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
+ ASSERT_TRUE(outputMQ->isValid());
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
std::vector<float> buffer;
EffectHelper::allocateInputData(common, inputMQ, buffer);
EffectHelper::writeToFmq(inputMQ, buffer);
EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer);
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
- ASSERT_NO_FATAL_FAILURE(close(effect));
- ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+ ASSERT_NO_FATAL_FAILURE(close(mEffect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
}
// Send data to IDLE effects and expect it to be consumed after effect start.
TEST_P(AudioEffectTest, SendDataAtIdleAndConsumeDataInProcessing) {
- std::shared_ptr<IEffect> effect;
- ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
Parameter::Common common = EffectHelper::createParamCommon(
0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
IEffect::OpenEffectReturn ret;
- ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, EX_NONE));
+ ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt /* specific */, &ret, EX_NONE));
auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
+ ASSERT_TRUE(statusMQ->isValid());
auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
+ ASSERT_TRUE(inputMQ->isValid());
auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
+ ASSERT_TRUE(outputMQ->isValid());
std::vector<float> buffer;
EffectHelper::allocateInputData(common, inputMQ, buffer);
EffectHelper::writeToFmq(inputMQ, buffer);
EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer);
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer);
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
- ASSERT_NO_FATAL_FAILURE(close(effect));
- ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+ ASSERT_NO_FATAL_FAILURE(close(mEffect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
}
// Send data multiple times.
TEST_P(AudioEffectTest, ProcessDataMultipleTimes) {
- std::shared_ptr<IEffect> effect;
- ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
Parameter::Common common = EffectHelper::createParamCommon(
0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
IEffect::OpenEffectReturn ret;
- ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, EX_NONE));
+ ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt /* specific */, &ret, EX_NONE));
auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
+ ASSERT_TRUE(statusMQ->isValid());
auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
+ ASSERT_TRUE(inputMQ->isValid());
auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
+ ASSERT_TRUE(outputMQ->isValid());
std::vector<float> buffer;
EffectHelper::allocateInputData(common, inputMQ, buffer);
EffectHelper::writeToFmq(inputMQ, buffer);
EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer);
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer);
// expect no status and data after consume
@@ -634,77 +635,81 @@
// expect no status and data after consume
EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer);
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
- ASSERT_NO_FATAL_FAILURE(close(effect));
- ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+ ASSERT_NO_FATAL_FAILURE(close(mEffect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
}
// Send data to IDLE state effects and expect it not be consumed.
TEST_P(AudioEffectTest, NotConsumeDataInIdleState) {
- std::shared_ptr<IEffect> effect;
- ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
Parameter::Common common = EffectHelper::createParamCommon(
0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
IEffect::OpenEffectReturn ret;
- ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, EX_NONE));
+ ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt /* specific */, &ret, EX_NONE));
auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
+ ASSERT_TRUE(statusMQ->isValid());
auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
+ ASSERT_TRUE(inputMQ->isValid());
auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
+ ASSERT_TRUE(outputMQ->isValid());
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
std::vector<float> buffer;
EffectHelper::allocateInputData(common, inputMQ, buffer);
EffectHelper::writeToFmq(inputMQ, buffer);
EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer);
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer);
- ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
- ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
- ASSERT_NO_FATAL_FAILURE(close(effect));
- ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+ ASSERT_NO_FATAL_FAILURE(close(mEffect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
}
// Send data to closed effects and expect it not be consumed.
TEST_P(AudioEffectTest, NotConsumeDataByClosedEffect) {
- std::shared_ptr<IEffect> effect;
- ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
Parameter::Common common = EffectHelper::createParamCommon(
0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
IEffect::OpenEffectReturn ret;
- ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, EX_NONE));
- ASSERT_NO_FATAL_FAILURE(close(effect));
+ ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt /* specific */, &ret, EX_NONE));
+ ASSERT_NO_FATAL_FAILURE(close(mEffect));
auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
+ ASSERT_TRUE(statusMQ->isValid());
auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
+ ASSERT_TRUE(inputMQ->isValid());
auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
+ ASSERT_TRUE(outputMQ->isValid());
std::vector<float> buffer;
EffectHelper::allocateInputData(common, inputMQ, buffer);
EffectHelper::writeToFmq(inputMQ, buffer);
EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer);
- ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
}
// Send data to multiple effects.
TEST_P(AudioEffectTest, ConsumeDataMultipleEffects) {
std::shared_ptr<IEffect> effect1, effect2;
- ASSERT_NO_FATAL_FAILURE(create(mFactory, effect1, mIdentity));
- ASSERT_NO_FATAL_FAILURE(create(mFactory, effect2, mIdentity));
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, effect1, mDescriptor));
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, effect2, mDescriptor));
Parameter::Common common1 = EffectHelper::createParamCommon(
0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
@@ -721,8 +726,11 @@
ASSERT_NO_FATAL_FAILURE(expectState(effect2, State::PROCESSING));
auto statusMQ1 = std::make_unique<EffectHelper::StatusMQ>(ret1.statusMQ);
+ ASSERT_TRUE(statusMQ1->isValid());
auto inputMQ1 = std::make_unique<EffectHelper::DataMQ>(ret1.inputDataMQ);
+ ASSERT_TRUE(inputMQ1->isValid());
auto outputMQ1 = std::make_unique<EffectHelper::DataMQ>(ret1.outputDataMQ);
+ ASSERT_TRUE(outputMQ1->isValid());
std::vector<float> buffer1, buffer2;
EffectHelper::allocateInputData(common1, inputMQ1, buffer1);
@@ -730,8 +738,11 @@
EffectHelper::readFromFmq(statusMQ1, 1, outputMQ1, buffer1.size(), buffer1);
auto statusMQ2 = std::make_unique<EffectHelper::StatusMQ>(ret2.statusMQ);
+ ASSERT_TRUE(statusMQ2->isValid());
auto inputMQ2 = std::make_unique<EffectHelper::DataMQ>(ret2.inputDataMQ);
+ ASSERT_TRUE(inputMQ2->isValid());
auto outputMQ2 = std::make_unique<EffectHelper::DataMQ>(ret2.outputDataMQ);
+ ASSERT_TRUE(outputMQ2->isValid());
EffectHelper::allocateInputData(common2, inputMQ2, buffer2);
EffectHelper::writeToFmq(inputMQ2, buffer2);
EffectHelper::readFromFmq(statusMQ2, 1, outputMQ2, buffer2.size(), buffer2);
@@ -752,16 +763,11 @@
::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);
+ auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
+ std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+ descriptor.common.name + "_TYPE_" +
+ descriptor.common.id.type.toString() + "_UUID_" +
+ descriptor.common.id.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..724a9c3
--- /dev/null
+++ b/audio/aidl/vts/VtsHalBassBoostTargetTest.cpp
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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>, 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, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
+ }
+
+ void SetUp() override {
+ ASSERT_NE(nullptr, mFactory);
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+
+ Parameter::Specific specific = getDefaultParamSpecific();
+ Parameter::Common common = EffectHelper::createParamCommon(
+ 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
+ kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
+ IEffect::OpenEffectReturn ret;
+ ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &ret, EX_NONE));
+ ASSERT_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 mDescriptor;
+ 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 descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
+ std::string strength = std::to_string(std::get<PARAM_STRENGTH>(info.param));
+ std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+ descriptor.common.name + "_UUID_" +
+ descriptor.common.id.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/VtsHalDownmixTargetTest.cpp b/audio/aidl/vts/VtsHalDownmixTargetTest.cpp
new file mode 100644
index 0000000..8612660
--- /dev/null
+++ b/audio/aidl/vts/VtsHalDownmixTargetTest.cpp
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "VtsHalDownmixTargetTest"
+
+#include <Utils.h>
+#include <aidl/Vintf.h>
+#include "EffectHelper.h"
+
+using namespace android;
+
+using aidl::android::hardware::audio::effect::Capability;
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::Downmix;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::kDownmixTypeUUID;
+using aidl::android::hardware::audio::effect::kEffectNullUuid;
+using aidl::android::hardware::audio::effect::Parameter;
+
+/**
+ * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
+ * VtsAudioEffectTargetTest.
+ */
+enum ParamName { PARAM_INSTANCE_NAME, PARAM_TYPE };
+using DownmixParamTestParam =
+ std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, Downmix::Type>;
+
+// Testing for enum values
+const std::vector<Downmix::Type> kTypeValues = {Downmix::Type::STRIP, Downmix::Type::FOLD};
+
+class DownmixParamTest : public ::testing::TestWithParam<DownmixParamTestParam>,
+ public EffectHelper {
+ public:
+ DownmixParamTest() : mParamType(std::get<PARAM_TYPE>(GetParam())) {
+ std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
+ }
+
+ void SetUp() override {
+ ASSERT_NE(nullptr, mFactory);
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+
+ Parameter::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));
+ }
+
+ static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+ std::shared_ptr<IFactory> mFactory;
+ std::shared_ptr<IEffect> mEffect;
+ Descriptor mDescriptor;
+ Downmix::Type mParamType = Downmix::Type::STRIP;
+
+ void SetAndGetDownmixParameters() {
+ for (auto& it : mTags) {
+ auto& tag = it.first;
+ auto& dm = it.second;
+
+ // set parameter
+ Parameter expectParam;
+ Parameter::Specific specific;
+ specific.set<Parameter::Specific::downmix>(dm);
+ expectParam.set<Parameter::specific>(specific);
+ // All values are valid, set parameter should succeed
+ EXPECT_STATUS(EX_NONE, mEffect->setParameter(expectParam)) << expectParam.toString();
+
+ // get parameter
+ Parameter getParam;
+ Parameter::Id id;
+ Downmix::Id dmId;
+ dmId.set<Downmix::Id::commonTag>(tag);
+ id.set<Parameter::Id::downmixTag>(dmId);
+ EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &getParam));
+
+ EXPECT_EQ(expectParam, getParam);
+ }
+ }
+
+ void addTypeParam(Downmix::Type type) {
+ Downmix dm;
+ dm.set<Downmix::type>(type);
+ mTags.push_back({Downmix::type, dm});
+ }
+
+ Parameter::Specific getDefaultParamSpecific() {
+ Downmix dm = Downmix::make<Downmix::type>(Downmix::Type::STRIP);
+ Parameter::Specific specific = Parameter::Specific::make<Parameter::Specific::downmix>(dm);
+ return specific;
+ }
+
+ private:
+ std::vector<std::pair<Downmix::Tag, Downmix>> mTags;
+ void CleanUp() { mTags.clear(); }
+};
+
+TEST_P(DownmixParamTest, SetAndGetType) {
+ EXPECT_NO_FATAL_FAILURE(addTypeParam(mParamType));
+ SetAndGetDownmixParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ DownmixTest, DownmixParamTest,
+ ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+ IFactory::descriptor, kDownmixTypeUUID)),
+ testing::ValuesIn(kTypeValues)),
+ [](const testing::TestParamInfo<DownmixParamTest::ParamType>& info) {
+ auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
+ std::string type = std::to_string(static_cast<int>(std::get<PARAM_TYPE>(info.param)));
+ std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+ descriptor.common.name + "_UUID_" +
+ descriptor.common.id.uuid.toString() + "_type" + type;
+ std::replace_if(
+ name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+ return name;
+ });
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DownmixParamTest);
+
+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..e11a936 100644
--- a/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp
@@ -57,8 +57,7 @@
*/
enum ParamName { PARAM_INSTANCE_NAME, PARAM_BAND_LEVEL };
-using EqualizerParamTestParam =
- std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor::Identity>, int>;
+using EqualizerParamTestParam = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>;
/*
Testing parameter range, assuming the parameter supported by effect is in this range.
@@ -71,12 +70,12 @@
public EffectHelper {
public:
EqualizerTest() : mBandLevel(std::get<PARAM_BAND_LEVEL>(GetParam())) {
- std::tie(mFactory, mIdentity) = std::get<PARAM_INSTANCE_NAME>(GetParam());
+ std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
}
void SetUp() override {
ASSERT_NE(nullptr, mFactory);
- ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mIdentity));
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
Parameter::Specific specific = getDefaultParamSpecific();
Parameter::Common common = EffectHelper::createParamCommon(
@@ -115,7 +114,7 @@
static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
std::shared_ptr<IFactory> mFactory;
std::shared_ptr<IEffect> mEffect;
- Descriptor::Identity mIdentity;
+ Descriptor mDescriptor;
std::pair<int, int> mPresetIndex;
std::pair<int, int> mBandIndex;
const int mBandLevel;
@@ -327,18 +326,11 @@
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);
+ auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
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 = "Implementor_" + descriptor.common.implementor + "_name_" +
+ descriptor.common.name + "_UUID_" +
+ descriptor.common.id.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/VtsHalHapticGeneratorTargetTest.cpp b/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp
new file mode 100644
index 0000000..a1daec2
--- /dev/null
+++ b/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "VtsHalHapticGeneratorTargetTest"
+
+#include <Utils.h>
+#include <aidl/Vintf.h>
+#include "EffectHelper.h"
+
+using namespace android;
+
+using aidl::android::hardware::audio::effect::Capability;
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::HapticGenerator;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::kHapticGeneratorTypeUUID;
+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_HAPTIC_SCALE_ID,
+ PARAM_HAPTIC_SCALE_VIBRATOR_SCALE,
+ PARAM_VIBRATION_INFORMATION_RESONANT_FREQUENCY,
+ PARAM_VIBRATION_INFORMATION_Q_FACTOR,
+ PARAM_VIBRATION_INFORMATION_MAX_AMPLITUDE,
+};
+using HapticGeneratorParamTestParam =
+ std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int,
+ HapticGenerator::VibratorScale, float, float, float>;
+
+/*
+ * 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.
+ */
+
+// TODO : Update the test values once range/capability is updated by implementation
+const int MIN_ID = std::numeric_limits<int>::min();
+const int MAX_ID = std::numeric_limits<int>::max();
+const float MIN_FLOAT = std::numeric_limits<float>::min();
+const float MAX_FLOAT = std::numeric_limits<float>::max();
+
+const std::vector<int> kHapticScaleIdValues = {MIN_ID, 0, MAX_ID};
+const std::vector<HapticGenerator::VibratorScale> kVibratorScaleValues = {
+ HapticGenerator::VibratorScale::MUTE, HapticGenerator::VibratorScale::VERY_LOW,
+ HapticGenerator::VibratorScale::LOW, HapticGenerator::VibratorScale::NONE,
+ HapticGenerator::VibratorScale::HIGH, HapticGenerator::VibratorScale::VERY_HIGH};
+
+const std::vector<float> kResonantFrequencyValues = {MIN_FLOAT, 100, MAX_FLOAT};
+const std::vector<float> kQFactorValues = {MIN_FLOAT, 100, MAX_FLOAT};
+const std::vector<float> kMaxAmplitude = {MIN_FLOAT, 100, MAX_FLOAT};
+
+class HapticGeneratorParamTest : public ::testing::TestWithParam<HapticGeneratorParamTestParam>,
+ public EffectHelper {
+ public:
+ HapticGeneratorParamTest()
+ : mParamHapticScaleId(std::get<PARAM_HAPTIC_SCALE_ID>(GetParam())),
+ mParamVibratorScale(std::get<PARAM_HAPTIC_SCALE_VIBRATOR_SCALE>(GetParam())),
+ mParamResonantFrequency(
+ std::get<PARAM_VIBRATION_INFORMATION_RESONANT_FREQUENCY>(GetParam())),
+ mParamQFactor(std::get<PARAM_VIBRATION_INFORMATION_Q_FACTOR>(GetParam())),
+ mParamMaxAmplitude(std::get<PARAM_VIBRATION_INFORMATION_MAX_AMPLITUDE>(GetParam())) {
+ std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
+ }
+ void SetUp() override {
+ ASSERT_NE(nullptr, mFactory);
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+
+ Parameter::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() {
+ HapticGenerator::HapticScale hapticScale = {.id = 0,
+ .scale = HapticGenerator::VibratorScale::MUTE};
+ HapticGenerator hg = HapticGenerator::make<HapticGenerator::hapticScale>(hapticScale);
+ Parameter::Specific specific =
+ Parameter::Specific::make<Parameter::Specific::hapticGenerator>(hg);
+ return specific;
+ }
+
+ static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+ std::shared_ptr<IFactory> mFactory;
+ std::shared_ptr<IEffect> mEffect;
+ Descriptor mDescriptor;
+ int mParamHapticScaleId = 0;
+ HapticGenerator::VibratorScale mParamVibratorScale = HapticGenerator::VibratorScale::MUTE;
+ float mParamResonantFrequency = 0;
+ float mParamQFactor = 0;
+ float mParamMaxAmplitude = 0;
+
+ void SetAndGetHapticGeneratorParameters() {
+ for (auto& it : mTags) {
+ auto& tag = it.first;
+ auto& hg = it.second;
+
+ // set parameter
+ Parameter expectParam;
+ Parameter::Specific specific;
+ specific.set<Parameter::Specific::hapticGenerator>(hg);
+ expectParam.set<Parameter::specific>(specific);
+ EXPECT_STATUS(EX_NONE, mEffect->setParameter(expectParam)) << expectParam.toString();
+
+ // get parameter
+ Parameter getParam;
+ Parameter::Id id;
+ HapticGenerator::Id hgId;
+ hgId.set<HapticGenerator::Id::commonTag>(tag);
+ id.set<Parameter::Id::hapticGeneratorTag>(hgId);
+ EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &getParam));
+ EXPECT_EQ(expectParam, getParam);
+ }
+ }
+
+ void addHapticScaleParam(int id, HapticGenerator::VibratorScale scale) {
+ HapticGenerator hg;
+ HapticGenerator::HapticScale hapticScale = {.id = id, .scale = scale};
+ hg.set<HapticGenerator::hapticScale>(hapticScale);
+ mTags.push_back({HapticGenerator::hapticScale, hg});
+ }
+
+ void addVibratorInformationParam(float resonantFrequencyHz, float qFactor, float maxAmplitude) {
+ HapticGenerator hg;
+ HapticGenerator::VibratorInformation vibrationInfo = {
+ .resonantFrequencyHz = resonantFrequencyHz,
+ .qFactor = qFactor,
+ .maxAmplitude = maxAmplitude};
+ hg.set<HapticGenerator::vibratorInfo>(vibrationInfo);
+ mTags.push_back({HapticGenerator::vibratorInfo, hg});
+ }
+
+ private:
+ std::vector<std::pair<HapticGenerator::Tag, HapticGenerator>> mTags;
+
+ void CleanUp() { mTags.clear(); }
+};
+
+TEST_P(HapticGeneratorParamTest, SetAndGetHapticScale) {
+ EXPECT_NO_FATAL_FAILURE(addHapticScaleParam(mParamHapticScaleId, mParamVibratorScale));
+ SetAndGetHapticGeneratorParameters();
+}
+
+TEST_P(HapticGeneratorParamTest, SetAndGetVibratorInformation) {
+ EXPECT_NO_FATAL_FAILURE(addVibratorInformationParam(mParamResonantFrequency, mParamQFactor,
+ mParamMaxAmplitude));
+ SetAndGetHapticGeneratorParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ HapticGeneratorValidTest, HapticGeneratorParamTest,
+ ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+ IFactory::descriptor, kHapticGeneratorTypeUUID)),
+ testing::ValuesIn(kHapticScaleIdValues),
+ testing::ValuesIn(kVibratorScaleValues),
+ testing::ValuesIn(kResonantFrequencyValues),
+ testing::ValuesIn(kQFactorValues), testing::ValuesIn(kMaxAmplitude)),
+ [](const testing::TestParamInfo<HapticGeneratorParamTest::ParamType>& info) {
+ auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
+ std::string hapticScaleID = std::to_string(std::get<PARAM_HAPTIC_SCALE_ID>(info.param));
+ std::string hapticScaleVibScale = std::to_string(
+ static_cast<int>(std::get<PARAM_HAPTIC_SCALE_VIBRATOR_SCALE>(info.param)));
+ std::string resonantFrequency = std::to_string(
+ std::get<PARAM_VIBRATION_INFORMATION_RESONANT_FREQUENCY>(info.param));
+ std::string qFactor =
+ std::to_string(std::get<PARAM_VIBRATION_INFORMATION_Q_FACTOR>(info.param));
+ std::string maxAmplitude =
+ std::to_string(std::get<PARAM_VIBRATION_INFORMATION_MAX_AMPLITUDE>(info.param));
+ std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+ descriptor.common.name + "_UUID_" +
+ descriptor.common.id.uuid.toString() + "_hapticScaleId" +
+ hapticScaleID + "_hapticScaleVibScale" + hapticScaleVibScale +
+ "_resonantFrequency" + resonantFrequency + "_qFactor" + qFactor +
+ "_maxAmplitude" + maxAmplitude;
+ std::replace_if(
+ name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+ return name;
+ });
+
+INSTANTIATE_TEST_SUITE_P(
+ HapticGeneratorInvalidTest, HapticGeneratorParamTest,
+ ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+ IFactory::descriptor, kHapticGeneratorTypeUUID)),
+ testing::Values(MIN_ID - 1),
+ testing::Values(HapticGenerator::VibratorScale::MUTE),
+ testing::Values(MIN_FLOAT), testing::Values(MIN_FLOAT),
+ testing::Values(MIN_FLOAT)),
+ [](const testing::TestParamInfo<HapticGeneratorParamTest::ParamType>& info) {
+ auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
+ std::string hapticScaleID = std::to_string(std::get<PARAM_HAPTIC_SCALE_ID>(info.param));
+ std::string hapticScaleVibScale = std::to_string(
+ static_cast<int>(std::get<PARAM_HAPTIC_SCALE_VIBRATOR_SCALE>(info.param)));
+ std::string resonantFrequency = std::to_string(
+ std::get<PARAM_VIBRATION_INFORMATION_RESONANT_FREQUENCY>(info.param));
+ std::string qFactor =
+ std::to_string(std::get<PARAM_VIBRATION_INFORMATION_Q_FACTOR>(info.param));
+ std::string maxAmplitude =
+ std::to_string(std::get<PARAM_VIBRATION_INFORMATION_MAX_AMPLITUDE>(info.param));
+ std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+ descriptor.common.name + "_UUID_" +
+ descriptor.common.id.uuid.toString() + "_hapticScaleId" +
+ hapticScaleID + "_hapticScaleVibScale" + hapticScaleVibScale +
+ "_resonantFrequency" + resonantFrequency + "_qFactor" + qFactor +
+ "_maxAmplitude" + maxAmplitude;
+ std::replace_if(
+ name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+ return name;
+ });
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(HapticGeneratorParamTest);
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ ABinderProcess_setThreadPoolMaxThreadCount(1);
+ ABinderProcess_startThreadPool();
+ return RUN_ALL_TESTS();
+}
diff --git a/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp b/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp
index 1485657..305c243 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"
@@ -37,7 +38,7 @@
*/
enum ParamName { PARAM_INSTANCE_NAME, PARAM_GAIN_MB };
using LoudnessEnhancerParamTestParam =
- std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor::Identity>, int>;
+ std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>;
// Every int 32 bit value is a valid gain, so testing the corner cases and one regular value.
// TODO : Update the test values once range/capability is updated by implementation.
@@ -48,12 +49,12 @@
public EffectHelper {
public:
LoudnessEnhancerParamTest() : mParamGainMb(std::get<PARAM_GAIN_MB>(GetParam())) {
- std::tie(mFactory, mIdentity) = std::get<PARAM_INSTANCE_NAME>(GetParam());
+ std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
}
void SetUp() override {
ASSERT_NE(nullptr, mFactory);
- ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mIdentity));
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
Parameter::Specific specific = getDefaultParamSpecific();
Parameter::Common common = EffectHelper::createParamCommon(
@@ -78,7 +79,7 @@
static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
std::shared_ptr<IFactory> mFactory;
std::shared_ptr<IEffect> mEffect;
- Descriptor::Identity mIdentity;
+ Descriptor mDescriptor;
int mParamGainMb = 0;
void SetAndGetParameters() {
@@ -129,19 +130,11 @@
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);
+ auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
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 = "Implementor_" + descriptor.common.implementor + "_name_" +
+ descriptor.common.name + "_UUID_" +
+ descriptor.common.id.uuid.toString() + "_gainMb_" + gainMb;
std::replace_if(
name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
return name;
diff --git a/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp b/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp
new file mode 100644
index 0000000..a7834fb
--- /dev/null
+++ b/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp
@@ -0,0 +1,329 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/Vintf.h>
+
+#define LOG_TAG "VtsHalVisualizerTest"
+
+#include <Utils.h>
+#include "EffectHelper.h"
+
+using namespace android;
+
+using aidl::android::hardware::audio::effect::Capability;
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::kVisualizerTypeUUID;
+using aidl::android::hardware::audio::effect::Parameter;
+using aidl::android::hardware::audio::effect::Visualizer;
+
+/**
+ * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
+ * VtsAudioEffectTargetTest.
+ */
+enum ParamName {
+ PARAM_INSTANCE_NAME,
+ PARAM_CAPTURE_SIZE,
+ PARAM_SCALING_MODE,
+ PARAM_MEASUREMENT_MODE,
+ PARAM_LATENCY,
+};
+using VisualizerParamTestParam =
+ std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int, Visualizer::ScalingMode,
+ Visualizer::MeasurementMode, int>;
+
+const int MIN_CAPTURE_SIZE = 128;
+const int MAX_CAPTURE_SIZE = 1024;
+const int MAX_LATENCY = 3000;
+
+const std::vector<int> kCaptureSizeValues = {MIN_CAPTURE_SIZE - 1, MIN_CAPTURE_SIZE,
+ MAX_CAPTURE_SIZE, MAX_CAPTURE_SIZE + 1};
+const std::vector<Visualizer::ScalingMode> kScalingModeValues = {
+ Visualizer::ScalingMode::NORMALIZED, Visualizer::ScalingMode::AS_PLAYED};
+const std::vector<Visualizer::MeasurementMode> kMeasurementModeValues = {
+ Visualizer::MeasurementMode::NONE, Visualizer::MeasurementMode::PEAK_RMS};
+const std::vector<int> kLatencyValues = {-1, 0, MAX_LATENCY, MAX_LATENCY + 1};
+
+class VisualizerParamTest : public ::testing::TestWithParam<VisualizerParamTestParam>,
+ public EffectHelper {
+ public:
+ VisualizerParamTest()
+ : mCaptureSize(std::get<PARAM_CAPTURE_SIZE>(GetParam())),
+ mScalingMode(std::get<PARAM_SCALING_MODE>(GetParam())),
+ mMeasurementMode(std::get<PARAM_MEASUREMENT_MODE>(GetParam())),
+ mLatency(std::get<PARAM_LATENCY>(GetParam())) {
+ std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
+ }
+
+ void SetUp() override {
+ ASSERT_NE(nullptr, mFactory);
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+
+ Parameter::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() {
+ Visualizer vs = Visualizer::make<Visualizer::captureSizeBytes>(MIN_CAPTURE_SIZE);
+ Parameter::Specific specific =
+ Parameter::Specific::make<Parameter::Specific::visualizer>(vs);
+ return specific;
+ }
+
+ static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+ std::shared_ptr<IFactory> mFactory;
+ std::shared_ptr<IEffect> mEffect;
+ Descriptor mDescriptor;
+ int mCaptureSize = MAX_CAPTURE_SIZE;
+ Visualizer::ScalingMode mScalingMode = Visualizer::ScalingMode::NORMALIZED;
+ Visualizer::MeasurementMode mMeasurementMode = Visualizer::MeasurementMode::NONE;
+ int mLatency = 0;
+
+ void SetAndGetCommonParameters() {
+ for (auto& it : mCommonTags) {
+ auto& tag = it.first;
+ auto& vs = it.second;
+
+ // validate parameter
+ Descriptor desc;
+ ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
+ const bool valid = isTagInRange(tag, vs, desc);
+ const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
+
+ // set parameter
+ Parameter expectParam;
+ Parameter::Specific specific;
+ specific.set<Parameter::Specific::visualizer>(vs);
+ 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;
+ Visualizer::Id vsId;
+ vsId.set<Visualizer::Id::commonTag>(tag);
+ id.set<Parameter::Id::visualizerTag>(vsId);
+ EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &getParam));
+
+ EXPECT_EQ(expectParam, getParam) << "\nexpect:" << expectParam.toString()
+ << "\ngetParam:" << getParam.toString();
+ }
+ }
+ }
+
+ void SetAndGetSetOnlyParameters() {
+ for (auto& it : mSetOnlyParamTags) {
+ auto& tag = it.first;
+ auto& vs = it.second;
+
+ // validate parameter
+ Descriptor desc;
+ ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
+ const bool valid = isSetOnlyParamTagInRange(tag, vs, desc);
+ const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
+
+ // set parameter
+ Parameter expectParam;
+ Parameter::Specific specific;
+ specific.set<Parameter::Specific::visualizer>(vs);
+ expectParam.set<Parameter::specific>(specific);
+ ASSERT_STATUS(expected, mEffect->setParameter(expectParam));
+
+ // parameter defined in this setOnlyParameter union must be settable via
+ // setParameter(), but must not be gettable
+ Parameter getParam;
+ Parameter::Id id;
+ Visualizer::Id vsId;
+ vsId.set<Visualizer::Id::setOnlyParamTag>(tag);
+ id.set<Parameter::Id::visualizerTag>(vsId);
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, mEffect->getParameter(id, &getParam));
+ }
+ }
+
+ void GetandSetGetOnlyParameters() {
+ for (auto& tag : mGetOnlyParamTags) {
+ // get parameter
+ Parameter getParam;
+ Parameter::Id id;
+ Visualizer::Id vsId;
+ vsId.set<Visualizer::Id::getOnlyParamTag>(tag);
+ id.set<Parameter::Id::visualizerTag>(vsId);
+ ASSERT_STATUS(EX_NONE, mEffect->getParameter(id, &getParam));
+
+ // parameter defined in this getOnlyParameter union must be gettable via
+ // getParameter(), but must not be settable
+ // set parameter
+ ASSERT_STATUS(EX_ILLEGAL_ARGUMENT, mEffect->setParameter(getParam));
+ }
+ }
+
+ void addCaptureSizeParam(int captureSize) {
+ Visualizer vs;
+ vs.set<Visualizer::captureSizeBytes>(captureSize);
+ mCommonTags.push_back({Visualizer::captureSizeBytes, vs});
+ }
+
+ void addScalingModeParam(Visualizer::ScalingMode scalingMode) {
+ Visualizer vs;
+ vs.set<Visualizer::scalingMode>(scalingMode);
+ mCommonTags.push_back({Visualizer::scalingMode, vs});
+ }
+
+ void addMeasurementModeParam(Visualizer::MeasurementMode measurementMode) {
+ Visualizer vs;
+ vs.set<Visualizer::measurementMode>(measurementMode);
+ mCommonTags.push_back({Visualizer::measurementMode, vs});
+ }
+
+ void addLatencyParam(int latency) {
+ Visualizer vs;
+ Visualizer::SetOnlyParameters setOnlyParam;
+ setOnlyParam.set<Visualizer::SetOnlyParameters::latencyMs>(latency);
+ vs.set<Visualizer::setOnlyParameters>(setOnlyParam);
+ mSetOnlyParamTags.push_back({Visualizer::SetOnlyParameters::latencyMs, vs});
+ }
+
+ void addMeasurementTag() {
+ mGetOnlyParamTags.push_back(Visualizer::GetOnlyParameters::measurement);
+ }
+
+ void addCaptureBytesTag() {
+ mGetOnlyParamTags.push_back(Visualizer::GetOnlyParameters::captureBytes);
+ }
+
+ bool isTagInRange(const Visualizer::Tag& tag, const Visualizer& vs,
+ const Descriptor& desc) const {
+ const Visualizer::Capability& vsCap = desc.capability.get<Capability::visualizer>();
+ switch (tag) {
+ case Visualizer::captureSizeBytes: {
+ int captureSize = vs.get<Visualizer::captureSizeBytes>();
+ return isCaptureSizeInRange(vsCap, captureSize);
+ }
+ case Visualizer::scalingMode:
+ case Visualizer::measurementMode:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ bool isSetOnlyParamTagInRange(Visualizer::SetOnlyParameters::Tag, const Visualizer& vs,
+ const Descriptor& desc) const {
+ const Visualizer::Capability& vsCap = desc.capability.get<Capability::visualizer>();
+ if (vs.getTag() != Visualizer::setOnlyParameters) return false;
+ Visualizer::SetOnlyParameters setOnlyParam = vs.get<Visualizer::setOnlyParameters>();
+ if (setOnlyParam.getTag() != Visualizer::SetOnlyParameters::latencyMs) return false;
+ int latency = setOnlyParam.get<Visualizer::SetOnlyParameters::latencyMs>();
+ return isLatencyInRange(vsCap, latency);
+ }
+
+ bool isCaptureSizeInRange(const Visualizer::Capability& cap, int captureSize) const {
+ return (captureSize >= cap.captureSizeRange.minBytes &&
+ captureSize <= cap.captureSizeRange.maxBytes);
+ }
+
+ bool isLatencyInRange(const Visualizer::Capability& cap, int latency) const {
+ return (latency >= 0 && latency <= cap.maxLatencyMs);
+ }
+
+ private:
+ std::vector<std::pair<Visualizer::Tag, Visualizer>> mCommonTags;
+ std::vector<std::pair<Visualizer::SetOnlyParameters::Tag, Visualizer>> mSetOnlyParamTags;
+ std::vector<Visualizer::GetOnlyParameters::Tag> mGetOnlyParamTags;
+ void CleanUp() {
+ mCommonTags.clear();
+ mSetOnlyParamTags.clear();
+ mGetOnlyParamTags.clear();
+ }
+};
+
+TEST_P(VisualizerParamTest, SetAndGetCaptureSize) {
+ EXPECT_NO_FATAL_FAILURE(addCaptureSizeParam(mCaptureSize));
+ SetAndGetCommonParameters();
+}
+
+TEST_P(VisualizerParamTest, SetAndGetScalingMode) {
+ EXPECT_NO_FATAL_FAILURE(addScalingModeParam(mScalingMode));
+ SetAndGetCommonParameters();
+}
+
+TEST_P(VisualizerParamTest, SetAndGetMeasurementMode) {
+ EXPECT_NO_FATAL_FAILURE(addMeasurementModeParam(mMeasurementMode));
+ SetAndGetCommonParameters();
+}
+
+TEST_P(VisualizerParamTest, SetAndGetLatency) {
+ EXPECT_NO_FATAL_FAILURE(addLatencyParam(mLatency));
+ SetAndGetSetOnlyParameters();
+}
+
+TEST_P(VisualizerParamTest, GetAndSetMeasurement) {
+ EXPECT_NO_FATAL_FAILURE(addMeasurementTag());
+ GetandSetGetOnlyParameters();
+}
+
+TEST_P(VisualizerParamTest, GetAndSetCaptureBytes) {
+ EXPECT_NO_FATAL_FAILURE(addCaptureBytesTag());
+ GetandSetGetOnlyParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ VisualizerTest, VisualizerParamTest,
+ ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+ IFactory::descriptor, kVisualizerTypeUUID)),
+ testing::ValuesIn(kCaptureSizeValues),
+ testing::ValuesIn(kScalingModeValues),
+ testing::ValuesIn(kMeasurementModeValues),
+ testing::ValuesIn(kLatencyValues)),
+ [](const testing::TestParamInfo<VisualizerParamTest::ParamType>& info) {
+ auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
+ std::string captureSize = std::to_string(std::get<PARAM_CAPTURE_SIZE>(info.param));
+ std::string scalingMode =
+ std::to_string(static_cast<int>(std::get<PARAM_SCALING_MODE>(info.param)));
+ std::string measurementMode =
+ std::to_string(static_cast<int>(std::get<PARAM_MEASUREMENT_MODE>(info.param)));
+ std::string latency = std::to_string(std::get<PARAM_LATENCY>(info.param));
+
+ std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+ descriptor.common.name + "_UUID_" +
+ descriptor.common.id.uuid.toString() + "_captureSize" + captureSize +
+ "_scalingMode" + scalingMode + "_measurementMode" + measurementMode +
+ "_latency" + latency;
+ std::replace_if(
+ name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+ return name;
+ });
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VisualizerParamTest);
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ ABinderProcess_setThreadPoolMaxThreadCount(1);
+ ABinderProcess_startThreadPool();
+ return RUN_ALL_TESTS();
+}
\ No newline at end of file
diff --git a/audio/common/all-versions/default/service/Android.bp b/audio/common/all-versions/default/service/Android.bp
index 9890be2..2fcfb23 100644
--- a/audio/common/all-versions/default/service/Android.bp
+++ b/audio/common/all-versions/default/service/Android.bp
@@ -38,9 +38,15 @@
name: "android.hardware.audio.service",
init_rc: ["android.hardware.audio.service.rc"],
+ vintf_fragments: ["android.hardware.audio.sounddose-aidl.xml"],
relative_install_path: "hw",
vendor: true,
+ defaults: [
+ "android_hardware_audio_config_defaults",
+ "latest_android_hardware_audio_sounddose_ndk_shared",
+ ],
+
srcs: ["service.cpp"],
cflags: [
@@ -50,6 +56,7 @@
],
shared_libs: [
+ "//hardware/interfaces/audio/aidl/sounddose/default:libsounddoseserviceexampleimpl",
"libcutils",
"libbinder",
"libbinder_ndk",
@@ -58,10 +65,6 @@
"libutils",
"libhardware",
],
-
- defaults: [
- "android_hardware_audio_config_defaults",
- ],
}
// Legacy service name, use android.hardware.audio.service instead
diff --git a/audio/common/all-versions/default/service/android.hardware.audio.service.rc b/audio/common/all-versions/default/service/android.hardware.audio.service.rc
index 45fef9a..0de4eea 100644
--- a/audio/common/all-versions/default/service/android.hardware.audio.service.rc
+++ b/audio/common/all-versions/default/service/android.hardware.audio.service.rc
@@ -3,7 +3,9 @@
user audioserver
# media gid needed for /dev/fm (radio) and for /data/misc/media (tee)
group audio camera drmrpc inet media mediadrm net_bt net_bt_admin net_bw_acct wakelock context_hub
- capabilities BLOCK_SUSPEND
+ capabilities BLOCK_SUSPEND SYS_NICE
+ # setting RLIMIT_RTPRIO allows binder RT priority inheritance
+ rlimit rtprio 10 10
ioprio rt 4
task_profiles ProcessCapacityHigh HighPerformance
onrestart restart audioserver
diff --git a/audio/common/all-versions/default/service/android.hardware.audio.sounddose-aidl.xml b/audio/common/all-versions/default/service/android.hardware.audio.sounddose-aidl.xml
new file mode 100644
index 0000000..a297bfb
--- /dev/null
+++ b/audio/common/all-versions/default/service/android.hardware.audio.sounddose-aidl.xml
@@ -0,0 +1,7 @@
+<manifest version="1.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.audio.sounddose</name>
+ <version>1</version>
+ <fqname>ISoundDoseFactory/default</fqname>
+ </hal>
+</manifest>
diff --git a/audio/common/all-versions/default/service/service.cpp b/audio/common/all-versions/default/service/service.cpp
index fbf6165..e79ad75 100644
--- a/audio/common/all-versions/default/service/service.cpp
+++ b/audio/common/all-versions/default/service/service.cpp
@@ -20,6 +20,10 @@
#include <string>
#include <vector>
+#include <SoundDoseFactory.h>
+#include <android-base/logging.h>
+#include <android/binder_ibinder_platform.h>
+#include <android/binder_manager.h>
#include <android/binder_process.h>
#include <binder/ProcessState.h>
#include <cutils/properties.h>
@@ -33,6 +37,8 @@
using InterfacesList = std::vector<std::string>;
+using aidl::android::hardware::audio::sounddose::SoundDoseFactory;
+
/** Try to register the provided factories in the provided order.
* If any registers successfully, do not register any other and return true.
* If all fail, return false.
@@ -164,5 +170,13 @@
}
}
+ // Register ISoundDoseFactory interface as a workaround for using the audio AIDL HAL
+ auto soundDoseDefault = ndk::SharedRefBase::make<SoundDoseFactory>();
+ const std::string soundDoseDefaultName =
+ std::string() + SoundDoseFactory::descriptor + "/default";
+ binder_status_t status = AServiceManager_addService(soundDoseDefault->asBinder().get(),
+ soundDoseDefaultName.c_str());
+ CHECK_EQ(STATUS_OK, status);
+
joinRpcThreadpool();
}
diff --git a/audio/core/all-versions/default/Device.cpp b/audio/core/all-versions/default/Device.cpp
index b954fcd..d03118a 100644
--- a/audio/core/all-versions/default/Device.cpp
+++ b/audio/core/all-versions/default/Device.cpp
@@ -30,6 +30,7 @@
#include <algorithm>
#include <android/log.h>
+#include <hidl/HidlTransportSupport.h>
#include <mediautils/MemoryLeakTrackUtil.h>
#include <memunreachable/memunreachable.h>
@@ -183,6 +184,7 @@
if (status == OK) {
streamOut = new StreamOut(this, halStream);
++mOpenedStreamsCount;
+ android::hardware::setMinSchedulerPolicy(streamOut, SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
}
status_t convertStatus =
HidlUtils::audioConfigFromHal(halConfig, false /*isInput*/, suggestedConfig);
@@ -220,6 +222,7 @@
if (status == OK) {
streamIn = new StreamIn(this, halStream);
++mOpenedStreamsCount;
+ android::hardware::setMinSchedulerPolicy(streamIn, SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
}
status_t convertStatus =
HidlUtils::audioConfigFromHal(halConfig, true /*isInput*/, suggestedConfig);
diff --git a/audio/core/all-versions/default/DevicesFactory.cpp b/audio/core/all-versions/default/DevicesFactory.cpp
index f44daf0..011f9ac 100644
--- a/audio/core/all-versions/default/DevicesFactory.cpp
+++ b/audio/core/all-versions/default/DevicesFactory.cpp
@@ -23,6 +23,8 @@
#include <string.h>
#include <android/log.h>
+#include <hidl/HidlTransportSupport.h>
+#include <system/thread_defs.h>
namespace android {
namespace hardware {
@@ -103,6 +105,7 @@
int halStatus = loadAudioInterface(moduleName, &halDevice);
if (halStatus == OK) {
result = new DeviceShim(halDevice);
+ android::hardware::setMinSchedulerPolicy(result, SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
retval = Result::OK;
} else if (halStatus == -EINVAL) {
retval = Result::NOT_INITIALIZED;
diff --git a/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
index 4b76a0b..719f752 100644
--- a/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
@@ -955,10 +955,16 @@
ASSERT_NO_FATAL_FAILURE(createPatchIfNeeded());
const int presentationeEndPrecisionMs = 1000;
const int sampleRate = 44100;
+ // The duration of sine882hz3s.mp3 is: 3 seconds + (576 + 756) samples.
+ // This is a mono file, thus 1 frame = 1 sample for it.
+ const int fullTrackDurationMs = 3000 + (576 + 756) * 1000 / sampleRate;
const int significantSampleNumber = (presentationeEndPrecisionMs * sampleRate) / 1000;
+ // 'delay' is the amount of frames ignored at the beginning, 'padding' is the amount of frames
+ // ignored at the end of the track. Extra 1000 samples are requested for trimming to reduce the
+ // test running time.
const int delay = 576 + 1000;
const int padding = 756 + 1000;
- const int durationMs = 3000 - 44;
+ const int durationMs = fullTrackDurationMs - (delay + padding) * 1000 / sampleRate;
auto start = std::chrono::steady_clock::now();
auto callbacks = sp<OffloadCallbacks>::make();
std::mutex presentationEndLock;
diff --git a/audio/core/all-versions/vts/functional/Android.bp b/audio/core/all-versions/vts/functional/Android.bp
index f51a8d0..9d93bb0 100644
--- a/audio/core/all-versions/vts/functional/Android.bp
+++ b/audio/core/all-versions/vts/functional/Android.bp
@@ -30,6 +30,7 @@
"android.hardware.audio.common.test.utility",
"audioclient-types-aidl-cpp",
"libaudioclient_aidl_conversion",
+ "libaudio_aidl_conversion_common_cpp",
"libstagefright_foundation",
],
shared_libs: [
diff --git a/audio/effect/all-versions/default/Effect.cpp b/audio/effect/all-versions/default/Effect.cpp
index 5dc42dc..87e1ab7 100644
--- a/audio/effect/all-versions/default/Effect.cpp
+++ b/audio/effect/all-versions/default/Effect.cpp
@@ -25,8 +25,11 @@
#define ATRACE_TAG ATRACE_TAG_AUDIO
#include <HidlUtils.h>
#include <android/log.h>
+#include <cutils/properties.h>
#include <media/EffectsFactoryApi.h>
#include <mediautils/ScopedStatistics.h>
+#include <sys/syscall.h>
+#include <system/audio_effects/effect_spatializer.h>
#include <util/EffectUtils.h>
#include <utils/Trace.h>
@@ -47,6 +50,160 @@
namespace {
+/**
+ * Some basic scheduling tools.
+ */
+namespace scheduler {
+
+int getCpu() {
+ return sched_getcpu();
+}
+
+uint64_t getAffinity(pid_t tid) {
+ cpu_set_t set;
+ CPU_ZERO_S(sizeof(set), &set);
+
+ if (sched_getaffinity(tid, sizeof(set), &set)) {
+ ALOGW("%s: for tid:%d returning 0, failed %s", __func__, tid, strerror(errno));
+ return 0;
+ }
+ const int count = CPU_COUNT_S(sizeof(set), &set);
+ uint64_t mask = 0;
+ for (int i = 0; i < CPU_SETSIZE; ++i) {
+ if (CPU_ISSET_S(i, sizeof(set), &set)) {
+ mask |= 1 << i;
+ }
+ }
+ ALOGV("%s: for tid:%d returning cpu count %d mask %llu", __func__, tid, count,
+ (unsigned long long)mask);
+ return mask;
+}
+
+status_t setAffinity(pid_t tid, uint64_t mask) {
+ cpu_set_t set;
+ CPU_ZERO_S(sizeof(set), &set);
+
+ for (uint64_t m = mask; m != 0;) {
+ uint64_t tz = __builtin_ctz(m);
+ CPU_SET_S(tz, sizeof(set), &set);
+ m &= ~(1 << tz);
+ }
+ if (sched_setaffinity(tid, sizeof(set), &set)) {
+ ALOGW("%s: for tid:%d setting cpu mask %llu failed %s", __func__, tid,
+ (unsigned long long)mask, strerror(errno));
+ return -errno;
+ }
+ ALOGV("%s: for tid:%d setting cpu mask %llu", __func__, tid, (unsigned long long)mask);
+ return OK;
+}
+
+__unused status_t setPriority(pid_t tid, int policy, int priority) {
+ struct sched_param param {
+ .sched_priority = priority,
+ };
+ if (sched_setscheduler(tid, policy, ¶m) != 0) {
+ ALOGW("%s: Cannot set FIFO priority for tid %d to policy %d priority %d %s", __func__, tid,
+ policy, priority, strerror(errno));
+ return -errno;
+ }
+ ALOGV("%s: Successfully set priority for tid %d to policy %d priority %d", __func__, tid,
+ policy, priority);
+ return NO_ERROR;
+}
+
+status_t setUtilMin(pid_t tid, uint32_t utilMin) {
+ // Currently, there is no wrapper in bionic: b/183240349.
+ struct {
+ uint32_t size;
+ uint32_t sched_policy;
+ uint64_t sched_flags;
+ int32_t sched_nice;
+ uint32_t sched_priority;
+ uint64_t sched_runtime;
+ uint64_t sched_deadline;
+ uint64_t sched_period;
+ uint32_t sched_util_min;
+ uint32_t sched_util_max;
+ } attr{
+ .size = sizeof(attr),
+ .sched_flags = SCHED_FLAG_KEEP_ALL | SCHED_FLAG_UTIL_CLAMP_MIN,
+ .sched_util_min = utilMin,
+ };
+
+ if (syscall(__NR_sched_setattr, tid, &attr, 0 /* flags */)) {
+ ALOGW("%s: Cannot set sched_util_min for pid %d to %u %s", __func__, tid, utilMin,
+ strerror(errno));
+ return -errno;
+ }
+ ALOGV("%s: Successfully set sched_util_min for pid %d to %u", __func__, tid, utilMin);
+ return NO_ERROR;
+}
+
+/*
+ Attempts to raise the priority and usage of tid for spatialization.
+ Returns OK if everything works.
+*/
+status_t updateSpatializerPriority(pid_t tid) {
+ status_t status = OK;
+
+ const int cpu = getCpu();
+ ALOGV("%s: current CPU:%d", __func__, cpu);
+
+ const auto currentAffinity = getAffinity(tid);
+ ALOGV("%s: current Affinity:%llx", __func__, (unsigned long long)currentAffinity);
+
+ // Set the desired CPU core affinity.
+ // Typically this would be done to move the Spatializer effect off of the little cores.
+ // The mid cores and large cores typically have more FP/NEON units
+ // and will advantageously reduce power and prevent glitches due CPU limitations.
+ //
+ // Since this is SOC dependent, we do not set the core affinity here but
+ // prefer to set the util_clamp_min below.
+ //
+ constexpr uint64_t kDefaultAffinity = 0;
+ const int32_t desiredAffinity =
+ property_get_int32("audio.spatializer.effect.affinity", kDefaultAffinity);
+ if (desiredAffinity != 0 && (desiredAffinity & ~currentAffinity) == 0) {
+ const status_t localStatus = setAffinity(tid, desiredAffinity);
+ status = status ? status : localStatus;
+ }
+
+ // Set the util_clamp_min.
+ // This is beneficial to reduce glitches when starting up, or due to scheduler
+ // thread statistics reset (e.g. core migration), which cause the CPU frequency to drop
+ // to minimum.
+ //
+ // Experimentation has found that moving to a mid core over a little core reduces
+ // power if the mid core (e.g. A76/78) has more (e.g. 2x) FP/NEON units
+ // than the little core (e.g. A55).
+ // A possible value is 300.
+ //
+ constexpr uint32_t kUtilMin = 0;
+ const int32_t utilMin = property_get_int32("audio.spatializer.effect.util_clamp_min", kUtilMin);
+ if (utilMin > 0 && utilMin <= 1024) {
+ const status_t localStatus = setUtilMin(tid, utilMin);
+ status = status ? status : localStatus;
+ }
+
+#if 0
+ // Provided for local vendor testing but not enabled as audioserver does this for us.
+ //
+ // Set priority if specified.
+ constexpr int32_t kRTPriorityMin = 1;
+ constexpr int32_t kRTPriorityMax = 3;
+ const int32_t priorityBoost =
+ property_get_int32("audio.spatializer.priority", kRTPriorityMin);
+ if (priorityBoost >= kRTPriorityMin && priorityBoost <= kRTPriorityMax) {
+ const status_t localStatus = scheduler::setPriority(threadId, SCHED_FIFO, priorityBoost);
+ status = status ? status : localStatus;
+ }
+#endif
+
+ return status;
+}
+
+} // namespace scheduler
+
#define SCOPED_STATS() \
::android::mediautils::ScopedStatistics scopedStatistics { \
std::string("EffectHal::").append(__func__), mEffectHal->mStatistics \
@@ -83,6 +240,16 @@
};
bool ProcessThread::threadLoop() {
+ // For a spatializer effect, we perform scheduler adjustments to reduce glitches and power.
+ {
+ effect_descriptor_t halDescriptor{};
+ if ((*mEffect)->get_descriptor(mEffect, &halDescriptor) == NO_ERROR &&
+ memcmp(&halDescriptor.type, FX_IID_SPATIALIZER, sizeof(effect_uuid_t)) == 0) {
+ const status_t status = scheduler::updateSpatializerPriority(gettid());
+ ALOGW_IF(status != OK, "Failed to update Spatializer priority");
+ }
+ }
+
// This implementation doesn't return control back to the Thread until it decides to stop,
// as the Thread uses mutexes, and this can lead to priority inversion.
while (!std::atomic_load_explicit(mStop, std::memory_order_acquire)) {
diff --git a/audio/effect/all-versions/default/EffectsFactory.cpp b/audio/effect/all-versions/default/EffectsFactory.cpp
index e93ad89..9bf309c 100644
--- a/audio/effect/all-versions/default/EffectsFactory.cpp
+++ b/audio/effect/all-versions/default/EffectsFactory.cpp
@@ -32,6 +32,7 @@
#include <UuidUtils.h>
#include <android/log.h>
+#include <hidl/HidlTransportSupport.h>
#include <media/EffectsFactoryApi.h>
#include <system/audio_effects/effect_aec.h>
#include <system/audio_effects/effect_agc.h>
@@ -44,6 +45,7 @@
#include <system/audio_effects/effect_presetreverb.h>
#include <system/audio_effects/effect_virtualizer.h>
#include <system/audio_effects/effect_visualizer.h>
+#include <system/thread_defs.h>
#include <util/EffectUtils.h>
namespace android {
@@ -189,6 +191,7 @@
status = (*handle)->get_descriptor(handle, &halDescriptor);
if (status == OK) {
effect = dispatchEffectInstanceCreation(halDescriptor, handle);
+ android::hardware::setMinSchedulerPolicy(effect, SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
effectId = EffectMap::getInstance().add(handle);
} else {
ALOGE("Error querying effect descriptor for %s: %s",
diff --git a/automotive/can/1.0/tools/configurator/canhalconfigurator.cpp b/automotive/can/1.0/tools/configurator/canhalconfigurator.cpp
index a100f06..3fb4259 100644
--- a/automotive/can/1.0/tools/configurator/canhalconfigurator.cpp
+++ b/automotive/can/1.0/tools/configurator/canhalconfigurator.cpp
@@ -70,6 +70,9 @@
static bool configuratorStart(const std::string& filepath) {
base::SetDefaultTag("CanConfigurator");
+ LOG(WARNING) << "The HIDL version of CAN HAL has been deprecated, if this tool fails with "
+ << "SIGABRT, you may need canhalconfigurator-aidl instead.";
+
auto pb_cfg = config::parseConfigFile(filepath);
if (!pb_cfg.has_value()) {
return false;
diff --git a/automotive/can/1.0/tools/libcanhaltools/libcanhaltools.cpp b/automotive/can/1.0/tools/libcanhaltools/libcanhaltools.cpp
index 9192e2f..fabe75f 100644
--- a/automotive/can/1.0/tools/libcanhaltools/libcanhaltools.cpp
+++ b/automotive/can/1.0/tools/libcanhaltools/libcanhaltools.cpp
@@ -34,8 +34,8 @@
auto manager = hidl::manager::V1_2::IServiceManager::getService();
hidl_vec<hidl_string> services;
manager->listManifestByInterface(ICanController::descriptor, hidl_utils::fill(&services));
- CHECK(services.size() > 0) << "No ICanController services registered (missing privileges?)"
- << std::endl;
+ CHECK(services.size() > 0) << "No ICanController services registered (missing privileges?). "
+ << "are you using the AIDL CanController?" << std::endl;
return services;
}
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/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
index 18a3329..9c8bfc4 100644
--- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
+++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
@@ -630,29 +630,29 @@
targetDisplayId = ids[0];
});
- // Request exclusive access to the first EVS display
- sp<IEvsDisplay_1_1> pDisplay = pEnumerator->openDisplay_1_1(targetDisplayId);
- ASSERT_NE(pDisplay, nullptr);
- LOG(INFO) << "Display " << targetDisplayId << " is alreay in use.";
-
- // Get the display descriptor
- pDisplay->getDisplayInfo_1_1([](const HwDisplayConfig& config, const HwDisplayState& state) {
- ASSERT_GT(config.size(), 0);
- ASSERT_GT(state.size(), 0);
-
- android::ui::DisplayMode* pConfig = (android::ui::DisplayMode*)config.data();
- const auto width = pConfig->resolution.getWidth();
- const auto height = pConfig->resolution.getHeight();
- LOG(INFO) << " Resolution: " << width << "x" << height;
- ASSERT_GT(width, 0);
- ASSERT_GT(height, 0);
-
- android::ui::DisplayState* pState = (android::ui::DisplayState*)state.data();
- ASSERT_NE(pState->layerStack, android::ui::INVALID_LAYER_STACK);
- });
-
// Test each reported camera
for (auto&& cam: cameraInfo) {
+ // Request exclusive access to the first EVS display
+ sp<IEvsDisplay_1_1> pDisplay = pEnumerator->openDisplay_1_1(targetDisplayId);
+ ASSERT_NE(pDisplay, nullptr);
+ LOG(INFO) << "Display " << targetDisplayId << " is already in use.";
+
+ // Get the display descriptor
+ pDisplay->getDisplayInfo_1_1([](const HwDisplayConfig& config, const HwDisplayState& state) {
+ ASSERT_GT(config.size(), 0);
+ ASSERT_GT(state.size(), 0);
+
+ android::ui::DisplayMode* pConfig = (android::ui::DisplayMode*)config.data();
+ const auto width = pConfig->resolution.getWidth();
+ const auto height = pConfig->resolution.getHeight();
+ LOG(INFO) << " Resolution: " << width << "x" << height;
+ ASSERT_GT(width, 0);
+ ASSERT_GT(height, 0);
+
+ android::ui::DisplayState* pState = (android::ui::DisplayState*)state.data();
+ ASSERT_NE(pState->layerStack, android::ui::INVALID_LAYER_STACK);
+ });
+
bool isLogicalCam = false;
getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
if (mIsHwModule && isLogicalCam) {
@@ -707,10 +707,10 @@
// Explicitly release the camera
pEnumerator->closeCamera(pCam);
activeCameras.clear();
- }
- // Explicitly release the display
- pEnumerator->closeDisplay(pDisplay);
+ // Explicitly release the display
+ pEnumerator->closeDisplay(pDisplay);
+ }
}
@@ -1631,12 +1631,12 @@
// Get the camera list
loadCameraList();
- // Request exclusive access to the EVS display
- sp<IEvsDisplay_1_0> pDisplay = pEnumerator->openDisplay();
- ASSERT_NE(pDisplay, nullptr);
-
// Test each reported camera
for (auto&& cam: cameraInfo) {
+ // Request exclusive access to the EVS display
+ sp<IEvsDisplay_1_0> pDisplay = pEnumerator->openDisplay();
+ ASSERT_NE(pDisplay, nullptr);
+
// Read a target resolution from the metadata
Stream targetCfg =
getFirstStreamConfiguration(reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
@@ -1978,10 +1978,9 @@
pEnumerator->closeCamera(pCam1);
activeCameras.clear();
+ // Explicitly release the display
+ pEnumerator->closeDisplay(pDisplay);
}
-
- // Explicitly release the display
- pEnumerator->closeDisplay(pDisplay);
}
@@ -1997,12 +1996,12 @@
// Get the camera list
loadCameraList();
- // Request exclusive access to the EVS display
- sp<IEvsDisplay_1_0> pDisplay = pEnumerator->openDisplay();
- ASSERT_NE(pDisplay, nullptr);
-
// Test each reported camera
for (auto&& cam: cameraInfo) {
+ // Request exclusive access to the EVS display
+ sp<IEvsDisplay_1_0> pDisplay = pEnumerator->openDisplay();
+ ASSERT_NE(pDisplay, nullptr);
+
// choose a configuration that has a frame rate faster than minReqFps.
Stream targetCfg = {};
const int32_t minReqFps = 15;
@@ -2078,10 +2077,10 @@
// Explicitly release the camera
pEnumerator->closeCamera(pCam);
activeCameras.clear();
- }
- // Explicitly release the display
- pEnumerator->closeDisplay(pDisplay);
+ // Explicitly release the display
+ pEnumerator->closeDisplay(pDisplay);
+ }
}
diff --git a/automotive/evs/aidl/vts/VtsHalEvsTargetTest.cpp b/automotive/evs/aidl/vts/VtsHalEvsTargetTest.cpp
index 3ea1eaa..3cab204 100644
--- a/automotive/evs/aidl/vts/VtsHalEvsTargetTest.cpp
+++ b/automotive/evs/aidl/vts/VtsHalEvsTargetTest.cpp
@@ -600,21 +600,21 @@
EXPECT_GT(displayIds.size(), 0);
targetDisplayId = displayIds[0];
- // Request exclusive access to the first EVS display
- std::shared_ptr<IEvsDisplay> pDisplay;
- ASSERT_TRUE(mEnumerator->openDisplay(targetDisplayId, &pDisplay).isOk());
- EXPECT_NE(pDisplay, nullptr);
- LOG(INFO) << "Display " << static_cast<int>(targetDisplayId) << " is in use.";
-
- // Get the display descriptor
- DisplayDesc displayDesc;
- ASSERT_TRUE(pDisplay->getDisplayInfo(&displayDesc).isOk());
- LOG(INFO) << " Resolution: " << displayDesc.width << "x" << displayDesc.height;
- ASSERT_GT(displayDesc.width, 0);
- ASSERT_GT(displayDesc.height, 0);
-
// Test each reported camera
for (auto&& cam : mCameraInfo) {
+ // Request exclusive access to the first EVS display
+ std::shared_ptr<IEvsDisplay> pDisplay;
+ ASSERT_TRUE(mEnumerator->openDisplay(targetDisplayId, &pDisplay).isOk());
+ EXPECT_NE(pDisplay, nullptr);
+ LOG(INFO) << "Display " << static_cast<int>(targetDisplayId) << " is in use.";
+
+ // Get the display descriptor
+ DisplayDesc displayDesc;
+ ASSERT_TRUE(pDisplay->getDisplayInfo(&displayDesc).isOk());
+ LOG(INFO) << " Resolution: " << displayDesc.width << "x" << displayDesc.height;
+ ASSERT_GT(displayDesc.width, 0);
+ ASSERT_GT(displayDesc.height, 0);
+
bool isLogicalCam = false;
getPhysicalCameraIds(cam.id, isLogicalCam);
if (mIsHwModule && isLogicalCam) {
@@ -668,10 +668,10 @@
// Explicitly release the camera
ASSERT_TRUE(mEnumerator->closeCamera(pCam).isOk());
mActiveCameras.clear();
- }
- // Explicitly release the display
- ASSERT_TRUE(mEnumerator->closeDisplay(pDisplay).isOk());
+ // Explicitly release the display
+ ASSERT_TRUE(mEnumerator->closeDisplay(pDisplay).isOk());
+ }
}
/*
@@ -1395,20 +1395,20 @@
// Get the camera list
loadCameraList();
- // Request available display IDs
- uint8_t targetDisplayId = 0;
- std::vector<uint8_t> displayIds;
- ASSERT_TRUE(mEnumerator->getDisplayIdList(&displayIds).isOk());
- EXPECT_GT(displayIds.size(), 0);
- targetDisplayId = displayIds[0];
-
- // Request exclusive access to the EVS display
- std::shared_ptr<IEvsDisplay> pDisplay;
- ASSERT_TRUE(mEnumerator->openDisplay(targetDisplayId, &pDisplay).isOk());
- EXPECT_NE(pDisplay, nullptr);
-
// Test each reported camera
for (auto&& cam : mCameraInfo) {
+ // Request available display IDs
+ uint8_t targetDisplayId = 0;
+ std::vector<uint8_t> displayIds;
+ ASSERT_TRUE(mEnumerator->getDisplayIdList(&displayIds).isOk());
+ EXPECT_GT(displayIds.size(), 0);
+ targetDisplayId = displayIds[0];
+
+ // Request exclusive access to the EVS display
+ std::shared_ptr<IEvsDisplay> pDisplay;
+ ASSERT_TRUE(mEnumerator->openDisplay(targetDisplayId, &pDisplay).isOk());
+ EXPECT_NE(pDisplay, nullptr);
+
// Read a target resolution from the metadata
Stream targetCfg = getFirstStreamConfiguration(
reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
@@ -1687,10 +1687,10 @@
ASSERT_TRUE(mEnumerator->closeCamera(pCam0).isOk());
ASSERT_TRUE(mEnumerator->closeCamera(pCam1).isOk());
mActiveCameras.clear();
- }
- // Explicitly release the display
- ASSERT_TRUE(mEnumerator->closeDisplay(pDisplay).isOk());
+ // Explicitly release the display
+ ASSERT_TRUE(mEnumerator->closeDisplay(pDisplay).isOk());
+ }
}
/*
@@ -1712,13 +1712,13 @@
EXPECT_GT(displayIds.size(), 0);
targetDisplayId = displayIds[0];
- // Request exclusive access to the EVS display
- std::shared_ptr<IEvsDisplay> pDisplay;
- ASSERT_TRUE(mEnumerator->openDisplay(targetDisplayId, &pDisplay).isOk());
- EXPECT_NE(pDisplay, nullptr);
-
// Test each reported camera
for (auto&& cam : mCameraInfo) {
+ // Request exclusive access to the EVS display
+ std::shared_ptr<IEvsDisplay> pDisplay;
+ ASSERT_TRUE(mEnumerator->openDisplay(targetDisplayId, &pDisplay).isOk());
+ EXPECT_NE(pDisplay, nullptr);
+
// choose a configuration that has a frame rate faster than minReqFps.
Stream targetCfg = {};
const int32_t minReqFps = 15;
@@ -1791,10 +1791,10 @@
// Explicitly release the camera
ASSERT_TRUE(mEnumerator->closeCamera(pCam).isOk());
mActiveCameras.clear();
- }
- // Explicitly release the display
- ASSERT_TRUE(mEnumerator->closeDisplay(pDisplay).isOk());
+ // Explicitly release the display
+ ASSERT_TRUE(mEnumerator->closeDisplay(pDisplay).isOk());
+ }
}
/*
diff --git a/automotive/remoteaccess/hal/default/Android.bp b/automotive/remoteaccess/hal/default/Android.bp
index a2bf86c..f27b8f8 100644
--- a/automotive/remoteaccess/hal/default/Android.bp
+++ b/automotive/remoteaccess/hal/default/Android.bp
@@ -18,11 +18,9 @@
default_applicable_licenses: ["Android-Apache-2.0"],
}
-cc_binary {
- name: "android.hardware.automotive.remoteaccess@V1-default-service",
+cc_defaults {
+ name: "remote-access-hal-defaults",
vendor: true,
- vintf_fragments: ["remoteaccess-default-service.xml"],
- init_rc: ["remoteaccess-default-service.rc"],
relative_install_path: "hw",
srcs: ["src/RemoteAccessImpl.cpp"],
whole_static_libs: [
@@ -41,10 +39,29 @@
],
cflags: [
"-Wno-unused-parameter",
+ ],
+}
+
+cc_binary {
+ name: "android.hardware.automotive.remoteaccess@V1-default-service",
+ defaults: ["remote-access-hal-defaults"],
+ vintf_fragments: ["remoteaccess-default-service.xml"],
+ init_rc: ["remoteaccess-default-service.rc"],
+ cflags: [
"-DGRPC_SERVICE_ADDRESS=\"localhost:50051\"",
],
}
+cc_binary {
+ name: "android.hardware.automotive.remoteaccess@V1-tcu-test-service",
+ defaults: ["remote-access-hal-defaults"],
+ vintf_fragments: ["remoteaccess-default-service.xml"],
+ init_rc: ["remoteaccess-tcu-test-service.rc"],
+ cflags: [
+ "-DGRPC_SERVICE_ADDRESS=\"10.10.10.1:50051\"",
+ ],
+}
+
cc_library {
name: "RemoteAccessService",
vendor_available: true,
diff --git a/automotive/remoteaccess/hal/default/remoteaccess-tcu-test-service.rc b/automotive/remoteaccess/hal/default/remoteaccess-tcu-test-service.rc
new file mode 100644
index 0000000..6437d70
--- /dev/null
+++ b/automotive/remoteaccess/hal/default/remoteaccess-tcu-test-service.rc
@@ -0,0 +1,4 @@
+service vendor.remoteaccess-default /vendor/bin/hw/android.hardware.automotive.remoteaccess@V1-tcu-test-service
+ class hal
+ user vehicle_network
+ group system inet
diff --git a/automotive/remoteaccess/hal/default/src/RemoteAccessService.cpp b/automotive/remoteaccess/hal/default/src/RemoteAccessService.cpp
index 5cd58d3..4be30a2 100644
--- a/automotive/remoteaccess/hal/default/src/RemoteAccessService.cpp
+++ b/automotive/remoteaccess/hal/default/src/RemoteAccessService.cpp
@@ -111,7 +111,9 @@
// Try to stop the reading stream.
if (mGetRemoteTasksContext) {
mGetRemoteTasksContext->TryCancel();
- mGetRemoteTasksContext.reset();
+ // Don't reset mGetRemoteTaskContext here since the read stream might still be affective
+ // and might still be using it. This will cause reader->Read to return false and
+ // mGetRemoteTasksContext will be cleared after reader->Finish() is called.
}
mTaskWaitStopped = true;
mCv.notify_all();
@@ -155,6 +157,7 @@
}
}
Status status = reader->Finish();
+ mGetRemoteTasksContext.reset();
ALOGE("GetRemoteTasks stream breaks, code: %d, message: %s, sleeping for 10s and retry",
status.error_code(), status.error_message().c_str());
diff --git a/automotive/remoteaccess/test_grpc_server/README.md b/automotive/remoteaccess/test_grpc_server/README.md
index 6bc1829..af3d54a 100644
--- a/automotive/remoteaccess/test_grpc_server/README.md
+++ b/automotive/remoteaccess/test_grpc_server/README.md
@@ -75,11 +75,18 @@
* Under android root: `source build/envsetup.sh`
+* Add
+ ```
+ PRODUCT_SOONG_NAMESPACES += hardware/interfaces/automotive/remoteaccess/test_grpc_server/lib`
+ ```
+
+ to `device/generic/car/common/car.mk`.
+
* `lunch sdk_car_x86_64-userdebug`
* `make -j TestWakeupClientServer`
-* `make -j ApPowerControlLib`
+* `make -j ApPOwerControlLib`
## How to push the test wakeup client to a TCU which runs Android.
@@ -99,7 +106,7 @@
* `adb push vendor/bin/TestWakeupClientServer /vendor/bin`
-* `adb push vendor/lib/ApPowerControlLib.so /vendor/lib`
+* `adb push vendor/lib64/ApPowerControlLib.so /vendor/lib64`
* `adb shell`
@@ -116,6 +123,13 @@
* Under android root, `source build/envsetup.sh`
+* Add
+ ```
+ PRODUCT_SOONG_NAMESPACES += hardware/interfaces/automotive/remoteaccess/test_grpc_server/lib`
+ ```
+
+ to `device/generic/car/common/car.mk`.
+
* `lunch sdk_car_x86_64-userdebug`
* `m -j`
@@ -150,8 +164,12 @@
* `make -j TestWakeupClientServer`
+* `make -j ApPOwerControlLib`
+
* `adb push $ANDROID_PRODUCT_OUT/vendor/bin/TestWakeupClientServer /vendor/bin`
+* `adb push $ANDROID_PRODUCT_OUT/vendor/lib64/ApPowerControlLib.so /vendor/lib64`
+
* `adb shell`
* `emulator_car_x86_64:/ # su`
diff --git a/automotive/remoteaccess/test_grpc_server/impl/src/main.cpp b/automotive/remoteaccess/test_grpc_server/impl/src/main.cpp
index 52698b5..d3f519c 100644
--- a/automotive/remoteaccess/test_grpc_server/impl/src/main.cpp
+++ b/automotive/remoteaccess/test_grpc_server/impl/src/main.cpp
@@ -28,20 +28,23 @@
using ::grpc::ServerBuilder;
using ::grpc::ServerWriter;
-void RunServer() {
- std::string serverAddress(GRPC_SERVICE_ADDRESS);
+void RunServer(const std::string& serviceAddr) {
std::shared_ptr<TestWakeupClientServiceImpl> service =
std::make_unique<TestWakeupClientServiceImpl>();
ServerBuilder builder;
- builder.AddListeningPort(serverAddress, grpc::InsecureServerCredentials());
+ builder.AddListeningPort(serviceAddr, grpc::InsecureServerCredentials());
builder.RegisterService(service.get());
std::unique_ptr<Server> server(builder.BuildAndStart());
- printf("Test Remote Access GRPC Server listening on %s\n", serverAddress.c_str());
+ printf("Test Remote Access GRPC Server listening on %s\n", serviceAddr.c_str());
server->Wait();
}
int main(int argc, char** argv) {
- RunServer();
+ std::string serviceAddr = GRPC_SERVICE_ADDRESS;
+ if (argc > 1) {
+ serviceAddr = argv[1];
+ }
+ RunServer(serviceAddr);
return 0;
}
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/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl
index b93a11b..6960894 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl
@@ -41,4 +41,5 @@
long maxInt64Value;
float minFloatValue;
float maxFloatValue;
+ @nullable long[] supportedEnumValues;
}
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleDisplay.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleDisplay.aidl
index 5aeafa4..be335ec 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleDisplay.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleDisplay.aidl
@@ -36,4 +36,7 @@
enum VehicleDisplay {
MAIN = 0,
INSTRUMENT_CLUSTER = 1,
+ HUD = 2,
+ INPUT = 3,
+ AUXILIARY = 4,
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleHwMotionButtonStateFlag.aidl
similarity index 75%
copy from audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
copy to automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleHwMotionButtonStateFlag.aidl
index 8ad4848..a7fee08 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleHwMotionButtonStateFlag.aidl
@@ -31,27 +31,14 @@
// with such a backward incompatible 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.vehicle;
+@Backing(type="int") @VintfStability
+enum VehicleHwMotionButtonStateFlag {
+ BUTTON_PRIMARY = 1,
+ BUTTON_SECONDARY = 2,
+ BUTTON_TERTIARY = 4,
+ BUTTON_BACK = 8,
+ BUTTON_FORWARD = 16,
+ BUTTON_STYLUS_PRIMARY = 32,
+ BUTTON_STYLUS_SECONDARY = 64,
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleHwMotionInputAction.aidl
similarity index 75%
copy from audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
copy to automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleHwMotionInputAction.aidl
index 8ad4848..db4b41e 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleHwMotionInputAction.aidl
@@ -31,27 +31,20 @@
// with such a backward incompatible 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.vehicle;
+@Backing(type="int") @VintfStability
+enum VehicleHwMotionInputAction {
+ ACTION_DOWN = 0,
+ ACTION_UP = 1,
+ ACTION_MOVE = 2,
+ ACTION_CANCEL = 3,
+ ACTION_OUTSIDE = 4,
+ ACTION_POINTER_DOWN = 5,
+ ACTION_POINTER_UP = 6,
+ ACTION_HOVER_MOVE = 7,
+ ACTION_SCROLL = 8,
+ ACTION_HOVER_ENTER = 9,
+ ACTION_HOVER_EXIT = 10,
+ ACTION_BUTTON_PRESS = 11,
+ ACTION_BUTTON_RELEASE = 12,
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleHwMotionInputSource.aidl
similarity index 75%
copy from audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
copy to automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleHwMotionInputSource.aidl
index 8ad4848..88c7873 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleHwMotionInputSource.aidl
@@ -31,27 +31,23 @@
// with such a backward incompatible 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.vehicle;
+@Backing(type="int") @VintfStability
+enum VehicleHwMotionInputSource {
+ SOURCE_UNKNOWN = 0,
+ SOURCE_KEYBOARD = 1,
+ SOURCE_DPAD = 2,
+ SOURCE_GAMEPAD = 3,
+ SOURCE_TOUCHSCREEN = 4,
+ SOURCE_MOUSE = 5,
+ SOURCE_STYLUS = 6,
+ SOURCE_BLUETOOTH_STYLUS = 7,
+ SOURCE_TRACKBALL = 8,
+ SOURCE_MOUSE_RELATIVE = 9,
+ SOURCE_TOUCHPAD = 10,
+ SOURCE_TOUCH_NAVIGATION = 11,
+ SOURCE_ROTARY_ENCODER = 12,
+ SOURCE_JOYSTICK = 13,
+ SOURCE_HDMI = 14,
+ SOURCE_SENSOR = 15,
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleHwMotionToolType.aidl
similarity index 72%
copy from audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
copy to automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleHwMotionToolType.aidl
index 8ad4848..2b3bc7f 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleHwMotionToolType.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -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;
-@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.vehicle;
+@Backing(type="int") @VintfStability
+enum VehicleHwMotionToolType {
+ TOOL_TYPE_UNKNOWN = 0,
+ TOOL_TYPE_FINGER = 1,
+ TOOL_TYPE_STYLUS = 2,
+ TOOL_TYPE_MOUSE = 3,
+ TOOL_TYPE_ERASER = 4,
}
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleProperty.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleProperty.aidl
index 24fd518..219ea3d 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleProperty.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleProperty.aidl
@@ -61,6 +61,7 @@
FUEL_LEVEL = 291504903,
FUEL_DOOR_OPEN = 287310600,
EV_BATTERY_LEVEL = 291504905,
+ EV_CURRENT_BATTERY_CAPACITY = 291504909,
EV_CHARGE_PORT_OPEN = 287310602,
EV_CHARGE_PORT_CONNECTED = 287310603,
EV_BATTERY_INSTANTANEOUS_CHARGE_RATE = 291504908,
@@ -71,6 +72,7 @@
CURRENT_GEAR = 289408001,
PARKING_BRAKE_ON = 287310850,
PARKING_BRAKE_AUTO_APPLY = 287310851,
+ EV_BRAKE_REGENERATION_LEVEL = 289408012,
FUEL_LEVEL_LOW = 287310853,
NIGHT_MODE = 287310855,
TURN_SIGNAL_STATE = 289408008,
@@ -114,6 +116,8 @@
AP_POWER_BOOTUP_REASON = 289409538,
DISPLAY_BRIGHTNESS = 289409539,
HW_KEY_INPUT = 289475088,
+ HW_KEY_INPUT_V2 = 367004177,
+ HW_MOTION_INPUT = 367004178,
HW_ROTARY_INPUT = 289475104,
HW_CUSTOM_INPUT = 289475120,
DOOR_POS = 373295872,
@@ -224,4 +228,5 @@
VEHICLE_CURB_WEIGHT = 289410886,
GENERAL_SAFETY_REGULATION_COMPLIANCE_REQUIREMENT = 289410887,
SUPPORTED_PROPERTY_IDS = 289476424,
+ SHUTDOWN_REQUEST = 289410889,
}
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl
index b44996d..abd9540 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl
@@ -40,4 +40,11 @@
float minFloatValue;
float maxFloatValue;
+
+ /**
+ * If the property has a @data_enum, then it is possible to specify a supported subset of the
+ * @data_enum. If the property has a @data_enum and supportedEnumValues is null, then it is
+ * assumed all @data_enum values are supported unless specified through another mechanism.
+ */
+ @nullable long[] supportedEnumValues;
}
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleDisplay.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleDisplay.aidl
index 1759a90..6642eee 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleDisplay.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleDisplay.aidl
@@ -23,5 +23,21 @@
* The primary Android display (for example, center console)
*/
MAIN = 0,
+ /**
+ * Instrument cluster display. This may exist only for driver
+ */
INSTRUMENT_CLUSTER = 1,
+
+ /**
+ * Head Up Display. This may exist only for driver
+ */
+ HUD = 2,
+ /**
+ * Dedicated display for showing IME for {@code MAIN}
+ */
+ INPUT = 3,
+ /**
+ * Auxiliary display which can provide additional screen for {@code MAIN} display
+ */
+ AUXILIARY = 4,
}
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleHwMotionButtonStateFlag.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleHwMotionButtonStateFlag.aidl
new file mode 100644
index 0000000..5313a55
--- /dev/null
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleHwMotionButtonStateFlag.aidl
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.vehicle;
+
+/**
+ * See {@code android.view.MotionEvent#getButtonState()} for more details.
+ */
+@VintfStability
+@Backing(type="int")
+enum VehicleHwMotionButtonStateFlag {
+ /**
+ * Button state primary
+ */
+ BUTTON_PRIMARY = 0x0001,
+ /**
+ * Button state secondary
+ */
+ BUTTON_SECONDARY = 0x0002,
+ /**
+ * Button state tertiary
+ */
+ BUTTON_TERTIARY = 0x0004,
+ /**
+ * Button state back
+ */
+ BUTTON_BACK = 0x0008,
+ /**
+ * Button state forward
+ */
+ BUTTON_FORWARD = 0x0010,
+ /**
+ * Button state stylus primary
+ */
+ BUTTON_STYLUS_PRIMARY = 0x0020,
+ /**
+ * Button state stylus secondary
+ */
+ BUTTON_STYLUS_SECONDARY = 0x0040,
+}
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleHwMotionInputAction.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleHwMotionInputAction.aidl
new file mode 100644
index 0000000..d80119a
--- /dev/null
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleHwMotionInputAction.aidl
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.vehicle;
+
+/**
+ * See {@code android.view.MotionEvent#ACTION_*} fields for more details.
+ */
+@VintfStability
+@Backing(type="int")
+enum VehicleHwMotionInputAction {
+ /**
+ * Motion down
+ */
+ ACTION_DOWN = 0,
+ /**
+ * Motion up
+ */
+ ACTION_UP = 1,
+ /**
+ * Motion move
+ */
+ ACTION_MOVE = 2,
+ /**
+ * Motion cancel
+ */
+ ACTION_CANCEL = 3,
+ /**
+ * Motion outside
+ */
+ ACTION_OUTSIDE = 4,
+ /**
+ * Motion pointer down
+ */
+ ACTION_POINTER_DOWN = 5,
+ /**
+ * Motion pointer up
+ */
+ ACTION_POINTER_UP = 6,
+ /**
+ * Motion hover move
+ */
+ ACTION_HOVER_MOVE = 7,
+ /**
+ * Motion scroll
+ */
+ ACTION_SCROLL = 8,
+ /**
+ * Motion hover enter
+ */
+ ACTION_HOVER_ENTER = 9,
+ /**
+ * Motion hover exit
+ */
+ ACTION_HOVER_EXIT = 10,
+ /**
+ * Motion button press
+ */
+ ACTION_BUTTON_PRESS = 11,
+ /**
+ * Motion button release
+ */
+ ACTION_BUTTON_RELEASE = 12,
+}
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleHwMotionInputSource.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleHwMotionInputSource.aidl
new file mode 100644
index 0000000..fb79983
--- /dev/null
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleHwMotionInputSource.aidl
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.vehicle;
+
+/**
+ * See {@code android.view.InputDevice#SOURCE_*} for more details.
+ */
+@VintfStability
+@Backing(type="int")
+enum VehicleHwMotionInputSource {
+ /**
+ * Unknown source
+ */
+ SOURCE_UNKNOWN = 0,
+ /**
+ * Source keyboard
+ */
+ SOURCE_KEYBOARD = 1,
+ /**
+ * Source dpad
+ */
+ SOURCE_DPAD = 2,
+ /**
+ * Source game pad
+ */
+ SOURCE_GAMEPAD = 3,
+ /**
+ * Source touch screen
+ */
+ SOURCE_TOUCHSCREEN = 4,
+ /**
+ * Source mouse
+ */
+ SOURCE_MOUSE = 5,
+ /**
+ * Source stylus
+ */
+ SOURCE_STYLUS = 6,
+ /**
+ * Source bluetooth stylus
+ */
+ SOURCE_BLUETOOTH_STYLUS = 7,
+ /**
+ * Source trackball
+ */
+ SOURCE_TRACKBALL = 8,
+ /**
+ * Source mouse relative
+ */
+ SOURCE_MOUSE_RELATIVE = 9,
+ /**
+ * Source touchpad
+ */
+ SOURCE_TOUCHPAD = 10,
+ /**
+ * Source touch navigation
+ */
+ SOURCE_TOUCH_NAVIGATION = 11,
+ /**
+ * Source rotary encoder
+ */
+ SOURCE_ROTARY_ENCODER = 12,
+ /**
+ * Source joystick
+ */
+ SOURCE_JOYSTICK = 13,
+ /**
+ * Source hdmi
+ */
+ SOURCE_HDMI = 14,
+ /**
+ * Source sensor
+ */
+ SOURCE_SENSOR = 15,
+}
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleHwMotionToolType.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleHwMotionToolType.aidl
new file mode 100644
index 0000000..08c9aed
--- /dev/null
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleHwMotionToolType.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.vehicle;
+
+/**
+ * See {@code android.view.MotionEvent#TOOL_TYPE_*} for more details.
+ */
+@VintfStability
+@Backing(type="int")
+enum VehicleHwMotionToolType {
+ /**
+ * Unknown type such as for a trackballl or other non-pointing device
+ */
+ TOOL_TYPE_UNKNOWN = 0,
+ /**
+ * Finger type
+ */
+ TOOL_TYPE_FINGER = 1,
+ /**
+ * Stylus type
+ */
+ TOOL_TYPE_STYLUS = 2,
+ /**
+ * Mouse type
+ */
+ TOOL_TYPE_MOUSE = 3,
+ /**
+ * Eraser type
+ */
+ TOOL_TYPE_ERASER = 4,
+}
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl
index b6886c0..472192f 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl
@@ -97,8 +97,12 @@
INFO_FUEL_TYPE = 0x0105 + 0x10000000 + 0x01000000
+ 0x00410000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32_VEC
/**
- * Battery capacity of the vehicle, if EV or hybrid. This is the nominal
- * battery capacity when the vehicle is new.
+ * Nominal battery capacity for EV or hybrid vehicle
+ *
+ * Returns the nominal battery capacity, if EV or hybrid. This is the battery capacity when the
+ * vehicle is new. This value might be different from EV_CURRENT_BATTERY_CAPACITY because
+ * EV_CURRENT_BATTERY_CAPACITY returns the real-time battery capacity taking into account
+ * factors such as battery aging and temperature dependency.
*
* @change_mode VehiclePropertyChangeMode.STATIC
* @access VehiclePropertyAccess.READ
@@ -327,9 +331,11 @@
FUEL_DOOR_OPEN = 0x0308 + 0x10000000 + 0x01000000
+ 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BOOLEAN
/**
- * EV battery level in WH, if EV or hybrid
+ * Battery level for EV or hybrid vehicle
*
- * Value may not exceed INFO_EV_BATTERY_CAPACITY
+ * Returns the current battery level, if EV or hybrid. This value will not exceed
+ * EV_CURRENT_BATTERY_CAPACITY. To calculate the battery percentage, use:
+ * (EV_BATTERY_LEVEL/EV_CURRENT_BATTERY_CAPACITY)*100.
*
* @change_mode VehiclePropertyChangeMode.CONTINUOUS
* @access VehiclePropertyAccess.READ
@@ -338,6 +344,20 @@
EV_BATTERY_LEVEL = 0x0309 + 0x10000000 + 0x01000000
+ 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:FLOAT
/**
+ * Current battery capacity for EV or hybrid vehicle
+ *
+ * Returns the actual value of battery capacity, if EV or hybrid. This property captures the
+ * real-time battery capacity taking into account factors such as battery aging and temperature
+ * dependency. Therefore, this value might be different from INFO_EV_BATTERY_CAPACITY because
+ * INFO_EV_BATTERY_CAPACITY returns the nominal battery capacity from when the vehicle was new.
+ *
+ * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+ * @access VehiclePropertyAccess.READ
+ * @unit VehicleUnit:WH
+ */
+ EV_CURRENT_BATTERY_CAPACITY =
+ 0x030D + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.FLOAT,
+ /**
* EV charge port open
*
* @change_mode VehiclePropertyChangeMode.ON_CHANGE
@@ -485,6 +505,21 @@
PARKING_BRAKE_AUTO_APPLY = 0x0403 + 0x10000000 + 0x01000000
+ 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BOOLEAN
/**
+ * Regenerative braking level of a electronic vehicle
+ *
+ * The maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All values between
+ * minInt32Value and maxInt32Value must be supported. The minInt32Value must be 0.
+ *
+ * The maxInt32Value in default area's VehicleAreaConfig indicates the maximum amount of energy
+ * regenerated from braking. The minInt32Value in default area's VehicleAreaConfig indicates no
+ * regenerative braking.
+ *
+ * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+ * @access VehiclePropertyAccess.READ_WRITE
+ */
+ EV_BRAKE_REGENERATION_LEVEL =
+ 0x040C + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
+ /**
* Warning for fuel low level.
*
* This property corresponds to the low fuel warning on the dashboard.
@@ -1150,7 +1185,7 @@
* It is assumed that AP's power state is controlled by a separate power
* controller.
*
- * For configuration information, VehiclePropConfig.configArray can have bit flag combining
+ * For configuration information, VehiclePropConfig.configArray must have bit flag combining
* values in VehicleApPowerStateConfigFlag.
*
* int32Values[0] : VehicleApPowerStateReq enum value
@@ -1224,6 +1259,62 @@
HW_KEY_INPUT = 0x0A10 + 0x10000000 + 0x01000000
+ 0x00410000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32_VEC
/**
+ * Property to feed H/W input events to android
+ *
+ * int32array[0]: target display defined by VehicleDisplay like VehicleDisplay::MAIN,
+ * VehicleDisplay::INSTRUMENT_CLUSTER, VehicleDisplay::AUX
+ * int32array[1]: key code, must use standard android key code like KEYCODE_HOME, KEYCODE_BACK
+ * int32array[2]: action defined in VehicleHwKeyInputAction like
+ * VehicleHwKeyInputAction::ACTION_UP, VehicleHwKeyInputAction::ACTION_UP
+ * int32array[3]: repeat count of the event. For key down events, this is the repeat count
+ * with the first down starting at 0 and counting up from there. For key up
+ * events, this is always equal to 0
+ *
+ * int64array[0]: down time, elapsed nanoseconds since boot. Denotes the time of the most
+ * recent key down event. For the down event, it will be the event time of the
+ * down event itself
+ *
+ * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+ * @access VehiclePropertyAccess.READ
+ * @config_flags
+ */
+ HW_KEY_INPUT_V2 =
+ 0x0A11 + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.MIXED,
+ /**
+ * Property to feed H/W input events to android
+ *
+ * int32array[0]: target display defined by VehicleDisplay like VehicleDisplay::MAIN,
+ * VehicleDisplay::INSTRUMENT_CLUSTER, VehicleDisplay::AUX
+ * int32array[1]: input type defined in VehicleHwMotionInputSource like
+ * VehicleHwMotionInputSource::SOURCE_KEYBOARD,
+ * VehicleHwMotionInputSource::SOURCE_DPAD
+ * int32array[2]: action code defined in VehicleHwMotionInputAction like
+ * VehicleHwMotionInputAction::ACTION_UP, VehicleHwMotionInputAction::ACTION_DOWN
+ * int32array[3]: button state flag defined in VehicleHwMotionButtonStateFlag like
+ * VehicleHwMotionButtonStateFlag::BUTTON_PRIMARY,
+ * VehicleHwMotionButtonStateFlag::BUTTON_SECONDARY
+ * int32array[4]: pointer events count, N. N must be a positive integer
+ * int32array[5:5+N-1]: pointer id, length N
+ * int32array[5+N:5+2*N-1] : tool type, length N. As defined in VehicleHwMotionToolType like
+ * VehicleHwMotionToolType::TOOL_TYPE_FINGER,
+ * VehicleHwMotionToolType::TOOL_TYPE_STYLUS
+ *
+ * floatArray[0:N-1] : x data, length N
+ * floatArray[N:2*N-1] : y data, length N
+ * floatArray[2*N:3*N-1] : pressure data, length N
+ * floatArray[3*N:4*N-1] : size data, length N
+ *
+ * int64array[0]: down time, elapsed nanoseconds since boot. Denotes the time when the user
+ * originally pressed down to start a stream of position events. For the down
+ * event, it will be the event time of the down event itself
+ *
+ * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+ * @access VehiclePropertyAccess.READ
+ * @config_flags
+ */
+ HW_MOTION_INPUT =
+ 0x0A12 + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.MIXED,
+ /**
* Property to feed H/W rotary events to android
*
* int32Values[0] : RotaryInputType identifying which rotary knob rotated
@@ -1742,6 +1833,9 @@
*
* This property can be set to VehiclePropertyAccess.READ read only for the sake of regulation
* or safety concerns.
+ *
+ * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+ * @access VehiclePropertyAccess.READ_WRITE
*/
SEAT_AIRBAG_ENABLED =
0x0B9E + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.BOOLEAN,
@@ -3133,4 +3227,41 @@
*/
SUPPORTED_PROPERTY_IDS = 0x0F48 + 0x10000000 + 0x01000000
+ 0x00410000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32_VEC
+
+ /**
+ * Request the head unit to be shutdown.
+ *
+ * <p>This usually involves telling a separate system outside the head unit (e.g. a power
+ * controller) to prepare shutting down the head unit.
+ *
+ * <p>This does not mean the head unit will shutdown immediately.
+ *
+ * <p>This means that another system will start sending a shutdown signal to the head unit,
+ * which will cause VHAL to send SHUTDOWN_PREPARE message to Android. Android will then start
+ * the shut down process by handling the message.
+ *
+ * <p>This property is only for issuing a request and only supports writing. Every time this
+ * property value is set, the request to shutdown will be issued no matter what the current
+ * property value is. The current property value is meaningless.
+ *
+ * <p>Since this property is write-only, subscribing is not allowed and no property change
+ * event will be generated.
+ *
+ * <p>The value to set indicates the shutdown option, it must be one of
+ * {@code VehicleApPowerStateShutdownParam}, e.g.,
+ * VehicleApPowerStateShutdownParam.SLEEP_IMMEDIATELY. This shutdown option might not be honored
+ * if the system doesn't support such option. In such case, an error will not be returned.
+ *
+ * <p>For configuration information, VehiclePropConfig.configArray must have bit flag combining
+ * values in {@code VehicleApPowerStateConfigFlag} to indicate which shutdown options are
+ * supported.
+ *
+ * <p>Returns error if failed to send the shutdown request to the other system.
+ *
+ * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+ * @access VehiclePropertyAccess.WRITE
+ * @data_enum VehicleApPowerStateShutdownParam
+ */
+ SHUTDOWN_REQUEST =
+ 0x0F49 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
}
diff --git a/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h b/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h
index d5182dd..c898baf 100644
--- a/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h
+++ b/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h
@@ -61,6 +61,7 @@
{VehicleProperty::FUEL_LEVEL, VehiclePropertyAccess::READ},
{VehicleProperty::FUEL_DOOR_OPEN, VehiclePropertyAccess::READ_WRITE},
{VehicleProperty::EV_BATTERY_LEVEL, VehiclePropertyAccess::READ},
+ {VehicleProperty::EV_CURRENT_BATTERY_CAPACITY, VehiclePropertyAccess::READ},
{VehicleProperty::EV_CHARGE_PORT_OPEN, VehiclePropertyAccess::READ_WRITE},
{VehicleProperty::EV_CHARGE_PORT_CONNECTED, VehiclePropertyAccess::READ},
{VehicleProperty::EV_BATTERY_INSTANTANEOUS_CHARGE_RATE, VehiclePropertyAccess::READ},
@@ -71,6 +72,7 @@
{VehicleProperty::CURRENT_GEAR, VehiclePropertyAccess::READ},
{VehicleProperty::PARKING_BRAKE_ON, VehiclePropertyAccess::READ},
{VehicleProperty::PARKING_BRAKE_AUTO_APPLY, VehiclePropertyAccess::READ},
+ {VehicleProperty::EV_BRAKE_REGENERATION_LEVEL, VehiclePropertyAccess::READ_WRITE},
{VehicleProperty::FUEL_LEVEL_LOW, VehiclePropertyAccess::READ},
{VehicleProperty::NIGHT_MODE, VehiclePropertyAccess::READ},
{VehicleProperty::TURN_SIGNAL_STATE, VehiclePropertyAccess::READ},
@@ -114,6 +116,8 @@
{VehicleProperty::AP_POWER_BOOTUP_REASON, VehiclePropertyAccess::READ},
{VehicleProperty::DISPLAY_BRIGHTNESS, VehiclePropertyAccess::READ_WRITE},
{VehicleProperty::HW_KEY_INPUT, VehiclePropertyAccess::READ},
+ {VehicleProperty::HW_KEY_INPUT_V2, VehiclePropertyAccess::READ},
+ {VehicleProperty::HW_MOTION_INPUT, VehiclePropertyAccess::READ},
{VehicleProperty::HW_ROTARY_INPUT, VehiclePropertyAccess::READ},
{VehicleProperty::HW_CUSTOM_INPUT, VehiclePropertyAccess::READ},
{VehicleProperty::DOOR_POS, VehiclePropertyAccess::READ_WRITE},
@@ -224,6 +228,7 @@
{VehicleProperty::VEHICLE_CURB_WEIGHT, VehiclePropertyAccess::READ},
{VehicleProperty::GENERAL_SAFETY_REGULATION_COMPLIANCE_REQUIREMENT, VehiclePropertyAccess::READ},
{VehicleProperty::SUPPORTED_PROPERTY_IDS, VehiclePropertyAccess::READ},
+ {VehicleProperty::SHUTDOWN_REQUEST, VehiclePropertyAccess::WRITE},
};
} // namespace vehicle
diff --git a/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h b/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h
index 47bad2c..c501d9b 100644
--- a/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h
+++ b/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h
@@ -61,6 +61,7 @@
{VehicleProperty::FUEL_LEVEL, VehiclePropertyChangeMode::CONTINUOUS},
{VehicleProperty::FUEL_DOOR_OPEN, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::EV_BATTERY_LEVEL, VehiclePropertyChangeMode::CONTINUOUS},
+ {VehicleProperty::EV_CURRENT_BATTERY_CAPACITY, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::EV_CHARGE_PORT_OPEN, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::EV_CHARGE_PORT_CONNECTED, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::EV_BATTERY_INSTANTANEOUS_CHARGE_RATE, VehiclePropertyChangeMode::CONTINUOUS},
@@ -71,6 +72,7 @@
{VehicleProperty::CURRENT_GEAR, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::PARKING_BRAKE_ON, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::PARKING_BRAKE_AUTO_APPLY, VehiclePropertyChangeMode::ON_CHANGE},
+ {VehicleProperty::EV_BRAKE_REGENERATION_LEVEL, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::FUEL_LEVEL_LOW, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::NIGHT_MODE, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::TURN_SIGNAL_STATE, VehiclePropertyChangeMode::ON_CHANGE},
@@ -114,6 +116,8 @@
{VehicleProperty::AP_POWER_BOOTUP_REASON, VehiclePropertyChangeMode::STATIC},
{VehicleProperty::DISPLAY_BRIGHTNESS, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::HW_KEY_INPUT, VehiclePropertyChangeMode::ON_CHANGE},
+ {VehicleProperty::HW_KEY_INPUT_V2, VehiclePropertyChangeMode::ON_CHANGE},
+ {VehicleProperty::HW_MOTION_INPUT, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::HW_ROTARY_INPUT, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::HW_CUSTOM_INPUT, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::DOOR_POS, VehiclePropertyChangeMode::ON_CHANGE},
@@ -224,6 +228,7 @@
{VehicleProperty::VEHICLE_CURB_WEIGHT, VehiclePropertyChangeMode::STATIC},
{VehicleProperty::GENERAL_SAFETY_REGULATION_COMPLIANCE_REQUIREMENT, VehiclePropertyChangeMode::STATIC},
{VehicleProperty::SUPPORTED_PROPERTY_IDS, VehiclePropertyChangeMode::STATIC},
+ {VehicleProperty::SHUTDOWN_REQUEST, VehiclePropertyChangeMode::ON_CHANGE},
};
} // namespace vehicle
diff --git a/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java b/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java
index 85a62d3..ca85de5 100644
--- a/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java
+++ b/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java
@@ -53,6 +53,7 @@
Map.entry(VehicleProperty.FUEL_LEVEL, VehiclePropertyAccess.READ),
Map.entry(VehicleProperty.FUEL_DOOR_OPEN, VehiclePropertyAccess.READ_WRITE),
Map.entry(VehicleProperty.EV_BATTERY_LEVEL, VehiclePropertyAccess.READ),
+ Map.entry(VehicleProperty.EV_CURRENT_BATTERY_CAPACITY, VehiclePropertyAccess.READ),
Map.entry(VehicleProperty.EV_CHARGE_PORT_OPEN, VehiclePropertyAccess.READ_WRITE),
Map.entry(VehicleProperty.EV_CHARGE_PORT_CONNECTED, VehiclePropertyAccess.READ),
Map.entry(VehicleProperty.EV_BATTERY_INSTANTANEOUS_CHARGE_RATE, VehiclePropertyAccess.READ),
@@ -63,6 +64,7 @@
Map.entry(VehicleProperty.CURRENT_GEAR, VehiclePropertyAccess.READ),
Map.entry(VehicleProperty.PARKING_BRAKE_ON, VehiclePropertyAccess.READ),
Map.entry(VehicleProperty.PARKING_BRAKE_AUTO_APPLY, VehiclePropertyAccess.READ),
+ Map.entry(VehicleProperty.EV_BRAKE_REGENERATION_LEVEL, VehiclePropertyAccess.READ_WRITE),
Map.entry(VehicleProperty.FUEL_LEVEL_LOW, VehiclePropertyAccess.READ),
Map.entry(VehicleProperty.NIGHT_MODE, VehiclePropertyAccess.READ),
Map.entry(VehicleProperty.TURN_SIGNAL_STATE, VehiclePropertyAccess.READ),
@@ -106,6 +108,8 @@
Map.entry(VehicleProperty.AP_POWER_BOOTUP_REASON, VehiclePropertyAccess.READ),
Map.entry(VehicleProperty.DISPLAY_BRIGHTNESS, VehiclePropertyAccess.READ_WRITE),
Map.entry(VehicleProperty.HW_KEY_INPUT, VehiclePropertyAccess.READ),
+ Map.entry(VehicleProperty.HW_KEY_INPUT_V2, VehiclePropertyAccess.READ),
+ Map.entry(VehicleProperty.HW_MOTION_INPUT, VehiclePropertyAccess.READ),
Map.entry(VehicleProperty.HW_ROTARY_INPUT, VehiclePropertyAccess.READ),
Map.entry(VehicleProperty.HW_CUSTOM_INPUT, VehiclePropertyAccess.READ),
Map.entry(VehicleProperty.DOOR_POS, VehiclePropertyAccess.READ_WRITE),
@@ -215,7 +219,8 @@
Map.entry(VehicleProperty.TRAILER_PRESENT, VehiclePropertyAccess.READ),
Map.entry(VehicleProperty.VEHICLE_CURB_WEIGHT, VehiclePropertyAccess.READ),
Map.entry(VehicleProperty.GENERAL_SAFETY_REGULATION_COMPLIANCE_REQUIREMENT, VehiclePropertyAccess.READ),
- Map.entry(VehicleProperty.SUPPORTED_PROPERTY_IDS, VehiclePropertyAccess.READ)
+ Map.entry(VehicleProperty.SUPPORTED_PROPERTY_IDS, VehiclePropertyAccess.READ),
+ Map.entry(VehicleProperty.SHUTDOWN_REQUEST, VehiclePropertyAccess.WRITE)
);
}
diff --git a/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java b/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java
index 46b9663..92a83a8 100644
--- a/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java
+++ b/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java
@@ -53,6 +53,7 @@
Map.entry(VehicleProperty.FUEL_LEVEL, VehiclePropertyChangeMode.CONTINUOUS),
Map.entry(VehicleProperty.FUEL_DOOR_OPEN, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.EV_BATTERY_LEVEL, VehiclePropertyChangeMode.CONTINUOUS),
+ Map.entry(VehicleProperty.EV_CURRENT_BATTERY_CAPACITY, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.EV_CHARGE_PORT_OPEN, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.EV_CHARGE_PORT_CONNECTED, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.EV_BATTERY_INSTANTANEOUS_CHARGE_RATE, VehiclePropertyChangeMode.CONTINUOUS),
@@ -63,6 +64,7 @@
Map.entry(VehicleProperty.CURRENT_GEAR, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.PARKING_BRAKE_ON, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.PARKING_BRAKE_AUTO_APPLY, VehiclePropertyChangeMode.ON_CHANGE),
+ Map.entry(VehicleProperty.EV_BRAKE_REGENERATION_LEVEL, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.FUEL_LEVEL_LOW, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.NIGHT_MODE, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.TURN_SIGNAL_STATE, VehiclePropertyChangeMode.ON_CHANGE),
@@ -106,6 +108,8 @@
Map.entry(VehicleProperty.AP_POWER_BOOTUP_REASON, VehiclePropertyChangeMode.STATIC),
Map.entry(VehicleProperty.DISPLAY_BRIGHTNESS, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.HW_KEY_INPUT, VehiclePropertyChangeMode.ON_CHANGE),
+ Map.entry(VehicleProperty.HW_KEY_INPUT_V2, VehiclePropertyChangeMode.ON_CHANGE),
+ Map.entry(VehicleProperty.HW_MOTION_INPUT, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.HW_ROTARY_INPUT, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.HW_CUSTOM_INPUT, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.DOOR_POS, VehiclePropertyChangeMode.ON_CHANGE),
@@ -215,7 +219,8 @@
Map.entry(VehicleProperty.TRAILER_PRESENT, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.VEHICLE_CURB_WEIGHT, VehiclePropertyChangeMode.STATIC),
Map.entry(VehicleProperty.GENERAL_SAFETY_REGULATION_COMPLIANCE_REQUIREMENT, VehiclePropertyChangeMode.STATIC),
- Map.entry(VehicleProperty.SUPPORTED_PROPERTY_IDS, VehiclePropertyChangeMode.STATIC)
+ Map.entry(VehicleProperty.SUPPORTED_PROPERTY_IDS, VehiclePropertyChangeMode.STATIC),
+ Map.entry(VehicleProperty.SHUTDOWN_REQUEST, VehiclePropertyChangeMode.ON_CHANGE)
);
}
diff --git a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp
index e4f13e8..20048a2 100644
--- a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp
+++ b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp
@@ -105,6 +105,7 @@
FAN_DIRECTION_FLOOR | FAN_DIRECTION_DEFROST | FAN_DIRECTION_FACE},
{"FUEL_DOOR_REAR_LEFT", FUEL_DOOR_REAR_LEFT},
{"LIGHT_STATE_ON", LIGHT_STATE_ON},
+ {"LIGHT_STATE_OFF", LIGHT_STATE_OFF},
{"LIGHT_SWITCH_OFF", LIGHT_SWITCH_OFF},
{"LIGHT_SWITCH_AUTO", LIGHT_SWITCH_AUTO},
{"MIRROR_DRIVER_LEFT_RIGHT",
@@ -460,6 +461,13 @@
&areaConfig.minFloatValue, errors);
tryParseJsonValueToVariable(jsonAreaConfig, "maxFloatValue", /*optional=*/true,
&areaConfig.maxFloatValue, errors);
+
+ std::vector<int64_t> supportedEnumValues;
+ tryParseJsonArrayToVariable(jsonAreaConfig, "supportedEnumValues", /*optional=*/true,
+ &supportedEnumValues, errors);
+ if (!supportedEnumValues.empty()) {
+ areaConfig.supportedEnumValues = std::move(supportedEnumValues);
+ }
config->config.areaConfigs.push_back(std::move(areaConfig));
RawPropValues areaValue = {};
diff --git a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/test/JsonConfigLoaderUnitTest.cpp b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/test/JsonConfigLoaderUnitTest.cpp
index 9ff8c1b..9882653 100644
--- a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/test/JsonConfigLoaderUnitTest.cpp
+++ b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/test/JsonConfigLoaderUnitTest.cpp
@@ -616,6 +616,89 @@
<< "Wrong type for DefaultValue for one area must cause error";
}
+TEST_F(JsonConfigLoaderUnitTest, testAreas_HandlesNoSupportedEnumValuesDeclared) {
+ std::istringstream iss(R"(
+ {
+ "properties": [{
+ "property": "VehicleProperty::CABIN_LIGHTS_STATE",
+ "areas": [{
+ "areaId": 0,
+ }]
+ }]
+ }
+ )");
+
+ auto result = mLoader.loadPropConfig(iss);
+ ASSERT_TRUE(result.ok());
+
+ auto configs = result.value();
+ ASSERT_EQ(configs.size(), 1u);
+
+ const VehiclePropConfig& config = configs.begin()->second.config;
+ ASSERT_EQ(config.areaConfigs.size(), 1u);
+
+ const VehicleAreaConfig& areaConfig = config.areaConfigs[0];
+ ASSERT_EQ(areaConfig.areaId, 0);
+ ASSERT_FALSE(areaConfig.supportedEnumValues);
+}
+
+TEST_F(JsonConfigLoaderUnitTest, testAreas_HandlesSupportedEnumValues) {
+ std::istringstream iss(R"(
+ {
+ "properties": [{
+ "property": "VehicleProperty::CABIN_LIGHTS_STATE",
+ "areas": [{
+ "areaId": 0,
+ "supportedEnumValues": ["Constants::LIGHT_STATE_ON", "Constants::LIGHT_STATE_OFF"]
+ }]
+ }]
+ }
+ )");
+
+ auto result = mLoader.loadPropConfig(iss);
+ ASSERT_TRUE(result.ok());
+
+ auto configs = result.value();
+ ASSERT_EQ(configs.size(), 1u);
+
+ const VehiclePropConfig& config = configs.begin()->second.config;
+ ASSERT_EQ(config.areaConfigs.size(), 1u);
+
+ const VehicleAreaConfig& areaConfig = config.areaConfigs[0];
+ ASSERT_EQ(areaConfig.areaId, 0);
+ ASSERT_TRUE(areaConfig.supportedEnumValues);
+ ASSERT_EQ(areaConfig.supportedEnumValues.value().size(), 2u);
+ ASSERT_EQ(areaConfig.supportedEnumValues.value(),
+ std::vector<int64_t>({LIGHT_STATE_ON, LIGHT_STATE_OFF}));
+}
+
+TEST_F(JsonConfigLoaderUnitTest, testAreas_HandlesEmptySupportedEnumValues) {
+ std::istringstream iss(R"(
+ {
+ "properties": [{
+ "property": "VehicleProperty::CABIN_LIGHTS_STATE",
+ "areas": [{
+ "areaId": 0,
+ "supportedEnumValues": []
+ }]
+ }]
+ }
+ )");
+
+ auto result = mLoader.loadPropConfig(iss);
+ ASSERT_TRUE(result.ok());
+
+ auto configs = result.value();
+ ASSERT_EQ(configs.size(), 1u);
+
+ const VehiclePropConfig& config = configs.begin()->second.config;
+ ASSERT_EQ(config.areaConfigs.size(), 1u);
+
+ const VehicleAreaConfig& areaConfig = config.areaConfigs[0];
+ ASSERT_EQ(areaConfig.areaId, 0);
+ ASSERT_FALSE(areaConfig.supportedEnumValues);
+}
+
} // namespace vehicle
} // namespace automotive
} // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json b/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
index 7ad8089..0123521 100644
--- a/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
+++ b/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
@@ -123,7 +123,7 @@
"property": "VehicleProperty::VEHICLE_SPEED_DISPLAY_UNITS",
"defaultValue": {
"int32Values": [
- "VehicleUnit::KILOMETERS_PER_HOUR"
+ "VehicleUnit::MILES_PER_HOUR"
]
},
"configArray": [
@@ -1310,6 +1310,14 @@
"minSampleRate": 1.0
},
{
+ "property": "VehicleProperty::EV_CURRENT_BATTERY_CAPACITY",
+ "defaultValue": {
+ "floatValues": [
+ 150000.0
+ ]
+ }
+ },
+ {
"property": "VehicleProperty::EV_CHARGE_PORT_OPEN",
"defaultValue": {
"int32Values": [
@@ -1545,6 +1553,21 @@
}
},
{
+ "property": "VehicleProperty::EV_BRAKE_REGENERATION_LEVEL",
+ "defaultValue": {
+ "int32Values": [
+ 0
+ ]
+ },
+ "areas": [
+ {
+ "areaId": 0,
+ "minInt32Value": 0,
+ "maxInt32Value": 3
+ }
+ ]
+ },
+ {
"property": "VehicleProperty::FUEL_LEVEL_LOW",
"defaultValue": {
"int32Values": [
@@ -1556,7 +1579,7 @@
"property": "VehicleProperty::FUEL_VOLUME_DISPLAY_UNITS",
"defaultValue": {
"int32Values": [
- "VehicleUnit::LITER"
+ "VehicleUnit::US_GALLON"
]
},
"configArray": [
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
index 1636cb6..e515bad 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
@@ -138,9 +138,12 @@
std::unique_ptr<RecurrentTimer> mRecurrentTimer;
// GeneratorHub is thread-safe.
std::unique_ptr<GeneratorHub> mGeneratorHub;
+
+ // Only allowed to set once.
+ std::unique_ptr<const PropertyChangeCallback> mOnPropertyChangeCallback;
+ std::unique_ptr<const PropertySetErrorCallback> mOnPropertySetErrorCallback;
+
std::mutex mLock;
- std::unique_ptr<const PropertyChangeCallback> mOnPropertyChangeCallback GUARDED_BY(mLock);
- std::unique_ptr<const PropertySetErrorCallback> mOnPropertySetErrorCallback GUARDED_BY(mLock);
std::unordered_map<PropIdAreaId, std::shared_ptr<RecurrentTimer::Callback>, PropIdAreaIdHash>
mRecurrentActions GUARDED_BY(mLock);
std::unordered_map<PropIdAreaId, VehiclePropValuePool::RecyclableType, PropIdAreaIdHash>
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
index d87e5aa..dd76524 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
@@ -320,7 +320,11 @@
if (updatedValue != nullptr) {
ALOGI("onSetProperty(): updating property returned by HAL: %s",
updatedValue->toString().c_str());
- if (auto writeResult = mServerSidePropStore->writeValue(std::move(result.value()));
+ // Update timestamp otherwise writeValue might fail because the timestamp is outdated.
+ updatedValue->timestamp = elapsedRealtimeNano();
+ if (auto writeResult = mServerSidePropStore->writeValue(
+ std::move(result.value()),
+ /*updateStatus=*/true, VehiclePropertyStore::EventMode::ALWAYS);
!writeResult.ok()) {
return StatusError(getErrorCode(writeResult))
<< "failed to write value into property store, error: "
@@ -623,11 +627,7 @@
} else if (EqualsIgnoreCase(option, "--inject-event")) {
result.buffer = dumpInjectEvent(options);
} else if (EqualsIgnoreCase(option, kUserHalDumpOption)) {
- if (options.size() == 1) {
- result.buffer = mFakeUserHal->showDumpHelp();
- } else {
- result.buffer = mFakeUserHal->dump(options[1]);
- }
+ result.buffer = mFakeUserHal->dump();
} else if (EqualsIgnoreCase(option, "--genfakedata")) {
result.buffer = genFakeDataCommand(options);
} else {
@@ -1228,13 +1228,19 @@
void FakeVehicleHardware::registerOnPropertyChangeEvent(
std::unique_ptr<const PropertyChangeCallback> callback) {
- std::scoped_lock<std::mutex> lockGuard(mLock);
+ if (mOnPropertyChangeCallback != nullptr) {
+ ALOGE("registerOnPropertyChangeEvent must only be called once");
+ return;
+ }
mOnPropertyChangeCallback = std::move(callback);
}
void FakeVehicleHardware::registerOnPropertySetErrorEvent(
std::unique_ptr<const PropertySetErrorCallback> callback) {
- std::scoped_lock<std::mutex> lockGuard(mLock);
+ if (mOnPropertySetErrorCallback != nullptr) {
+ ALOGE("registerOnPropertySetErrorEvent must only be called once");
+ return;
+ }
mOnPropertySetErrorCallback = std::move(callback);
}
@@ -1278,8 +1284,6 @@
}
void FakeVehicleHardware::onValueChangeCallback(const VehiclePropValue& value) {
- std::scoped_lock<std::mutex> lockGuard(mLock);
-
if (mOnPropertyChangeCallback == nullptr) {
return;
}
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
index c230c51..0184462 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
@@ -1223,6 +1223,8 @@
ASSERT_EQ(events.size(), static_cast<size_t>(1));
events[0].timestamp = 0;
+ // The returned event will have area ID 0.
+ valueToSet.areaId = 0;
ASSERT_EQ(events[0], valueToSet);
// Try to get switch_user again, should return default value.
@@ -1277,6 +1279,8 @@
auto events = getChangedProperties();
ASSERT_EQ(events.size(), static_cast<size_t>(1));
events[0].timestamp = 0;
+ // The returned event will have area ID 0.
+ valueToSet.areaId = 0;
EXPECT_EQ(events[0], valueToSet);
// Try to get create_user again, should return default value.
@@ -1330,7 +1334,7 @@
ASSERT_EQ(events.size(), static_cast<size_t>(1));
events[0].timestamp = 0;
EXPECT_EQ(events[0], (VehiclePropValue{
- .areaId = 1,
+ .areaId = 0,
.prop = toInt(VehicleProperty::INITIAL_USER_INFO),
.value.int32Values = {3, 1, 11},
}));
@@ -1516,26 +1520,16 @@
ASSERT_THAT(result.buffer, ContainsRegex("Invalid option: --invalid"));
}
-TEST_F(FakeVehicleHardwareTest, testDumpFakeUserHalHelp) {
- std::vector<std::string> options;
- options.push_back("--user-hal");
-
- DumpResult result = getHardware()->dump(options);
- ASSERT_FALSE(result.callerShouldDumpState);
- ASSERT_NE(result.buffer, "");
- ASSERT_THAT(result.buffer, ContainsRegex("dumps state used for user management"));
-}
-
TEST_F(FakeVehicleHardwareTest, testDumpFakeUserHal) {
std::vector<std::string> options;
options.push_back("--user-hal");
- // Indent: " ".
- options.push_back(" ");
DumpResult result = getHardware()->dump(options);
ASSERT_FALSE(result.callerShouldDumpState);
ASSERT_NE(result.buffer, "");
- ASSERT_THAT(result.buffer, ContainsRegex(" No InitialUserInfo response\n"));
+ ASSERT_THAT(result.buffer,
+ ContainsRegex("No InitialUserInfo response\nNo SwitchUser response\nNo CreateUser "
+ "response\nNo SetUserIdentificationAssociation response\n"));
}
struct SetPropTestCase {
diff --git a/automotive/vehicle/aidl/impl/fake_impl/userhal/include/FakeUserHal.h b/automotive/vehicle/aidl/impl/fake_impl/userhal/include/FakeUserHal.h
index 4ae9c8c..fcbe8fd 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/userhal/include/FakeUserHal.h
+++ b/automotive/vehicle/aidl/impl/fake_impl/userhal/include/FakeUserHal.h
@@ -64,7 +64,7 @@
std::string showDumpHelp() const;
// Dump its contents.
- std::string dump(std::string indent) const;
+ std::string dump() const;
private:
const std::shared_ptr<VehiclePropValuePool> mValuePool;
diff --git a/automotive/vehicle/aidl/impl/fake_impl/userhal/src/FakeUserHal.cpp b/automotive/vehicle/aidl/impl/fake_impl/userhal/src/FakeUserHal.cpp
index 7748fb6..878c2e7 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/userhal/src/FakeUserHal.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/userhal/src/FakeUserHal.cpp
@@ -328,6 +328,9 @@
<< "invalid action on lshal response: " << response->toString();
}
+ // Update area ID to 0 since this is a global property (and the area ID was only set to emulate
+ // the request id behavior).
+ response->areaId = 0;
ALOGD("updating property to: %s", response->toString().c_str());
return response;
}
@@ -336,33 +339,31 @@
return fmt::format("{}: dumps state used for user management\n", kUserHalDumpOption);
}
-std::string FakeUserHal::dump(std::string indent) const {
+std::string FakeUserHal::dump() const {
std::scoped_lock<std::mutex> lockGuard(mLock);
std::string info;
if (mInitialUserResponseFromCmd != nullptr) {
- info += fmt::format("{}InitialUserInfo response: {}\n", indent,
+ info += fmt::format("InitialUserInfo response: {}\n",
mInitialUserResponseFromCmd->toString());
} else {
- info += fmt::format("{}No InitialUserInfo response\n", indent);
+ info += "No InitialUserInfo response\n";
}
if (mSwitchUserResponseFromCmd != nullptr) {
- info += fmt::format("{}SwitchUser response: {}\n", indent,
- mSwitchUserResponseFromCmd->toString());
+ info += fmt::format("SwitchUser response: {}\n", mSwitchUserResponseFromCmd->toString());
} else {
- info += fmt::format("{}No SwitchUser response\n", indent);
+ info += "No SwitchUser response\n";
}
if (mCreateUserResponseFromCmd != nullptr) {
- info += fmt::format("{}CreateUser response: {}\n", indent,
- mCreateUserResponseFromCmd->toString());
+ info += fmt::format("CreateUser response: {}\n", mCreateUserResponseFromCmd->toString());
} else {
- info += fmt::format("{}No CreateUser response\n", indent);
+ info += "No CreateUser response\n";
}
if (mSetUserIdentificationAssociationResponseFromCmd != nullptr) {
- info += fmt::format("{}SetUserIdentificationAssociation response: {}\n", indent,
+ info += fmt::format("SetUserIdentificationAssociation response: {}\n",
mSetUserIdentificationAssociationResponseFromCmd->toString());
} else {
- info += fmt::format("{}No SetUserIdentificationAssociation response\n", indent);
+ info += "No SetUserIdentificationAssociation response\n";
}
return info;
}
diff --git a/automotive/vehicle/aidl/impl/hardware/include/IVehicleHardware.h b/automotive/vehicle/aidl/impl/hardware/include/IVehicleHardware.h
index 759db41..d92ccfd 100644
--- a/automotive/vehicle/aidl/impl/hardware/include/IVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/hardware/include/IVehicleHardware.h
@@ -116,11 +116,12 @@
virtual aidl::android::hardware::automotive::vehicle::StatusCode checkHealth() = 0;
// Register a callback that would be called when there is a property change event from vehicle.
+ // Must only be called once during initialization.
virtual void registerOnPropertyChangeEvent(
std::unique_ptr<const PropertyChangeCallback> callback) = 0;
// Register a callback that would be called when there is a property set error event from
- // vehicle.
+ // vehicle. Must only be called once during initialization.
virtual void registerOnPropertySetErrorEvent(
std::unique_ptr<const PropertySetErrorCallback> callback) = 0;
};
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/PropertyUtils.h b/automotive/vehicle/aidl/impl/utils/common/include/PropertyUtils.h
index caf17e8..bf27c95 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/PropertyUtils.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/PropertyUtils.h
@@ -96,6 +96,7 @@
constexpr int CHARGE_PORT_FRONT_LEFT = toInt(propertyutils_impl::PortLocationType::FRONT_LEFT);
constexpr int CHARGE_PORT_REAR_LEFT = toInt(propertyutils_impl::PortLocationType::REAR_LEFT);
constexpr int LIGHT_STATE_ON = toInt(propertyutils_impl::VehicleLightState::ON);
+constexpr int LIGHT_STATE_OFF = toInt(propertyutils_impl::VehicleLightState::OFF);
constexpr int LIGHT_SWITCH_OFF = toInt(propertyutils_impl::VehicleLightSwitch::OFF);
constexpr int LIGHT_SWITCH_AUTO = toInt(propertyutils_impl::VehicleLightSwitch::AUTOMATIC);
constexpr int WHEEL_FRONT_LEFT = toInt(propertyutils_impl::VehicleAreaWheel::LEFT_FRONT);
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/RecurrentTimer.h b/automotive/vehicle/aidl/impl/utils/common/include/RecurrentTimer.h
index 5f0f716..cd2b727 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/RecurrentTimer.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/RecurrentTimer.h
@@ -83,8 +83,9 @@
// each time we might introduce outdated elements to the top. We must make sure the heap is
// always valid from the top.
void removeInvalidCallbackLocked() REQUIRES(mLock);
- // Pops the next closest callback (must be valid) from the heap.
- std::unique_ptr<CallbackInfo> popNextCallbackLocked() REQUIRES(mLock);
+ // Gets the next calblack to run (must be valid) from the heap, update its nextTime and put
+ // it back to the heap.
+ std::shared_ptr<Callback> getNextCallbackLocked(int64_t now) REQUIRES(mLock);
};
} // namespace vehicle
diff --git a/automotive/vehicle/aidl/impl/utils/common/src/RecurrentTimer.cpp b/automotive/vehicle/aidl/impl/utils/common/src/RecurrentTimer.cpp
index 43f5d69..c6d3687 100644
--- a/automotive/vehicle/aidl/impl/utils/common/src/RecurrentTimer.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/src/RecurrentTimer.cpp
@@ -103,68 +103,71 @@
}
}
-std::unique_ptr<RecurrentTimer::CallbackInfo> RecurrentTimer::popNextCallbackLocked() {
+std::shared_ptr<RecurrentTimer::Callback> RecurrentTimer::getNextCallbackLocked(int64_t now) {
std::pop_heap(mCallbackQueue.begin(), mCallbackQueue.end(), CallbackInfo::cmp);
- std::unique_ptr<CallbackInfo> info = std::move(mCallbackQueue[mCallbackQueue.size() - 1]);
- mCallbackQueue.pop_back();
+ auto& callbackInfo = mCallbackQueue[mCallbackQueue.size() - 1];
+ auto nextCallback = callbackInfo->callback;
+ // intervalCount is the number of interval we have to advance until we pass now.
+ size_t intervalCount = (now - callbackInfo->nextTime) / callbackInfo->interval + 1;
+ callbackInfo->nextTime += intervalCount * callbackInfo->interval;
+ std::push_heap(mCallbackQueue.begin(), mCallbackQueue.end(), CallbackInfo::cmp);
+
// Make sure the first element is always valid.
removeInvalidCallbackLocked();
- return info;
+
+ return nextCallback;
}
void RecurrentTimer::loop() {
- std::unique_lock<std::mutex> uniqueLock(mLock);
-
+ std::vector<std::shared_ptr<Callback>> callbacksToRun;
while (true) {
- // Wait until the timer exits or we have at least one recurrent callback.
- mCond.wait(uniqueLock, [this] {
- ScopedLockAssertion lockAssertion(mLock);
- return mStopRequested || mCallbackQueue.size() != 0;
- });
-
- int64_t interval;
{
+ std::unique_lock<std::mutex> uniqueLock(mLock);
ScopedLockAssertion lockAssertion(mLock);
+ // Wait until the timer exits or we have at least one recurrent callback.
+ mCond.wait(uniqueLock, [this] {
+ ScopedLockAssertion lockAssertion(mLock);
+ return mStopRequested || mCallbackQueue.size() != 0;
+ });
+
+ int64_t interval;
if (mStopRequested) {
return;
}
// The first element is the nearest next event.
int64_t nextTime = mCallbackQueue[0]->nextTime;
int64_t now = uptimeNanos();
+
if (nextTime > now) {
interval = nextTime - now;
} else {
interval = 0;
}
- }
- // Wait for the next event or the timer exits.
- if (mCond.wait_for(uniqueLock, std::chrono::nanoseconds(interval), [this] {
- ScopedLockAssertion lockAssertion(mLock);
- return mStopRequested;
- })) {
- return;
- }
+ // Wait for the next event or the timer exits.
+ if (mCond.wait_for(uniqueLock, std::chrono::nanoseconds(interval), [this] {
+ ScopedLockAssertion lockAssertion(mLock);
+ return mStopRequested;
+ })) {
+ return;
+ }
- {
- ScopedLockAssertion lockAssertion(mLock);
- int64_t now = uptimeNanos();
+ now = uptimeNanos();
+ callbacksToRun.clear();
while (mCallbackQueue.size() > 0) {
int64_t nextTime = mCallbackQueue[0]->nextTime;
if (nextTime > now) {
break;
}
- std::unique_ptr<CallbackInfo> info = popNextCallbackLocked();
- info->nextTime += info->interval;
-
- auto callback = info->callback;
- mCallbackQueue.push_back(std::move(info));
- std::push_heap(mCallbackQueue.begin(), mCallbackQueue.end(), CallbackInfo::cmp);
-
- (*callback)();
+ callbacksToRun.push_back(getNextCallbackLocked(now));
}
}
+
+ // Do not execute the callback while holding the lock.
+ for (size_t i = 0; i < callbacksToRun.size(); i++) {
+ (*callbacksToRun[i])();
+ }
}
}
diff --git a/automotive/vehicle/aidl/impl/utils/common/test/RecurrentTimerTest.cpp b/automotive/vehicle/aidl/impl/utils/common/test/RecurrentTimerTest.cpp
index a033a24..141efc1 100644
--- a/automotive/vehicle/aidl/impl/utils/common/test/RecurrentTimerTest.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/test/RecurrentTimerTest.cpp
@@ -186,6 +186,33 @@
ASSERT_EQ(countTimerCallbackQueue(&timer), static_cast<size_t>(0));
}
+TEST_F(RecurrentTimerTest, testRegisterCallbackMultipleTimesNoDeadLock) {
+ // We want to avoid the following situation:
+ // Caller holds a lock while calling registerTimerCallback, registerTimerCallback will try
+ // to obtain an internal lock inside timer.
+ // Meanwhile an recurrent action happens with timer holding an internal lock. The action
+ // tries to obtain the lock currently hold by the caller.
+ // The solution is that while calling recurrent actions, timer must not hold the internal lock.
+
+ std::unique_ptr<RecurrentTimer> timer = std::make_unique<RecurrentTimer>();
+ std::mutex lock;
+ for (size_t i = 0; i < 1000; i++) {
+ std::scoped_lock<std::mutex> lockGuard(lock);
+ auto action = std::make_shared<RecurrentTimer::Callback>([&lock] {
+ // While calling this function, the timer must not hold lock in order not to dead
+ // lock.
+ std::scoped_lock<std::mutex> lockGuard(lock);
+ });
+ // 10ms
+ int64_t interval = 10'000'000;
+ timer->registerTimerCallback(interval, action);
+ // Sleep for a little while to let the recurrent actions begin.
+ std::this_thread::sleep_for(std::chrono::milliseconds(1));
+ }
+ // Make sure we stop the timer before we destroy lock.
+ timer.reset();
+}
+
} // namespace vehicle
} // namespace automotive
} // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
index d447bf8..4a4e023 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
@@ -789,10 +789,13 @@
for (uint32_t i = 0; i < numArgs; i++) {
options.push_back(args[i]);
}
+ if (options.size() == 1 && options[0] == "-a") {
+ // Ignore "-a" option. Bugreport will call with this option.
+ options.clear();
+ }
DumpResult result = mVehicleHardware->dump(options);
dprintf(fd, "%s", (result.buffer + "\n").c_str());
if (!result.callerShouldDumpState) {
- dprintf(fd, "Skip dumping Vehicle HAL State.\n");
return STATUS_OK;
}
dprintf(fd, "Vehicle HAL State: \n");
diff --git a/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp b/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
index 7eefe2a..1943c41 100644
--- a/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
+++ b/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
@@ -481,6 +481,18 @@
actualPropertyType);
}
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyEvBrakeRegenerationLevelConfig) {
+ verifyProperty(VehicleProperty::EV_BRAKE_REGENERATION_LEVEL,
+ VehiclePropertyAccess::READ_WRITE, VehiclePropertyChangeMode::ON_CHANGE,
+ VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::INT32);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyEvCurrentBatteryCapacityConfig) {
+ verifyProperty(VehicleProperty::EV_CURRENT_BATTERY_CAPACITY, VehiclePropertyAccess::READ,
+ VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+ VehicleArea::GLOBAL, VehiclePropertyType::FLOAT);
+}
+
TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyDoorChildLockEnabledConfig) {
verifyProperty(VehicleProperty::DOOR_CHILD_LOCK_ENABLED, VehiclePropertyAccess::READ_WRITE,
VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
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/biometrics/fingerprint/aidl/default/fingerprint-example.rc b/biometrics/fingerprint/aidl/default/fingerprint-example.rc
index 574438e..10db00d 100644
--- a/biometrics/fingerprint/aidl/default/fingerprint-example.rc
+++ b/biometrics/fingerprint/aidl/default/fingerprint-example.rc
@@ -2,3 +2,8 @@
class hal
user nobody
group nobody
+ disabled
+on property:ro.vendor.fingerprint_virtual_hal_start=true
+ enable vendor.fingerprint-example
+on property:persist.vendor.fingerprint.virtual.type=*
+ enable vendor.fingerprint-example
diff --git a/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/Result.aidl b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/Result.aidl
index 07edae8..3464412 100644
--- a/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/Result.aidl
+++ b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/Result.aidl
@@ -40,5 +40,6 @@
INVALID_STATE = 3,
NOT_SUPPORTED = 4,
TIMEOUT = 5,
- UNKNOWN_ERROR = 6,
+ CANCELED = 6,
+ UNKNOWN_ERROR = 7,
}
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/ITunerCallback.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/ITunerCallback.aidl
index 1f0221c..8de12c8 100644
--- a/broadcastradio/aidl/android/hardware/broadcastradio/ITunerCallback.aidl
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/ITunerCallback.aidl
@@ -36,6 +36,7 @@
* @param result {@link Result#TIMEOUT} in case that tune(), seek() or
* step() is not completed within
* @link IBroadcastRadio#TUNER_TIMEOUT_MS}
+ * or {@link Result#CANCELED} if the command was canceled.
* @param selector A ProgramSelector structure passed from tune() call;
* empty for step() and seek().
*/
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/Result.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/Result.aidl
index 9985ccb..3f7ddac 100644
--- a/broadcastradio/aidl/android/hardware/broadcastradio/Result.aidl
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/Result.aidl
@@ -55,6 +55,12 @@
TIMEOUT,
/**
+ * Error used when a tune, seek, step or operation is canceled before
+ * being processed.
+ */
+ CANCELED,
+
+ /**
* Error that does not follow into the error categories above.
*/
UNKNOWN_ERROR,
diff --git a/broadcastradio/aidl/default/BroadcastRadio.cpp b/broadcastradio/aidl/default/BroadcastRadio.cpp
index 0209a0e..42e550e 100644
--- a/broadcastradio/aidl/default/BroadcastRadio.cpp
+++ b/broadcastradio/aidl/default/BroadcastRadio.cpp
@@ -238,7 +238,8 @@
}
callback->onCurrentProgramInfoChanged(programInfo);
};
- mThread->schedule(task, kTuneDelayTimeMs);
+ auto cancelTask = [program, callback]() { callback->onTuneFailed(Result::CANCELED, program); };
+ mThread->schedule(task, cancelTask, kTuneDelayTimeMs);
return ScopedAStatus::ok();
}
@@ -258,6 +259,7 @@
const auto& list = mVirtualRadio.getProgramList();
std::shared_ptr<ITunerCallback> callback = mCallback;
+ auto cancelTask = [callback]() { callback->onTuneFailed(Result::CANCELED, {}); };
if (list.empty()) {
mIsTuneCompleted = false;
auto task = [callback]() {
@@ -265,7 +267,7 @@
callback->onTuneFailed(Result::TIMEOUT, {});
};
- mThread->schedule(task, kSeekDelayTimeMs);
+ mThread->schedule(task, cancelTask, kSeekDelayTimeMs);
return ScopedAStatus::ok();
}
@@ -298,7 +300,7 @@
}
callback->onCurrentProgramInfoChanged(programInfo);
};
- mThread->schedule(task, kSeekDelayTimeMs);
+ mThread->schedule(task, cancelTask, kSeekDelayTimeMs);
return ScopedAStatus::ok();
}
@@ -352,7 +354,8 @@
}
callback->onCurrentProgramInfoChanged(programInfo);
};
- mThread->schedule(task, kStepDelayTimeMs);
+ auto cancelTask = [callback]() { callback->onTuneFailed(Result::CANCELED, {}); };
+ mThread->schedule(task, cancelTask, kStepDelayTimeMs);
return ScopedAStatus::ok();
}
diff --git a/broadcastradio/common/utils/WorkerThread.cpp b/broadcastradio/common/utils/WorkerThread.cpp
index dd87f53..43fd04a 100644
--- a/broadcastradio/common/utils/WorkerThread.cpp
+++ b/broadcastradio/common/utils/WorkerThread.cpp
@@ -18,14 +18,13 @@
namespace android {
-using std::chrono::milliseconds;
-using std::chrono::steady_clock;
using std::function;
using std::lock_guard;
using std::mutex;
-using std::priority_queue;
-using std::this_thread::sleep_for;
using std::unique_lock;
+using std::chrono::milliseconds;
+using std::chrono::steady_clock;
+using std::this_thread::sleep_for;
bool operator<(const WorkerThread::Task& lhs, const WorkerThread::Task& rhs) {
return lhs.when > rhs.when;
@@ -47,16 +46,26 @@
}
void WorkerThread::schedule(function<void()> task, milliseconds delay) {
+ auto cancelTask = []() {};
+ schedule(std::move(task), cancelTask, delay);
+}
+
+void WorkerThread::schedule(function<void()> task, function<void()> cancelTask,
+ milliseconds delay) {
auto when = steady_clock::now() + delay;
lock_guard<mutex> lk(mMut);
- mTasks.push(Task({when, task}));
+ mTasks.push(Task({when, std::move(task), std::move(cancelTask)}));
mCond.notify_one();
}
void WorkerThread::cancelAll() {
lock_guard<mutex> lk(mMut);
- priority_queue<Task>().swap(mTasks); // empty queue
+ while (!mTasks.empty()) {
+ auto task = mTasks.top();
+ task.onCanceled();
+ mTasks.pop();
+ }
}
void WorkerThread::threadLoop() {
diff --git a/broadcastradio/common/utils/include/broadcastradio-utils/WorkerThread.h b/broadcastradio/common/utils/include/broadcastradio-utils/WorkerThread.h
index 62bede6..457b57e 100644
--- a/broadcastradio/common/utils/include/broadcastradio-utils/WorkerThread.h
+++ b/broadcastradio/common/utils/include/broadcastradio-utils/WorkerThread.h
@@ -28,12 +28,15 @@
virtual ~WorkerThread();
void schedule(std::function<void()> task, std::chrono::milliseconds delay);
+ void schedule(std::function<void()> task, std::function<void()> cancelTask,
+ std::chrono::milliseconds delay);
void cancelAll();
private:
struct Task {
std::chrono::time_point<std::chrono::steady_clock> when;
std::function<void()> what;
+ std::function<void()> onCanceled;
};
friend bool operator<(const Task& lhs, const Task& rhs);
diff --git a/camera/common/aidl/Android.bp b/camera/common/aidl/Android.bp
index d21ae58..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: {
@@ -19,6 +20,9 @@
java: {
enabled: false,
},
+ rust: {
+ enabled: true,
+ }
},
versions_with_info: [
{
diff --git a/camera/common/1.0/default/Android.bp b/camera/common/default/Android.bp
similarity index 78%
rename from camera/common/1.0/default/Android.bp
rename to camera/common/default/Android.bp
index 4a5ca83..e8c8f9d 100644
--- a/camera/common/1.0/default/Android.bp
+++ b/camera/common/default/Android.bp
@@ -8,7 +8,7 @@
}
cc_library_static {
- name: "android.hardware.camera.common@1.0-helper",
+ name: "android.hardware.camera.common-helper",
vendor_available: true,
defaults: ["hidl_defaults"],
srcs: [
@@ -18,6 +18,7 @@
"VendorTagDescriptor.cpp",
"HandleImporter.cpp",
"Exif.cpp",
+ "SimpleThread.cpp",
],
cflags: [
"-Werror",
@@ -37,3 +38,11 @@
include_dirs: ["system/media/private/camera/include"],
export_include_dirs: ["include"],
}
+
+// NOTE: Deprecated module kept for compatibility reasons.
+// Depend on "android.hardware.camera.common-helper" instead
+cc_library_static {
+ name: "android.hardware.camera.common@1.0-helper",
+ vendor_available: true,
+ whole_static_libs: ["android.hardware.camera.common-helper"],
+}
diff --git a/camera/common/1.0/default/CameraMetadata.cpp b/camera/common/default/CameraMetadata.cpp
similarity index 74%
rename from camera/common/1.0/default/CameraMetadata.cpp
rename to camera/common/default/CameraMetadata.cpp
index eb1bd1c..ed56261 100644
--- a/camera/common/1.0/default/CameraMetadata.cpp
+++ b/camera/common/default/CameraMetadata.cpp
@@ -27,44 +27,36 @@
namespace hardware {
namespace camera {
namespace common {
-namespace V1_0 {
namespace helper {
-#define ALIGN_TO(val, alignment) \
- (((uintptr_t)(val) + ((alignment) - 1)) & ~((alignment) - 1))
+#define ALIGN_TO(val, alignment) (((uintptr_t)(val) + ((alignment)-1)) & ~((alignment)-1))
-CameraMetadata::CameraMetadata() :
- mBuffer(NULL), mLocked(false) {
-}
+CameraMetadata::CameraMetadata() : mBuffer(NULL), mLocked(false) {}
-CameraMetadata::CameraMetadata(size_t entryCapacity, size_t dataCapacity) :
- mLocked(false)
-{
+CameraMetadata::CameraMetadata(size_t entryCapacity, size_t dataCapacity) : mLocked(false) {
mBuffer = allocate_camera_metadata(entryCapacity, dataCapacity);
}
-CameraMetadata::CameraMetadata(const CameraMetadata &other) :
- mLocked(false) {
+CameraMetadata::CameraMetadata(const CameraMetadata& other) : mLocked(false) {
mBuffer = clone_camera_metadata(other.mBuffer);
}
-CameraMetadata::CameraMetadata(camera_metadata_t *buffer) :
- mBuffer(NULL), mLocked(false) {
+CameraMetadata::CameraMetadata(camera_metadata_t* buffer) : mBuffer(NULL), mLocked(false) {
acquire(buffer);
}
-CameraMetadata &CameraMetadata::operator=(const CameraMetadata &other) {
+CameraMetadata& CameraMetadata::operator=(const CameraMetadata& other) {
return operator=(other.mBuffer);
}
-CameraMetadata &CameraMetadata::operator=(const camera_metadata_t *buffer) {
+CameraMetadata& CameraMetadata::operator=(const camera_metadata_t* buffer) {
if (mLocked) {
ALOGE("%s: Assignment to a locked CameraMetadata!", __FUNCTION__);
return *this;
}
if (CC_LIKELY(buffer != mBuffer)) {
- camera_metadata_t *newBuffer = clone_camera_metadata(buffer);
+ camera_metadata_t* newBuffer = clone_camera_metadata(buffer);
clear();
mBuffer = newBuffer;
}
@@ -81,14 +73,13 @@
return mBuffer;
}
-status_t CameraMetadata::unlock(const camera_metadata_t *buffer) const {
+status_t CameraMetadata::unlock(const camera_metadata_t* buffer) const {
if (!mLocked) {
ALOGE("%s: Can't unlock a non-locked CameraMetadata!", __FUNCTION__);
return INVALID_OPERATION;
}
if (buffer != mBuffer) {
- ALOGE("%s: Can't unlock CameraMetadata with wrong pointer!",
- __FUNCTION__);
+ ALOGE("%s: Can't unlock CameraMetadata with wrong pointer!", __FUNCTION__);
return BAD_VALUE;
}
mLocked = false;
@@ -100,7 +91,7 @@
ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
return NULL;
}
- camera_metadata_t *released = mBuffer;
+ camera_metadata_t* released = mBuffer;
mBuffer = NULL;
return released;
}
@@ -116,7 +107,7 @@
}
}
-void CameraMetadata::acquire(camera_metadata_t *buffer) {
+void CameraMetadata::acquire(camera_metadata_t* buffer) {
if (mLocked) {
ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
return;
@@ -124,12 +115,11 @@
clear();
mBuffer = buffer;
- ALOGE_IF(validate_camera_metadata_structure(mBuffer, /*size*/NULL) != OK,
- "%s: Failed to validate metadata structure %p",
- __FUNCTION__, buffer);
+ ALOGE_IF(validate_camera_metadata_structure(mBuffer, /*size*/ NULL) != OK,
+ "%s: Failed to validate metadata structure %p", __FUNCTION__, buffer);
}
-void CameraMetadata::acquire(CameraMetadata &other) {
+void CameraMetadata::acquire(CameraMetadata& other) {
if (mLocked) {
ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
return;
@@ -137,7 +127,7 @@
acquire(other.release());
}
-status_t CameraMetadata::append(const CameraMetadata &other) {
+status_t CameraMetadata::append(const CameraMetadata& other) {
return append(other.mBuffer);
}
@@ -154,8 +144,7 @@
}
size_t CameraMetadata::entryCount() const {
- return (mBuffer == NULL) ? 0 :
- get_camera_metadata_entry_count(mBuffer);
+ return (mBuffer == NULL) ? 0 : get_camera_metadata_entry_count(mBuffer);
}
bool CameraMetadata::isEmpty() const {
@@ -172,11 +161,11 @@
status_t CameraMetadata::checkType(uint32_t tag, uint8_t expectedType) {
int tagType = get_local_camera_metadata_tag_type(tag, mBuffer);
- if ( CC_UNLIKELY(tagType == -1)) {
+ if (CC_UNLIKELY(tagType == -1)) {
ALOGE("Update metadata entry: Unknown tag %d", tag);
return INVALID_OPERATION;
}
- if ( CC_UNLIKELY(tagType != expectedType) ) {
+ if (CC_UNLIKELY(tagType != expectedType)) {
ALOGE("Mismatched tag type when updating entry %s (%d) of type %s; "
"got type %s data instead ",
get_local_camera_metadata_tag_name(tag, mBuffer), tag,
@@ -186,112 +175,105 @@
return OK;
}
-status_t CameraMetadata::update(uint32_t tag,
- const int32_t *data, size_t data_count) {
+status_t CameraMetadata::update(uint32_t tag, const int32_t* data, size_t data_count) {
status_t res;
if (mLocked) {
ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
return INVALID_OPERATION;
}
- if ( (res = checkType(tag, TYPE_INT32)) != OK) {
+ if ((res = checkType(tag, TYPE_INT32)) != OK) {
return res;
}
return updateImpl(tag, (const void*)data, data_count);
}
-status_t CameraMetadata::update(uint32_t tag,
- const uint8_t *data, size_t data_count) {
+status_t CameraMetadata::update(uint32_t tag, const uint8_t* data, size_t data_count) {
status_t res;
if (mLocked) {
ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
return INVALID_OPERATION;
}
- if ( (res = checkType(tag, TYPE_BYTE)) != OK) {
+ if ((res = checkType(tag, TYPE_BYTE)) != OK) {
return res;
}
return updateImpl(tag, (const void*)data, data_count);
}
-status_t CameraMetadata::update(uint32_t tag,
- const float *data, size_t data_count) {
+status_t CameraMetadata::update(uint32_t tag, const float* data, size_t data_count) {
status_t res;
if (mLocked) {
ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
return INVALID_OPERATION;
}
- if ( (res = checkType(tag, TYPE_FLOAT)) != OK) {
+ if ((res = checkType(tag, TYPE_FLOAT)) != OK) {
return res;
}
return updateImpl(tag, (const void*)data, data_count);
}
-status_t CameraMetadata::update(uint32_t tag,
- const int64_t *data, size_t data_count) {
+status_t CameraMetadata::update(uint32_t tag, const int64_t* data, size_t data_count) {
status_t res;
if (mLocked) {
ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
return INVALID_OPERATION;
}
- if ( (res = checkType(tag, TYPE_INT64)) != OK) {
+ if ((res = checkType(tag, TYPE_INT64)) != OK) {
return res;
}
return updateImpl(tag, (const void*)data, data_count);
}
-status_t CameraMetadata::update(uint32_t tag,
- const double *data, size_t data_count) {
+status_t CameraMetadata::update(uint32_t tag, const double* data, size_t data_count) {
status_t res;
if (mLocked) {
ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
return INVALID_OPERATION;
}
- if ( (res = checkType(tag, TYPE_DOUBLE)) != OK) {
+ if ((res = checkType(tag, TYPE_DOUBLE)) != OK) {
return res;
}
return updateImpl(tag, (const void*)data, data_count);
}
-status_t CameraMetadata::update(uint32_t tag,
- const camera_metadata_rational_t *data, size_t data_count) {
+status_t CameraMetadata::update(uint32_t tag, const camera_metadata_rational_t* data,
+ size_t data_count) {
status_t res;
if (mLocked) {
ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
return INVALID_OPERATION;
}
- if ( (res = checkType(tag, TYPE_RATIONAL)) != OK) {
+ if ((res = checkType(tag, TYPE_RATIONAL)) != OK) {
return res;
}
return updateImpl(tag, (const void*)data, data_count);
}
-status_t CameraMetadata::update(uint32_t tag,
- const String8 &string) {
+status_t CameraMetadata::update(uint32_t tag, const String8& string) {
status_t res;
if (mLocked) {
ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
return INVALID_OPERATION;
}
- if ( (res = checkType(tag, TYPE_BYTE)) != OK) {
+ if ((res = checkType(tag, TYPE_BYTE)) != OK) {
return res;
}
// string.size() doesn't count the null termination character.
return updateImpl(tag, (const void*)string.string(), string.size() + 1);
}
-status_t CameraMetadata::update(const camera_metadata_ro_entry &entry) {
+status_t CameraMetadata::update(const camera_metadata_ro_entry& entry) {
status_t res;
if (mLocked) {
ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
return INVALID_OPERATION;
}
- if ( (res = checkType(entry.tag, entry.type)) != OK) {
+ if ((res = checkType(entry.tag, entry.type)) != OK) {
return res;
}
return updateImpl(entry.tag, (const void*)entry.data.u8, entry.count);
}
-status_t CameraMetadata::updateImpl(uint32_t tag, const void *data,
- size_t data_count) {
+status_t CameraMetadata::updateImpl(uint32_t tag, const void* data, size_t data_count) {
status_t res;
if (mLocked) {
ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
@@ -308,13 +290,11 @@
uintptr_t bufAddr = reinterpret_cast<uintptr_t>(mBuffer);
uintptr_t dataAddr = reinterpret_cast<uintptr_t>(data);
if (dataAddr > bufAddr && dataAddr < (bufAddr + bufferSize)) {
- ALOGE("%s: Update attempted with data from the same metadata buffer!",
- __FUNCTION__);
+ ALOGE("%s: Update attempted with data from the same metadata buffer!", __FUNCTION__);
return INVALID_OPERATION;
}
- size_t data_size = calculate_camera_metadata_entry_data_size(type,
- data_count);
+ size_t data_size = calculate_camera_metadata_entry_data_size(type, data_count);
res = resizeIfNeeded(1, data_size);
@@ -322,11 +302,9 @@
camera_metadata_entry_t entry;
res = find_camera_metadata_entry(mBuffer, tag, &entry);
if (res == NAME_NOT_FOUND) {
- res = add_camera_metadata_entry(mBuffer,
- tag, data, data_count);
+ res = add_camera_metadata_entry(mBuffer, tag, data, data_count);
} else if (res == OK) {
- res = update_camera_metadata_entry(mBuffer,
- entry.index, data, data_count, NULL);
+ res = update_camera_metadata_entry(mBuffer, entry.index, data, data_count, NULL);
}
}
@@ -337,11 +315,10 @@
}
IF_ALOGV() {
- ALOGE_IF(validate_camera_metadata_structure(mBuffer, /*size*/NULL) !=
- OK,
+ ALOGE_IF(validate_camera_metadata_structure(mBuffer, /*size*/ NULL) != OK,
- "%s: Failed to validate metadata structure after update %p",
- __FUNCTION__, mBuffer);
+ "%s: Failed to validate metadata structure after update %p", __FUNCTION__,
+ mBuffer);
}
return res;
@@ -361,7 +338,7 @@
return entry;
}
res = find_camera_metadata_entry(mBuffer, tag, &entry);
- if (CC_UNLIKELY( res != OK )) {
+ if (CC_UNLIKELY(res != OK)) {
entry.count = 0;
entry.data.u8 = NULL;
}
@@ -372,7 +349,7 @@
status_t res;
camera_metadata_ro_entry entry;
res = find_camera_metadata_ro_entry(mBuffer, tag, &entry);
- if (CC_UNLIKELY( res != OK )) {
+ if (CC_UNLIKELY(res != OK)) {
entry.count = 0;
entry.data.u8 = NULL;
}
@@ -418,23 +395,17 @@
} else {
size_t currentEntryCount = get_camera_metadata_entry_count(mBuffer);
size_t currentEntryCap = get_camera_metadata_entry_capacity(mBuffer);
- size_t newEntryCount = currentEntryCount +
- extraEntries;
- newEntryCount = (newEntryCount > currentEntryCap) ?
- newEntryCount * 2 : currentEntryCap;
+ size_t newEntryCount = currentEntryCount + extraEntries;
+ newEntryCount = (newEntryCount > currentEntryCap) ? newEntryCount * 2 : currentEntryCap;
size_t currentDataCount = get_camera_metadata_data_count(mBuffer);
size_t currentDataCap = get_camera_metadata_data_capacity(mBuffer);
- size_t newDataCount = currentDataCount +
- extraData;
- newDataCount = (newDataCount > currentDataCap) ?
- newDataCount * 2 : currentDataCap;
+ size_t newDataCount = currentDataCount + extraData;
+ newDataCount = (newDataCount > currentDataCap) ? newDataCount * 2 : currentDataCap;
- if (newEntryCount > currentEntryCap ||
- newDataCount > currentDataCap) {
- camera_metadata_t *oldBuffer = mBuffer;
- mBuffer = allocate_camera_metadata(newEntryCount,
- newDataCount);
+ if (newEntryCount > currentEntryCap || newDataCount > currentDataCap) {
+ camera_metadata_t* oldBuffer = mBuffer;
+ mBuffer = allocate_camera_metadata(newEntryCount, newDataCount);
if (mBuffer == NULL) {
ALOGE("%s: Can't allocate larger metadata buffer", __FUNCTION__);
return NO_MEMORY;
@@ -462,14 +433,13 @@
mBuffer = otherBuf;
}
-status_t CameraMetadata::getTagFromName(const char *name,
- const VendorTagDescriptor* vTags, uint32_t *tag) {
-
+status_t CameraMetadata::getTagFromName(const char* name, const VendorTagDescriptor* vTags,
+ uint32_t* tag) {
if (name == nullptr || tag == nullptr) return BAD_VALUE;
size_t nameLength = strlen(name);
- const SortedVector<String8> *vendorSections;
+ const SortedVector<String8>* vendorSections;
size_t vendorSectionCount = 0;
if (vTags != NULL) {
@@ -478,18 +448,18 @@
}
// First, find the section by the longest string match
- const char *section = NULL;
+ const char* section = NULL;
size_t sectionIndex = 0;
size_t sectionLength = 0;
size_t totalSectionCount = ANDROID_SECTION_COUNT + vendorSectionCount;
for (size_t i = 0; i < totalSectionCount; ++i) {
-
- const char *str = (i < ANDROID_SECTION_COUNT) ? camera_metadata_section_names[i] :
- (*vendorSections)[i - ANDROID_SECTION_COUNT].string();
+ const char* str = (i < ANDROID_SECTION_COUNT)
+ ? camera_metadata_section_names[i]
+ : (*vendorSections)[i - ANDROID_SECTION_COUNT].string();
ALOGV("%s: Trying to match against section '%s'", __FUNCTION__, str);
- if (strstr(name, str) == name) { // name begins with the section name
+ if (strstr(name, str) == name) { // name begins with the section name
size_t strLength = strlen(str);
ALOGV("%s: Name begins with section name", __FUNCTION__);
@@ -508,12 +478,11 @@
if (section == NULL) {
return NAME_NOT_FOUND;
} else {
- ALOGV("%s: Found matched section '%s' (%zu)",
- __FUNCTION__, section, sectionIndex);
+ ALOGV("%s: Found matched section '%s' (%zu)", __FUNCTION__, section, sectionIndex);
}
// Get the tag name component of the name
- const char *nameTagName = name + sectionLength + 1; // x.y.z -> z
+ const char* nameTagName = name + sectionLength + 1; // x.y.z -> z
if (sectionLength + 1 >= nameLength) {
return BAD_VALUE;
}
@@ -522,16 +491,15 @@
uint32_t candidateTag = 0;
if (sectionIndex < ANDROID_SECTION_COUNT) {
// Match built-in tags (typically android.*)
- uint32_t tagBegin, tagEnd; // [tagBegin, tagEnd)
+ uint32_t tagBegin, tagEnd; // [tagBegin, tagEnd)
tagBegin = camera_metadata_section_bounds[sectionIndex][0];
tagEnd = camera_metadata_section_bounds[sectionIndex][1];
for (candidateTag = tagBegin; candidateTag < tagEnd; ++candidateTag) {
- const char *tagName = get_camera_metadata_tag_name(candidateTag);
+ const char* tagName = get_camera_metadata_tag_name(candidateTag);
if (strcmp(nameTagName, tagName) == 0) {
- ALOGV("%s: Found matched tag '%s' (%d)",
- __FUNCTION__, tagName, candidateTag);
+ ALOGV("%s: Found matched tag '%s' (%d)", __FUNCTION__, tagName, candidateTag);
break;
}
}
@@ -554,10 +522,8 @@
return OK;
}
-
-} // namespace helper
-} // namespace V1_0
-} // namespace common
-} // namespace camera
-} // namespace hardware
-} // namespace android
+} // namespace helper
+} // namespace common
+} // namespace camera
+} // namespace hardware
+} // namespace android
diff --git a/camera/common/1.0/default/CameraModule.cpp b/camera/common/default/CameraModule.cpp
similarity index 84%
rename from camera/common/1.0/default/CameraModule.cpp
rename to camera/common/default/CameraModule.cpp
index 16fb85c..9960842 100644
--- a/camera/common/1.0/default/CameraModule.cpp
+++ b/camera/common/default/CameraModule.cpp
@@ -16,7 +16,7 @@
#define LOG_TAG "CamComm1.0-CamModule"
#define ATRACE_TAG ATRACE_TAG_CAMERA
-//#define LOG_NDEBUG 0
+// #define LOG_NDEBUG 0
#include <utils/Trace.h>
@@ -26,11 +26,9 @@
namespace hardware {
namespace camera {
namespace common {
-namespace V1_0 {
namespace helper {
-void CameraModule::deriveCameraCharacteristicsKeys(
- uint32_t deviceVersion, CameraMetadata &chars) {
+void CameraModule::deriveCameraCharacteristicsKeys(uint32_t deviceVersion, CameraMetadata& chars) {
ATRACE_CALL();
Vector<int32_t> derivedCharKeys;
@@ -40,9 +38,9 @@
if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_3) {
Vector<uint8_t> controlModes;
uint8_t data = ANDROID_CONTROL_AE_LOCK_AVAILABLE_TRUE;
- chars.update(ANDROID_CONTROL_AE_LOCK_AVAILABLE, &data, /*count*/1);
+ chars.update(ANDROID_CONTROL_AE_LOCK_AVAILABLE, &data, /*count*/ 1);
data = ANDROID_CONTROL_AWB_LOCK_AVAILABLE_TRUE;
- chars.update(ANDROID_CONTROL_AWB_LOCK_AVAILABLE, &data, /*count*/1);
+ chars.update(ANDROID_CONTROL_AWB_LOCK_AVAILABLE, &data, /*count*/ 1);
controlModes.push(ANDROID_CONTROL_MODE_AUTO);
camera_metadata_entry entry = chars.find(ANDROID_CONTROL_AVAILABLE_SCENE_MODES);
if (entry.count > 1 || entry.data.u8[0] != ANDROID_CONTROL_SCENE_MODE_DISABLED) {
@@ -121,14 +119,14 @@
if (entry.count > 0) {
Vector<int32_t> highSpeedConfig;
for (size_t i = 0; i < entry.count; i += 4) {
- highSpeedConfig.add(entry.data.i32[i]); // width
- highSpeedConfig.add(entry.data.i32[i + 1]); // height
- highSpeedConfig.add(entry.data.i32[i + 2]); // fps_min
- highSpeedConfig.add(entry.data.i32[i + 3]); // fps_max
- highSpeedConfig.add(1); // batchSize_max. default to 1 for HAL3.2
+ highSpeedConfig.add(entry.data.i32[i]); // width
+ highSpeedConfig.add(entry.data.i32[i + 1]); // height
+ highSpeedConfig.add(entry.data.i32[i + 2]); // fps_min
+ highSpeedConfig.add(entry.data.i32[i + 3]); // fps_max
+ highSpeedConfig.add(1); // batchSize_max. default to 1 for HAL3.2
}
chars.update(ANDROID_CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS,
- highSpeedConfig);
+ highSpeedConfig);
}
}
@@ -145,25 +143,23 @@
const int STREAM_IS_INPUT_OFFSET = 3;
Vector<int32_t> rawOpaqueSizes;
- for (size_t i=0; i < entry.count; i += STREAM_CONFIGURATION_SIZE) {
+ for (size_t i = 0; i < entry.count; i += STREAM_CONFIGURATION_SIZE) {
int32_t format = entry.data.i32[i + STREAM_FORMAT_OFFSET];
int32_t width = entry.data.i32[i + STREAM_WIDTH_OFFSET];
int32_t height = entry.data.i32[i + STREAM_HEIGHT_OFFSET];
int32_t isInput = entry.data.i32[i + STREAM_IS_INPUT_OFFSET];
if (isInput == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
- format == HAL_PIXEL_FORMAT_RAW_OPAQUE) {
+ format == HAL_PIXEL_FORMAT_RAW_OPAQUE) {
supportRawOpaque = true;
rawOpaqueSizes.push(width);
rawOpaqueSizes.push(height);
// 2 bytes per pixel. This rough estimation is only used when
// HAL does not fill in the opaque raw size
- rawOpaqueSizes.push(width * height *2);
+ rawOpaqueSizes.push(width * height * 2);
}
if (isInput == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
- (format == HAL_PIXEL_FORMAT_RAW16 ||
- format == HAL_PIXEL_FORMAT_RAW10 ||
- format == HAL_PIXEL_FORMAT_RAW12 ||
- format == HAL_PIXEL_FORMAT_RAW_OPAQUE)) {
+ (format == HAL_PIXEL_FORMAT_RAW16 || format == HAL_PIXEL_FORMAT_RAW10 ||
+ format == HAL_PIXEL_FORMAT_RAW12 || format == HAL_PIXEL_FORMAT_RAW_OPAQUE)) {
supportAnyRaw = true;
}
}
@@ -183,9 +179,7 @@
entry = chars.find(ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE);
if (entry.count == 0) {
// Fill in default value (100, 100)
- chars.update(
- ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE,
- defaultRange, 2);
+ chars.update(ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE, defaultRange, 2);
derivedCharKeys.push(ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE);
// Actual request/results will be derived by camera device.
derivedRequestKeys.push(ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST);
@@ -197,22 +191,19 @@
// Add those newly added keys to AVAILABLE_CHARACTERISTICS_KEYS
// This has to be done at this end of this function.
if (derivedCharKeys.size() > 0) {
- appendAvailableKeys(
- chars, ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, derivedCharKeys);
+ appendAvailableKeys(chars, ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, derivedCharKeys);
}
if (derivedRequestKeys.size() > 0) {
- appendAvailableKeys(
- chars, ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS, derivedRequestKeys);
+ appendAvailableKeys(chars, ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS, derivedRequestKeys);
}
if (derivedResultKeys.size() > 0) {
- appendAvailableKeys(
- chars, ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, derivedResultKeys);
+ appendAvailableKeys(chars, ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, derivedResultKeys);
}
return;
}
-void CameraModule::appendAvailableKeys(CameraMetadata &chars,
- int32_t keyTag, const Vector<int32_t>& appendKeys) {
+void CameraModule::appendAvailableKeys(CameraMetadata& chars, int32_t keyTag,
+ const Vector<int32_t>& appendKeys) {
camera_metadata_entry entry = chars.find(keyTag);
Vector<int32_t> availableKeys;
availableKeys.setCapacity(entry.count + appendKeys.size());
@@ -225,7 +216,7 @@
chars.update(keyTag, availableKeys);
}
-CameraModule::CameraModule(camera_module_t *module) : mNumberOfCameras(0) {
+CameraModule::CameraModule(camera_module_t* module) : mNumberOfCameras(0) {
if (module == NULL) {
ALOGE("%s: camera hardware module must not be null", __FUNCTION__);
assert(0);
@@ -233,8 +224,7 @@
mModule = module;
}
-CameraModule::~CameraModule()
-{
+CameraModule::~CameraModule() {
while (mCameraInfoMap.size() > 0) {
camera_info cameraInfo = mCameraInfoMap.editValueAt(0);
if (cameraInfo.static_camera_characteristics != NULL) {
@@ -256,8 +246,7 @@
int CameraModule::init() {
ATRACE_CALL();
int res = OK;
- if (getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_4 &&
- mModule->init != NULL) {
+ if (getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_4 && mModule->init != NULL) {
ATRACE_BEGIN("camera_module->init");
res = mModule->init();
ATRACE_END();
@@ -267,7 +256,7 @@
return res;
}
-int CameraModule::getCameraInfo(int cameraId, struct camera_info *info) {
+int CameraModule::getCameraInfo(int cameraId, struct camera_info* info) {
ATRACE_CALL();
Mutex::Autolock lock(mCameraInfoLock);
if (cameraId < 0) {
@@ -318,7 +307,7 @@
return OK;
}
-int CameraModule::getPhysicalCameraInfo(int physicalCameraId, camera_metadata_t **physicalInfo) {
+int CameraModule::getPhysicalCameraInfo(int physicalCameraId, camera_metadata_t** physicalInfo) {
ATRACE_CALL();
Mutex::Autolock lock(mCameraInfoLock);
if (physicalCameraId < mNumberOfCameras) {
@@ -330,7 +319,7 @@
int apiVersion = mModule->common.module_api_version;
if (apiVersion < CAMERA_MODULE_API_VERSION_2_5) {
ALOGE("%s: Module version must be at least 2.5 to handle getPhysicalCameraInfo",
- __FUNCTION__);
+ __FUNCTION__);
return -ENODEV;
}
if (mModule->get_physical_camera_info == nullptr) {
@@ -341,7 +330,7 @@
ssize_t index = mPhysicalCameraInfoMap.indexOfKey(physicalCameraId);
if (index == NAME_NOT_FOUND) {
// Get physical camera characteristics, and cache it
- camera_metadata_t *info = nullptr;
+ camera_metadata_t* info = nullptr;
ATRACE_BEGIN("camera_module->get_physical_camera_info");
int ret = mModule->get_physical_camera_info(physicalCameraId, &info);
ATRACE_END();
@@ -396,8 +385,7 @@
return mModule->open_legacy != NULL;
}
-int CameraModule::openLegacy(
- const char* id, uint32_t halVersion, struct hw_device_t** device) {
+int CameraModule::openLegacy(const char* id, uint32_t halVersion, struct hw_device_t** device) {
int res;
ATRACE_BEGIN("camera_module->open_legacy");
res = mModule->open_legacy(&mModule->common, id, halVersion, device);
@@ -413,7 +401,7 @@
return numCameras;
}
-int CameraModule::setCallbacks(const camera_module_callbacks_t *callbacks) {
+int CameraModule::setCallbacks(const camera_module_callbacks_t* callbacks) {
int res = OK;
ATRACE_BEGIN("camera_module->set_callbacks");
if (getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_1) {
@@ -438,8 +426,7 @@
bool CameraModule::isSetTorchModeSupported() const {
if (getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_4) {
if (mModule->set_torch_mode == NULL) {
- ALOGE("%s: Module 2.4 device must support set torch API!",
- __FUNCTION__);
+ ALOGE("%s: Module 2.4 device must support set torch API!", __FUNCTION__);
return false;
}
return true;
@@ -457,7 +444,7 @@
return res;
}
-int CameraModule::isStreamCombinationSupported(int cameraId, camera_stream_combination_t *streams) {
+int CameraModule::isStreamCombinationSupported(int cameraId, camera_stream_combination_t* streams) {
int res = INVALID_OPERATION;
if (mModule->is_stream_combination_supported != NULL) {
ATRACE_BEGIN("camera_module->is_stream_combination_supported");
@@ -468,44 +455,41 @@
}
void CameraModule::notifyDeviceStateChange(uint64_t deviceState) {
- if (getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_5 &&
- mModule->notify_device_state_change != NULL) {
- ATRACE_BEGIN("camera_module->notify_device_state_change");
- ALOGI("%s: calling notify_device_state_change with state %" PRId64, __FUNCTION__,
- deviceState);
- mModule->notify_device_state_change(deviceState);
- ATRACE_END();
- }
+ if (getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_5 &&
+ mModule->notify_device_state_change != NULL) {
+ ATRACE_BEGIN("camera_module->notify_device_state_change");
+ ALOGI("%s: calling notify_device_state_change with state %" PRId64, __FUNCTION__,
+ deviceState);
+ mModule->notify_device_state_change(deviceState);
+ ATRACE_END();
+ }
}
-bool CameraModule::isLogicalMultiCamera(
- const common::V1_0::helper::CameraMetadata& metadata,
- std::unordered_set<std::string>* physicalCameraIds) {
+bool CameraModule::isLogicalMultiCamera(const common::helper::CameraMetadata& metadata,
+ std::unordered_set<std::string>* physicalCameraIds) {
if (physicalCameraIds == nullptr) {
ALOGE("%s: physicalCameraIds must not be null", __FUNCTION__);
return false;
}
bool isLogicalMultiCamera = false;
- camera_metadata_ro_entry_t capabilities =
- metadata.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
+ camera_metadata_ro_entry_t capabilities = metadata.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
for (size_t i = 0; i < capabilities.count; i++) {
if (capabilities.data.u8[i] ==
- ANDROID_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA) {
+ ANDROID_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA) {
isLogicalMultiCamera = true;
break;
}
}
if (isLogicalMultiCamera) {
- camera_metadata_ro_entry_t entry =
- metadata.find(ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS);
+ camera_metadata_ro_entry_t entry = metadata.find(ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS);
const uint8_t* ids = entry.data.u8;
size_t start = 0;
for (size_t i = 0; i < entry.count; ++i) {
if (ids[i] == '\0') {
if (start != i) {
- const char* physicalId = reinterpret_cast<const char*>(ids+start);
+ const char* physicalId = reinterpret_cast<const char*>(ids + start);
physicalCameraIds->emplace(physicalId);
}
start = i + 1;
@@ -516,7 +500,7 @@
}
status_t CameraModule::filterOpenErrorCode(status_t err) {
- switch(err) {
+ switch (err) {
case NO_ERROR:
case -EBUSY:
case -EINVAL:
@@ -533,9 +517,9 @@
// static_camera_characteristics
if (getDeviceVersion(cameraId) >= CAMERA_DEVICE_API_VERSION_3_0) {
std::unordered_set<std::string> physicalIds;
- camera_metadata_t *metadata = const_cast<camera_metadata_t*>(
+ camera_metadata_t* metadata = const_cast<camera_metadata_t*>(
mCameraInfoMap.valueFor(cameraId).static_camera_characteristics);
- common::V1_0::helper::CameraMetadata hidlMetadata(metadata);
+ common::helper::CameraMetadata hidlMetadata(metadata);
if (isLogicalMultiCamera(hidlMetadata, &physicalIds)) {
for (const auto& id : physicalIds) {
@@ -545,7 +529,7 @@
mPhysicalCameraInfoMap.removeItem(idInt);
} else {
ALOGE("%s: Cannot find corresponding static metadata for physical id %s",
- __FUNCTION__, id.c_str());
+ __FUNCTION__, id.c_str());
}
}
}
@@ -575,9 +559,8 @@
return mModule->common.dso;
}
-} // namespace helper
-} // namespace V1_0
-} // namespace common
-} // namespace camera
-} // namespace hardware
-} // namespace android
+} // namespace helper
+} // namespace common
+} // namespace camera
+} // namespace hardware
+} // namespace android
diff --git a/camera/common/1.0/default/CameraParameters.cpp b/camera/common/default/CameraParameters.cpp
similarity index 77%
rename from camera/common/1.0/default/CameraParameters.cpp
rename to camera/common/default/CameraParameters.cpp
index e707b08..37e28a2 100644
--- a/camera/common/1.0/default/CameraParameters.cpp
+++ b/camera/common/default/CameraParameters.cpp
@@ -18,17 +18,16 @@
#define LOG_TAG "CameraParams"
#include <log/log.h>
-#include <string.h>
#include <stdlib.h>
+#include <string.h>
+#include <system/graphics.h>
#include <unistd.h>
#include "CameraParameters.h"
-#include <system/graphics.h>
namespace android {
namespace hardware {
namespace camera {
namespace common {
-namespace V1_0 {
namespace helper {
// Parameter keys to communicate between camera application and driver.
@@ -79,7 +78,8 @@
const char CameraParameters::KEY_AUTO_EXPOSURE_LOCK[] = "auto-exposure-lock";
const char CameraParameters::KEY_AUTO_EXPOSURE_LOCK_SUPPORTED[] = "auto-exposure-lock-supported";
const char CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK[] = "auto-whitebalance-lock";
-const char CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK_SUPPORTED[] = "auto-whitebalance-lock-supported";
+const char CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK_SUPPORTED[] =
+ "auto-whitebalance-lock-supported";
const char CameraParameters::KEY_MAX_NUM_METERING_AREAS[] = "max-num-metering-areas";
const char CameraParameters::KEY_METERING_AREAS[] = "metering-areas";
const char CameraParameters::KEY_ZOOM[] = "zoom";
@@ -91,7 +91,8 @@
const char CameraParameters::KEY_VIDEO_FRAME_FORMAT[] = "video-frame-format";
const char CameraParameters::KEY_VIDEO_SIZE[] = "video-size";
const char CameraParameters::KEY_SUPPORTED_VIDEO_SIZES[] = "video-size-values";
-const char CameraParameters::KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO[] = "preferred-preview-size-for-video";
+const char CameraParameters::KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO[] =
+ "preferred-preview-size-for-video";
const char CameraParameters::KEY_MAX_NUM_DETECTED_FACES_HW[] = "max-num-detected-faces-hw";
const char CameraParameters::KEY_MAX_NUM_DETECTED_FACES_SW[] = "max-num-detected-faces-sw";
const char CameraParameters::KEY_RECORDING_HINT[] = "recording-hint";
@@ -160,7 +161,7 @@
const char CameraParameters::PIXEL_FORMAT_YUV422SP[] = "yuv422sp";
const char CameraParameters::PIXEL_FORMAT_YUV420SP[] = "yuv420sp";
const char CameraParameters::PIXEL_FORMAT_YUV422I[] = "yuv422i-yuyv";
-const char CameraParameters::PIXEL_FORMAT_YUV420P[] = "yuv420p";
+const char CameraParameters::PIXEL_FORMAT_YUV420P[] = "yuv420p";
const char CameraParameters::PIXEL_FORMAT_RGB565[] = "rgb565";
const char CameraParameters::PIXEL_FORMAT_RGBA8888[] = "rgba8888";
const char CameraParameters::PIXEL_FORMAT_JPEG[] = "jpeg";
@@ -180,17 +181,11 @@
const char CameraParameters::LIGHTFX_LOWLIGHT[] = "low-light";
const char CameraParameters::LIGHTFX_HDR[] = "high-dynamic-range";
-CameraParameters::CameraParameters()
- : mMap()
-{
-}
+CameraParameters::CameraParameters() : mMap() {}
-CameraParameters::~CameraParameters()
-{
-}
+CameraParameters::~CameraParameters() {}
-String8 CameraParameters::flatten() const
-{
+String8 CameraParameters::flatten() const {
String8 flattened("");
size_t size = mMap.size();
@@ -202,31 +197,28 @@
flattened += k;
flattened += "=";
flattened += v;
- if (i != size-1)
- flattened += ";";
+ if (i != size - 1) flattened += ";";
}
return flattened;
}
-void CameraParameters::unflatten(const String8 ¶ms)
-{
- const char *a = params.string();
- const char *b;
+void CameraParameters::unflatten(const String8& params) {
+ const char* a = params.string();
+ const char* b;
mMap.clear();
for (;;) {
// Find the bounds of the key name.
b = strchr(a, '=');
- if (b == 0)
- break;
+ if (b == 0) break;
// Create the key string.
- String8 k(a, (size_t)(b-a));
+ String8 k(a, (size_t)(b - a));
// Find the value.
- a = b+1;
+ a = b + 1;
b = strchr(a, ';');
if (b == 0) {
// If there's no semicolon, this is the last item.
@@ -235,15 +227,13 @@
break;
}
- String8 v(a, (size_t)(b-a));
+ String8 v(a, (size_t)(b - a));
mMap.add(k, v);
- a = b+1;
+ a = b + 1;
}
}
-
-void CameraParameters::set(const char *key, const char *value)
-{
+void CameraParameters::set(const char* key, const char* value) {
// i think i can do this with strspn()
if (strchr(key, '=') || strchr(key, ';')) {
// ALOGE("Key \"%s\"contains invalid character (= or ;)", key);
@@ -258,54 +248,44 @@
mMap.replaceValueFor(String8(key), String8(value));
}
-void CameraParameters::set(const char *key, int value)
-{
+void CameraParameters::set(const char* key, int value) {
char str[16];
sprintf(str, "%d", value);
set(key, str);
}
-void CameraParameters::setFloat(const char *key, float value)
-{
+void CameraParameters::setFloat(const char* key, float value) {
char str[16]; // 14 should be enough. We overestimate to be safe.
snprintf(str, sizeof(str), "%g", value);
set(key, str);
}
-const char *CameraParameters::get(const char *key) const
-{
+const char* CameraParameters::get(const char* key) const {
String8 v = mMap.valueFor(String8(key));
- if (v.length() == 0)
- return 0;
+ if (v.length() == 0) return 0;
return v.string();
}
-int CameraParameters::getInt(const char *key) const
-{
- const char *v = get(key);
- if (v == 0)
- return -1;
+int CameraParameters::getInt(const char* key) const {
+ const char* v = get(key);
+ if (v == 0) return -1;
return strtol(v, 0, 0);
}
-float CameraParameters::getFloat(const char *key) const
-{
- const char *v = get(key);
+float CameraParameters::getFloat(const char* key) const {
+ const char* v = get(key);
if (v == 0) return -1;
return strtof(v, 0);
}
-void CameraParameters::remove(const char *key)
-{
+void CameraParameters::remove(const char* key) {
mMap.removeItem(String8(key));
}
// Parse string like "640x480" or "10000,20000"
-static int parse_pair(const char *str, int *first, int *second, char delim,
- char **endptr = NULL)
-{
+static int parse_pair(const char* str, int* first, int* second, char delim, char** endptr = NULL) {
// Find the first integer.
- char *end;
+ char* end;
int w = (int)strtol(str, &end, 10);
// If a delimeter does not immediately follow, give up.
if (*end != delim) {
@@ -314,7 +294,7 @@
}
// Find the second integer, immediately after the delimeter.
- int h = (int)strtol(end+1, &end, 10);
+ int h = (int)strtol(end + 1, &end, 10);
*first = w;
*second = h;
@@ -326,18 +306,16 @@
return 0;
}
-static void parseSizesList(const char *sizesStr, Vector<Size> &sizes)
-{
+static void parseSizesList(const char* sizesStr, Vector<Size>& sizes) {
if (sizesStr == 0) {
return;
}
- char *sizeStartPtr = (char *)sizesStr;
+ char* sizeStartPtr = (char*)sizesStr;
while (true) {
int width, height;
- int success = parse_pair(sizeStartPtr, &width, &height, 'x',
- &sizeStartPtr);
+ int success = parse_pair(sizeStartPtr, &width, &height, 'x', &sizeStartPtr);
if (success == -1 || (*sizeStartPtr != ',' && *sizeStartPtr != '\0')) {
ALOGE("Picture sizes string \"%s\" contains invalid character.", sizesStr);
return;
@@ -351,119 +329,101 @@
}
}
-void CameraParameters::setPreviewSize(int width, int height)
-{
+void CameraParameters::setPreviewSize(int width, int height) {
char str[32];
sprintf(str, "%dx%d", width, height);
set(KEY_PREVIEW_SIZE, str);
}
-void CameraParameters::getPreviewSize(int *width, int *height) const
-{
+void CameraParameters::getPreviewSize(int* width, int* height) const {
*width = *height = -1;
// Get the current string, if it doesn't exist, leave the -1x-1
- const char *p = get(KEY_PREVIEW_SIZE);
- if (p == 0) return;
+ const char* p = get(KEY_PREVIEW_SIZE);
+ if (p == 0) return;
parse_pair(p, width, height, 'x');
}
-void CameraParameters::getPreferredPreviewSizeForVideo(int *width, int *height) const
-{
+void CameraParameters::getPreferredPreviewSizeForVideo(int* width, int* height) const {
*width = *height = -1;
- const char *p = get(KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO);
- if (p == 0) return;
+ const char* p = get(KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO);
+ if (p == 0) return;
parse_pair(p, width, height, 'x');
}
-void CameraParameters::getSupportedPreviewSizes(Vector<Size> &sizes) const
-{
- const char *previewSizesStr = get(KEY_SUPPORTED_PREVIEW_SIZES);
+void CameraParameters::getSupportedPreviewSizes(Vector<Size>& sizes) const {
+ const char* previewSizesStr = get(KEY_SUPPORTED_PREVIEW_SIZES);
parseSizesList(previewSizesStr, sizes);
}
-void CameraParameters::setVideoSize(int width, int height)
-{
+void CameraParameters::setVideoSize(int width, int height) {
char str[32];
sprintf(str, "%dx%d", width, height);
set(KEY_VIDEO_SIZE, str);
}
-void CameraParameters::getVideoSize(int *width, int *height) const
-{
+void CameraParameters::getVideoSize(int* width, int* height) const {
*width = *height = -1;
- const char *p = get(KEY_VIDEO_SIZE);
+ const char* p = get(KEY_VIDEO_SIZE);
if (p == 0) return;
parse_pair(p, width, height, 'x');
}
-void CameraParameters::getSupportedVideoSizes(Vector<Size> &sizes) const
-{
- const char *videoSizesStr = get(KEY_SUPPORTED_VIDEO_SIZES);
+void CameraParameters::getSupportedVideoSizes(Vector<Size>& sizes) const {
+ const char* videoSizesStr = get(KEY_SUPPORTED_VIDEO_SIZES);
parseSizesList(videoSizesStr, sizes);
}
-void CameraParameters::setPreviewFrameRate(int fps)
-{
+void CameraParameters::setPreviewFrameRate(int fps) {
set(KEY_PREVIEW_FRAME_RATE, fps);
}
-int CameraParameters::getPreviewFrameRate() const
-{
+int CameraParameters::getPreviewFrameRate() const {
return getInt(KEY_PREVIEW_FRAME_RATE);
}
-void CameraParameters::getPreviewFpsRange(int *min_fps, int *max_fps) const
-{
+void CameraParameters::getPreviewFpsRange(int* min_fps, int* max_fps) const {
*min_fps = *max_fps = -1;
- const char *p = get(KEY_PREVIEW_FPS_RANGE);
+ const char* p = get(KEY_PREVIEW_FPS_RANGE);
if (p == 0) return;
parse_pair(p, min_fps, max_fps, ',');
}
-void CameraParameters::setPreviewFormat(const char *format)
-{
+void CameraParameters::setPreviewFormat(const char* format) {
set(KEY_PREVIEW_FORMAT, format);
}
-const char *CameraParameters::getPreviewFormat() const
-{
+const char* CameraParameters::getPreviewFormat() const {
return get(KEY_PREVIEW_FORMAT);
}
-void CameraParameters::setPictureSize(int width, int height)
-{
+void CameraParameters::setPictureSize(int width, int height) {
char str[32];
sprintf(str, "%dx%d", width, height);
set(KEY_PICTURE_SIZE, str);
}
-void CameraParameters::getPictureSize(int *width, int *height) const
-{
+void CameraParameters::getPictureSize(int* width, int* height) const {
*width = *height = -1;
// Get the current string, if it doesn't exist, leave the -1x-1
- const char *p = get(KEY_PICTURE_SIZE);
+ const char* p = get(KEY_PICTURE_SIZE);
if (p == 0) return;
parse_pair(p, width, height, 'x');
}
-void CameraParameters::getSupportedPictureSizes(Vector<Size> &sizes) const
-{
- const char *pictureSizesStr = get(KEY_SUPPORTED_PICTURE_SIZES);
+void CameraParameters::getSupportedPictureSizes(Vector<Size>& sizes) const {
+ const char* pictureSizesStr = get(KEY_SUPPORTED_PICTURE_SIZES);
parseSizesList(pictureSizesStr, sizes);
}
-void CameraParameters::setPictureFormat(const char *format)
-{
+void CameraParameters::setPictureFormat(const char* format) {
set(KEY_PICTURE_FORMAT, format);
}
-const char *CameraParameters::getPictureFormat() const
-{
+const char* CameraParameters::getPictureFormat() const {
return get(KEY_PICTURE_FORMAT);
}
-void CameraParameters::dump() const
-{
+void CameraParameters::dump() const {
ALOGD("dump: mMap.size = %zu", mMap.size());
for (size_t i = 0; i < mMap.size(); i++) {
String8 k, v;
@@ -473,8 +433,7 @@
}
}
-status_t CameraParameters::dump(int fd, const Vector<String16>& /*args*/) const
-{
+status_t CameraParameters::dump(int fd, const Vector<String16>& /*args*/) const {
const size_t SIZE = 256;
char buffer[SIZE];
String8 result;
@@ -492,8 +451,7 @@
}
void CameraParameters::getSupportedPreviewFormats(Vector<int>& formats) const {
- const char* supportedPreviewFormats =
- get(CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS);
+ const char* supportedPreviewFormats = get(CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS);
if (supportedPreviewFormats == NULL) {
ALOGW("%s: No supported preview formats.", __FUNCTION__);
@@ -515,35 +473,31 @@
fmtStr.unlockBuffer(fmtStr.size());
}
-
int CameraParameters::previewFormatToEnum(const char* format) {
- return
- !format ?
- HAL_PIXEL_FORMAT_YCrCb_420_SP :
- !strcmp(format, PIXEL_FORMAT_YUV422SP) ?
- HAL_PIXEL_FORMAT_YCbCr_422_SP : // NV16
- !strcmp(format, PIXEL_FORMAT_YUV420SP) ?
- HAL_PIXEL_FORMAT_YCrCb_420_SP : // NV21
- !strcmp(format, PIXEL_FORMAT_YUV422I) ?
- HAL_PIXEL_FORMAT_YCbCr_422_I : // YUY2
- !strcmp(format, PIXEL_FORMAT_YUV420P) ?
- HAL_PIXEL_FORMAT_YV12 : // YV12
- !strcmp(format, PIXEL_FORMAT_RGB565) ?
- HAL_PIXEL_FORMAT_RGB_565 : // RGB565
- !strcmp(format, PIXEL_FORMAT_RGBA8888) ?
- HAL_PIXEL_FORMAT_RGBA_8888 : // RGB8888
- !strcmp(format, PIXEL_FORMAT_BAYER_RGGB) ?
- HAL_PIXEL_FORMAT_RAW16 : // Raw sensor data
- -1;
+ return !format ? HAL_PIXEL_FORMAT_YCrCb_420_SP
+ : !strcmp(format, PIXEL_FORMAT_YUV422SP) ? HAL_PIXEL_FORMAT_YCbCr_422_SP
+ : // NV16
+ !strcmp(format, PIXEL_FORMAT_YUV420SP) ? HAL_PIXEL_FORMAT_YCrCb_420_SP
+ : // NV21
+ !strcmp(format, PIXEL_FORMAT_YUV422I) ? HAL_PIXEL_FORMAT_YCbCr_422_I
+ : // YUY2
+ !strcmp(format, PIXEL_FORMAT_YUV420P) ? HAL_PIXEL_FORMAT_YV12
+ : // YV12
+ !strcmp(format, PIXEL_FORMAT_RGB565) ? HAL_PIXEL_FORMAT_RGB_565
+ : // RGB565
+ !strcmp(format, PIXEL_FORMAT_RGBA8888) ? HAL_PIXEL_FORMAT_RGBA_8888
+ : // RGB8888
+ !strcmp(format, PIXEL_FORMAT_BAYER_RGGB) ? HAL_PIXEL_FORMAT_RAW16
+ : // Raw sensor data
+ -1;
}
bool CameraParameters::isEmpty() const {
return mMap.isEmpty();
}
-};
-};
-};
-};
-};
-}; // namespace android
+}; // namespace helper
+}; // namespace common
+}; // namespace camera
+}; // namespace hardware
+}; // namespace android
diff --git a/camera/common/1.0/default/Exif.cpp b/camera/common/default/Exif.cpp
similarity index 83%
rename from camera/common/1.0/default/Exif.cpp
rename to camera/common/default/Exif.cpp
index 413b6bb..f4b2a31 100644
--- a/camera/common/1.0/default/Exif.cpp
+++ b/camera/common/default/Exif.cpp
@@ -16,7 +16,7 @@
#define LOG_TAG "CamComm1.0-Exif"
#define ATRACE_TAG ATRACE_TAG_CAMERA
-//#define LOG_NDEBUG 0
+// #define LOG_NDEBUG 0
#include <android/log.h>
@@ -41,15 +41,12 @@
} // namespace std
-
namespace android {
namespace hardware {
namespace camera {
namespace common {
-namespace V1_0 {
namespace helper {
-
class ExifUtilsImpl : public ExifUtils {
public:
ExifUtilsImpl();
@@ -61,8 +58,7 @@
virtual bool initialize();
// set all known fields from a metadata structure
- virtual bool setFromMetadata(const CameraMetadata& metadata,
- const size_t imageWidth,
+ virtual bool setFromMetadata(const CameraMetadata& metadata, const size_t imageWidth,
const size_t imageHeight);
// sets the len aperture.
@@ -254,7 +250,6 @@
// Returns false if memory allocation fails.
virtual bool setExifVersion(const std::string& exif_version);
-
// Resets the pointers and memories.
virtual void reset();
@@ -262,8 +257,7 @@
// if the tag exists.
// Returns the entry of the tag. The reference count of returned ExifEntry is
// two.
- virtual std::unique_ptr<ExifEntry> addVariableLengthEntry(ExifIfd ifd,
- ExifTag tag,
+ virtual std::unique_ptr<ExifEntry> addVariableLengthEntry(ExifIfd ifd, ExifTag tag,
ExifFormat format,
uint64_t components,
unsigned int size);
@@ -275,32 +269,17 @@
virtual std::unique_ptr<ExifEntry> addEntry(ExifIfd ifd, ExifTag tag);
// Helpe functions to add exif data with different types.
- virtual bool setShort(ExifIfd ifd,
- ExifTag tag,
- uint16_t value,
- const std::string& msg);
+ virtual bool setShort(ExifIfd ifd, ExifTag tag, uint16_t value, const std::string& msg);
- virtual bool setLong(ExifIfd ifd,
- ExifTag tag,
- uint32_t value,
- const std::string& msg);
+ virtual bool setLong(ExifIfd ifd, ExifTag tag, uint32_t value, const std::string& msg);
- virtual bool setRational(ExifIfd ifd,
- ExifTag tag,
- uint32_t numerator,
- uint32_t denominator,
+ virtual bool setRational(ExifIfd ifd, ExifTag tag, uint32_t numerator, uint32_t denominator,
const std::string& msg);
- virtual bool setSRational(ExifIfd ifd,
- ExifTag tag,
- int32_t numerator,
- int32_t denominator,
+ virtual bool setSRational(ExifIfd ifd, ExifTag tag, int32_t numerator, int32_t denominator,
const std::string& msg);
- virtual bool setString(ExifIfd ifd,
- ExifTag tag,
- ExifFormat format,
- const std::string& buffer,
+ virtual bool setString(ExifIfd ifd, ExifTag tag, ExifFormat format, const std::string& buffer,
const std::string& msg);
// Destroys the buffer of APP1 segment if exists.
@@ -313,37 +292,31 @@
uint8_t* app1_buffer_;
// The length of |app1_buffer_|.
unsigned int app1_length_;
-
};
-#define SET_SHORT(ifd, tag, value) \
- do { \
- if (setShort(ifd, tag, value, #tag) == false) \
- return false; \
+#define SET_SHORT(ifd, tag, value) \
+ do { \
+ if (setShort(ifd, tag, value, #tag) == false) return false; \
} while (0);
-#define SET_LONG(ifd, tag, value) \
- do { \
- if (setLong(ifd, tag, value, #tag) == false) \
- return false; \
+#define SET_LONG(ifd, tag, value) \
+ do { \
+ if (setLong(ifd, tag, value, #tag) == false) return false; \
} while (0);
-#define SET_RATIONAL(ifd, tag, numerator, denominator) \
- do { \
- if (setRational(ifd, tag, numerator, denominator, #tag) == false) \
- return false; \
+#define SET_RATIONAL(ifd, tag, numerator, denominator) \
+ do { \
+ if (setRational(ifd, tag, numerator, denominator, #tag) == false) return false; \
} while (0);
-#define SET_SRATIONAL(ifd, tag, numerator, denominator) \
- do { \
- if (setSRational(ifd, tag, numerator, denominator, #tag) == false) \
- return false; \
+#define SET_SRATIONAL(ifd, tag, numerator, denominator) \
+ do { \
+ if (setSRational(ifd, tag, numerator, denominator, #tag) == false) return false; \
} while (0);
#define SET_STRING(ifd, tag, format, buffer) \
do { \
- if (setString(ifd, tag, format, buffer, #tag) == false) \
- return false; \
+ if (setString(ifd, tag, format, buffer, #tag) == false) return false; \
} while (0);
// This comes from the Exif Version 2.2 standard table 6.
@@ -353,30 +326,25 @@
// Take the integer part of |num|.
ExifLong degrees = static_cast<ExifLong>(num);
ExifLong minutes = static_cast<ExifLong>(60 * (num - degrees));
- ExifLong microseconds =
- static_cast<ExifLong>(3600000000u * (num - degrees - minutes / 60.0));
+ ExifLong microseconds = static_cast<ExifLong>(3600000000u * (num - degrees - minutes / 60.0));
exif_set_rational(data, EXIF_BYTE_ORDER_INTEL, {degrees, 1});
- exif_set_rational(data + sizeof(ExifRational), EXIF_BYTE_ORDER_INTEL,
- {minutes, 1});
+ exif_set_rational(data + sizeof(ExifRational), EXIF_BYTE_ORDER_INTEL, {minutes, 1});
exif_set_rational(data + 2 * sizeof(ExifRational), EXIF_BYTE_ORDER_INTEL,
- {microseconds, 1000000});
+ {microseconds, 1000000});
}
-ExifUtils *ExifUtils::create() {
+ExifUtils* ExifUtils::create() {
return new ExifUtilsImpl();
}
-ExifUtils::~ExifUtils() {
-}
+ExifUtils::~ExifUtils() {}
-ExifUtilsImpl::ExifUtilsImpl()
- : exif_data_(nullptr), app1_buffer_(nullptr), app1_length_(0) {}
+ExifUtilsImpl::ExifUtilsImpl() : exif_data_(nullptr), app1_buffer_(nullptr), app1_length_(0) {}
ExifUtilsImpl::~ExifUtilsImpl() {
reset();
}
-
bool ExifUtilsImpl::initialize() {
reset();
exif_data_ = exif_data_new();
@@ -403,8 +371,7 @@
}
bool ExifUtilsImpl::setBrightness(int32_t numerator, int32_t denominator) {
- SET_SRATIONAL(EXIF_IFD_EXIF, EXIF_TAG_BRIGHTNESS_VALUE, numerator,
- denominator);
+ SET_SRATIONAL(EXIF_IFD_EXIF, EXIF_TAG_BRIGHTNESS_VALUE, numerator, denominator);
return true;
}
@@ -413,10 +380,9 @@
return true;
}
-bool ExifUtilsImpl::setComponentsConfiguration(
- const std::string& components_configuration) {
- SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_COMPONENTS_CONFIGURATION,
- EXIF_FORMAT_UNDEFINED, components_configuration);
+bool ExifUtilsImpl::setComponentsConfiguration(const std::string& components_configuration) {
+ SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_COMPONENTS_CONFIGURATION, EXIF_FORMAT_UNDEFINED,
+ components_configuration);
return true;
}
@@ -433,37 +399,31 @@
bool ExifUtilsImpl::setDateTime(const struct tm& t) {
// The length is 20 bytes including NULL for termination in Exif standard.
char str[20];
- int result = snprintf(str, sizeof(str), "%04i:%02i:%02i %02i:%02i:%02i",
- t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour,
- t.tm_min, t.tm_sec);
+ int result = snprintf(str, sizeof(str), "%04i:%02i:%02i %02i:%02i:%02i", t.tm_year + 1900,
+ t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
if (result != sizeof(str) - 1) {
ALOGW("%s: Input time is invalid", __FUNCTION__);
return false;
}
std::string buffer(str);
SET_STRING(EXIF_IFD_0, EXIF_TAG_DATE_TIME, EXIF_FORMAT_ASCII, buffer);
- SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_DATE_TIME_ORIGINAL, EXIF_FORMAT_ASCII,
- buffer);
- SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_DATE_TIME_DIGITIZED, EXIF_FORMAT_ASCII,
- buffer);
+ SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_DATE_TIME_ORIGINAL, EXIF_FORMAT_ASCII, buffer);
+ SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_DATE_TIME_DIGITIZED, EXIF_FORMAT_ASCII, buffer);
return true;
}
bool ExifUtilsImpl::setDescription(const std::string& description) {
- SET_STRING(EXIF_IFD_0, EXIF_TAG_IMAGE_DESCRIPTION, EXIF_FORMAT_ASCII,
- description);
+ SET_STRING(EXIF_IFD_0, EXIF_TAG_IMAGE_DESCRIPTION, EXIF_FORMAT_ASCII, description);
return true;
}
bool ExifUtilsImpl::setDigitalZoomRatio(uint32_t numerator, uint32_t denominator) {
- SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_DIGITAL_ZOOM_RATIO, numerator,
- denominator);
+ SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_DIGITAL_ZOOM_RATIO, numerator, denominator);
return true;
}
bool ExifUtilsImpl::setExposureBias(int32_t numerator, int32_t denominator) {
- SET_SRATIONAL(EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_BIAS_VALUE, numerator,
- denominator);
+ SET_SRATIONAL(EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_BIAS_VALUE, numerator, denominator);
return true;
}
@@ -526,7 +486,7 @@
return false;
}
exif_set_rational(entry->data, EXIF_BYTE_ORDER_INTEL,
- {static_cast<ExifLong>(altitude * 1000), 1000});
+ {static_cast<ExifLong>(altitude * 1000), 1000});
return true;
}
@@ -588,26 +548,23 @@
}
bool ExifUtilsImpl::setGpsProcessingMethod(const std::string& method) {
- std::string buffer =
- std::string(gExifAsciiPrefix, sizeof(gExifAsciiPrefix)) + method;
+ std::string buffer = std::string(gExifAsciiPrefix, sizeof(gExifAsciiPrefix)) + method;
SET_STRING(EXIF_IFD_GPS, static_cast<ExifTag>(EXIF_TAG_GPS_PROCESSING_METHOD),
- EXIF_FORMAT_UNDEFINED, buffer);
+ EXIF_FORMAT_UNDEFINED, buffer);
return true;
}
bool ExifUtilsImpl::setGpsTimestamp(const struct tm& t) {
const ExifTag dateTag = static_cast<ExifTag>(EXIF_TAG_GPS_DATE_STAMP);
const size_t kGpsDateStampSize = 11;
- std::unique_ptr<ExifEntry> entry =
- addVariableLengthEntry(EXIF_IFD_GPS, dateTag, EXIF_FORMAT_ASCII,
- kGpsDateStampSize, kGpsDateStampSize);
+ std::unique_ptr<ExifEntry> entry = addVariableLengthEntry(
+ EXIF_IFD_GPS, dateTag, EXIF_FORMAT_ASCII, kGpsDateStampSize, kGpsDateStampSize);
if (!entry) {
ALOGE("%s: Adding GPSDateStamp exif entry failed", __FUNCTION__);
return false;
}
- int result =
- snprintf(reinterpret_cast<char*>(entry->data), kGpsDateStampSize,
- "%04i:%02i:%02i", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday);
+ int result = snprintf(reinterpret_cast<char*>(entry->data), kGpsDateStampSize, "%04i:%02i:%02i",
+ t.tm_year + 1900, t.tm_mon + 1, t.tm_mday);
if (result != kGpsDateStampSize - 1) {
ALOGW("%s: Input time is invalid", __FUNCTION__);
return false;
@@ -615,18 +572,16 @@
const ExifTag timeTag = static_cast<ExifTag>(EXIF_TAG_GPS_TIME_STAMP);
entry = addVariableLengthEntry(EXIF_IFD_GPS, timeTag, EXIF_FORMAT_RATIONAL, 3,
- 3 * sizeof(ExifRational));
+ 3 * sizeof(ExifRational));
if (!entry) {
ALOGE("%s: Adding GPSTimeStamp exif entry failed", __FUNCTION__);
return false;
}
- exif_set_rational(entry->data, EXIF_BYTE_ORDER_INTEL,
- {static_cast<ExifLong>(t.tm_hour), 1});
+ exif_set_rational(entry->data, EXIF_BYTE_ORDER_INTEL, {static_cast<ExifLong>(t.tm_hour), 1});
exif_set_rational(entry->data + sizeof(ExifRational), EXIF_BYTE_ORDER_INTEL,
- {static_cast<ExifLong>(t.tm_min), 1});
- exif_set_rational(entry->data + 2 * sizeof(ExifRational),
- EXIF_BYTE_ORDER_INTEL,
- {static_cast<ExifLong>(t.tm_sec), 1});
+ {static_cast<ExifLong>(t.tm_min), 1});
+ exif_set_rational(entry->data + 2 * sizeof(ExifRational), EXIF_BYTE_ORDER_INTEL,
+ {static_cast<ExifLong>(t.tm_sec), 1});
return true;
}
@@ -654,8 +609,7 @@
}
bool ExifUtilsImpl::setMaxAperture(uint32_t numerator, uint32_t denominator) {
- SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_MAX_APERTURE_VALUE, numerator,
- denominator);
+ SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_MAX_APERTURE_VALUE, numerator, denominator);
return true;
}
@@ -714,24 +668,19 @@
}
bool ExifUtilsImpl::setShutterSpeed(int32_t numerator, int32_t denominator) {
- SET_SRATIONAL(EXIF_IFD_EXIF, EXIF_TAG_SHUTTER_SPEED_VALUE, numerator,
- denominator);
+ SET_SRATIONAL(EXIF_IFD_EXIF, EXIF_TAG_SHUTTER_SPEED_VALUE, numerator, denominator);
return true;
}
bool ExifUtilsImpl::setSubjectDistance(uint32_t numerator, uint32_t denominator) {
- SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_SUBJECT_DISTANCE, numerator,
- denominator);
+ SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_SUBJECT_DISTANCE, numerator, denominator);
return true;
}
bool ExifUtilsImpl::setSubsecTime(const std::string& subsec_time) {
- SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_SUB_SEC_TIME, EXIF_FORMAT_ASCII,
- subsec_time);
- SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_SUB_SEC_TIME_ORIGINAL, EXIF_FORMAT_ASCII,
- subsec_time);
- SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_SUB_SEC_TIME_DIGITIZED, EXIF_FORMAT_ASCII,
- subsec_time);
+ SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_SUB_SEC_TIME, EXIF_FORMAT_ASCII, subsec_time);
+ SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_SUB_SEC_TIME_ORIGINAL, EXIF_FORMAT_ASCII, subsec_time);
+ SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_SUB_SEC_TIME_DIGITIZED, EXIF_FORMAT_ASCII, subsec_time);
return true;
}
@@ -816,8 +765,7 @@
}
}
-std::unique_ptr<ExifEntry> ExifUtilsImpl::addVariableLengthEntry(ExifIfd ifd,
- ExifTag tag,
+std::unique_ptr<ExifEntry> ExifUtilsImpl::addVariableLengthEntry(ExifIfd ifd, ExifTag tag,
ExifFormat format,
uint64_t components,
unsigned int size) {
@@ -872,10 +820,7 @@
return entry;
}
-bool ExifUtilsImpl::setShort(ExifIfd ifd,
- ExifTag tag,
- uint16_t value,
- const std::string& msg) {
+bool ExifUtilsImpl::setShort(ExifIfd ifd, ExifTag tag, uint16_t value, const std::string& msg) {
std::unique_ptr<ExifEntry> entry = addEntry(ifd, tag);
if (!entry) {
ALOGE("%s: Adding '%s' entry failed", __FUNCTION__, msg.c_str());
@@ -885,10 +830,7 @@
return true;
}
-bool ExifUtilsImpl::setLong(ExifIfd ifd,
- ExifTag tag,
- uint32_t value,
- const std::string& msg) {
+bool ExifUtilsImpl::setLong(ExifIfd ifd, ExifTag tag, uint32_t value, const std::string& msg) {
std::unique_ptr<ExifEntry> entry = addEntry(ifd, tag);
if (!entry) {
ALOGE("%s: Adding '%s' entry failed", __FUNCTION__, msg.c_str());
@@ -898,41 +840,30 @@
return true;
}
-bool ExifUtilsImpl::setRational(ExifIfd ifd,
- ExifTag tag,
- uint32_t numerator,
- uint32_t denominator,
+bool ExifUtilsImpl::setRational(ExifIfd ifd, ExifTag tag, uint32_t numerator, uint32_t denominator,
const std::string& msg) {
std::unique_ptr<ExifEntry> entry = addEntry(ifd, tag);
if (!entry) {
ALOGE("%s: Adding '%s' entry failed", __FUNCTION__, msg.c_str());
return false;
}
- exif_set_rational(entry->data, EXIF_BYTE_ORDER_INTEL,
- {numerator, denominator});
+ exif_set_rational(entry->data, EXIF_BYTE_ORDER_INTEL, {numerator, denominator});
return true;
}
-bool ExifUtilsImpl::setSRational(ExifIfd ifd,
- ExifTag tag,
- int32_t numerator,
- int32_t denominator,
+bool ExifUtilsImpl::setSRational(ExifIfd ifd, ExifTag tag, int32_t numerator, int32_t denominator,
const std::string& msg) {
std::unique_ptr<ExifEntry> entry = addEntry(ifd, tag);
if (!entry) {
ALOGE("%s: Adding '%s' entry failed", __FUNCTION__, msg.c_str());
return false;
}
- exif_set_srational(entry->data, EXIF_BYTE_ORDER_INTEL,
- {numerator, denominator});
+ exif_set_srational(entry->data, EXIF_BYTE_ORDER_INTEL, {numerator, denominator});
return true;
}
-bool ExifUtilsImpl::setString(ExifIfd ifd,
- ExifTag tag,
- ExifFormat format,
- const std::string& buffer,
- const std::string& msg) {
+bool ExifUtilsImpl::setString(ExifIfd ifd, ExifTag tag, ExifFormat format,
+ const std::string& buffer, const std::string& msg) {
size_t entry_size = buffer.length();
// Since the exif format is undefined, NULL termination is not necessary.
if (format == EXIF_FORMAT_ASCII) {
@@ -959,13 +890,11 @@
app1_length_ = 0;
}
-bool ExifUtilsImpl::setFromMetadata(const CameraMetadata& metadata,
- const size_t imageWidth,
+bool ExifUtilsImpl::setFromMetadata(const CameraMetadata& metadata, const size_t imageWidth,
const size_t imageHeight) {
// How precise the float-to-rational conversion for EXIF tags would be.
constexpr int kRationalPrecision = 10000;
- if (!setImageWidth(imageWidth) ||
- !setImageHeight(imageHeight)) {
+ if (!setImageWidth(imageWidth) || !setImageHeight(imageHeight)) {
ALOGE("%s: setting image resolution failed.", __FUNCTION__);
return false;
}
@@ -984,9 +913,8 @@
if (entry.count) {
focal_length = entry.data.f[0];
- if (!setFocalLength(
- static_cast<uint32_t>(focal_length * kRationalPrecision),
- kRationalPrecision)) {
+ if (!setFocalLength(static_cast<uint32_t>(focal_length * kRationalPrecision),
+ kRationalPrecision)) {
ALOGE("%s: setting focal length failed.", __FUNCTION__);
return false;
}
@@ -1048,7 +976,7 @@
if (metadata.exists(ANDROID_SENSOR_EXPOSURE_TIME)) {
entry = metadata.find(ANDROID_SENSOR_EXPOSURE_TIME);
// int64_t of nanoseconds
- if (!setExposureTime(entry.data.i64[0],1000000000u)) {
+ if (!setExposureTime(entry.data.i64[0], 1000000000u)) {
ALOGE("%s: setting exposure time failed.", __FUNCTION__);
return false;
}
@@ -1057,8 +985,7 @@
if (metadata.exists(ANDROID_LENS_APERTURE)) {
const int kAperturePrecision = 10000;
entry = metadata.find(ANDROID_LENS_APERTURE);
- if (!setFNumber(entry.data.f[0] * kAperturePrecision,
- kAperturePrecision)) {
+ if (!setFNumber(entry.data.f[0] * kAperturePrecision, kAperturePrecision)) {
ALOGE("%s: setting F number failed.", __FUNCTION__);
return false;
}
@@ -1073,7 +1000,7 @@
return false;
}
} else {
- ALOGE("%s: Unsupported flash info: %d",__FUNCTION__, entry.data.u8[0]);
+ ALOGE("%s: Unsupported flash info: %d", __FUNCTION__, entry.data.u8[0]);
return false;
}
}
@@ -1107,9 +1034,8 @@
return true;
}
-} // namespace helper
-} // namespace V1_0
-} // namespace common
-} // namespace camera
-} // namespace hardware
-} // namespace android
+} // namespace helper
+} // namespace common
+} // namespace camera
+} // namespace hardware
+} // namespace android
diff --git a/camera/common/1.0/default/HandleImporter.cpp b/camera/common/default/HandleImporter.cpp
similarity index 74%
rename from camera/common/1.0/default/HandleImporter.cpp
rename to camera/common/default/HandleImporter.cpp
index d2fdf02..1145baa 100644
--- a/camera/common/1.0/default/HandleImporter.cpp
+++ b/camera/common/default/HandleImporter.cpp
@@ -18,14 +18,13 @@
#include "HandleImporter.h"
#include <gralloctypes/Gralloc4.h>
-#include "aidl/android/hardware/graphics/common/Smpte2086.h"
#include <log/log.h>
+#include "aidl/android/hardware/graphics/common/Smpte2086.h"
namespace android {
namespace hardware {
namespace camera {
namespace common {
-namespace V1_0 {
namespace helper {
using aidl::android::hardware::graphics::common::PlaneLayout;
@@ -75,20 +74,18 @@
mInitialized = false;
}
-template<class M, class E>
+template <class M, class E>
bool HandleImporter::importBufferInternal(const sp<M> mapper, buffer_handle_t& handle) {
E error;
buffer_handle_t importedHandle;
auto ret = mapper->importBuffer(
- hidl_handle(handle),
- [&](const auto& tmpError, const auto& tmpBufferHandle) {
- error = tmpError;
- importedHandle = static_cast<buffer_handle_t>(tmpBufferHandle);
- });
+ hidl_handle(handle), [&](const auto& tmpError, const auto& tmpBufferHandle) {
+ error = tmpError;
+ importedHandle = static_cast<buffer_handle_t>(tmpBufferHandle);
+ });
if (!ret.isOk()) {
- ALOGE("%s: mapper importBuffer failed: %s",
- __FUNCTION__, ret.description().c_str());
+ ALOGE("%s: mapper importBuffer failed: %s", __FUNCTION__, ret.description().c_str());
return false;
}
@@ -100,61 +97,62 @@
return true;
}
-template<class M, class E>
+template <class M, class E>
YCbCrLayout HandleImporter::lockYCbCrInternal(const sp<M> mapper, buffer_handle_t& buf,
- uint64_t cpuUsage, const IMapper::Rect& accessRegion) {
+ uint64_t cpuUsage,
+ const IMapper::Rect& accessRegion) {
hidl_handle acquireFenceHandle;
auto buffer = const_cast<native_handle_t*>(buf);
YCbCrLayout layout = {};
- typename M::Rect accessRegionCopy = {accessRegion.left, accessRegion.top,
- accessRegion.width, accessRegion.height};
+ typename M::Rect accessRegionCopy = {accessRegion.left, accessRegion.top, accessRegion.width,
+ accessRegion.height};
mapper->lockYCbCr(buffer, cpuUsage, accessRegionCopy, acquireFenceHandle,
- [&](const auto& tmpError, const auto& tmpLayout) {
- if (tmpError == E::NONE) {
- // Member by member copy from different versions of YCbCrLayout.
- layout.y = tmpLayout.y;
- layout.cb = tmpLayout.cb;
- layout.cr = tmpLayout.cr;
- layout.yStride = tmpLayout.yStride;
- layout.cStride = tmpLayout.cStride;
- layout.chromaStep = tmpLayout.chromaStep;
- } else {
- ALOGE("%s: failed to lockYCbCr error %d!", __FUNCTION__, tmpError);
- }
- });
+ [&](const auto& tmpError, const auto& tmpLayout) {
+ if (tmpError == E::NONE) {
+ // Member by member copy from different versions of YCbCrLayout.
+ layout.y = tmpLayout.y;
+ layout.cb = tmpLayout.cb;
+ layout.cr = tmpLayout.cr;
+ layout.yStride = tmpLayout.yStride;
+ layout.cStride = tmpLayout.cStride;
+ layout.chromaStep = tmpLayout.chromaStep;
+ } else {
+ ALOGE("%s: failed to lockYCbCr error %d!", __FUNCTION__, tmpError);
+ }
+ });
return layout;
}
bool isMetadataPesent(const sp<IMapperV4> mapper, const buffer_handle_t& buf,
- MetadataType metadataType) {
+ MetadataType metadataType) {
auto buffer = const_cast<native_handle_t*>(buf);
bool ret = false;
hidl_vec<uint8_t> vec;
- mapper->get(buffer, metadataType, [&] (const auto& tmpError,
- const auto& tmpMetadata) {
- if (tmpError == MapperErrorV4::NONE) {
- vec = tmpMetadata;
- } else {
- ALOGE("%s: failed to get metadata %d!", __FUNCTION__, tmpError);
- }});
+ mapper->get(buffer, metadataType, [&](const auto& tmpError, const auto& tmpMetadata) {
+ if (tmpError == MapperErrorV4::NONE) {
+ vec = tmpMetadata;
+ } else {
+ ALOGE("%s: failed to get metadata %d!", __FUNCTION__, tmpError);
+ }
+ });
if (vec.size() > 0) {
- if (metadataType == gralloc4::MetadataType_Smpte2086){
- std::optional<Smpte2086> realSmpte2086;
- gralloc4::decodeSmpte2086(vec, &realSmpte2086);
- ret = realSmpte2086.has_value();
- } else if (metadataType == gralloc4::MetadataType_Smpte2094_10) {
- std::optional<std::vector<uint8_t>> realSmpte2094_10;
- gralloc4::decodeSmpte2094_10(vec, &realSmpte2094_10);
- ret = realSmpte2094_10.has_value();
- } else if (metadataType == gralloc4::MetadataType_Smpte2094_40) {
- std::optional<std::vector<uint8_t>> realSmpte2094_40;
- gralloc4::decodeSmpte2094_40(vec, &realSmpte2094_40);
- ret = realSmpte2094_40.has_value();
- } else {
- ALOGE("%s: Unknown metadata type!", __FUNCTION__);
- }
+ if (metadataType == gralloc4::MetadataType_Smpte2086) {
+ std::optional<Smpte2086> realSmpte2086;
+ gralloc4::decodeSmpte2086(vec, &realSmpte2086);
+ ret = realSmpte2086.has_value();
+ } else if (metadataType == gralloc4::MetadataType_Smpte2094_10) {
+ std::optional<std::vector<uint8_t>> realSmpte2094_10;
+ gralloc4::decodeSmpte2094_10(vec, &realSmpte2094_10);
+ ret = realSmpte2094_10.has_value();
+ } else if (metadataType == gralloc4::MetadataType_Smpte2094_40) {
+ std::optional<std::vector<uint8_t>> realSmpte2094_40;
+ gralloc4::decodeSmpte2094_40(vec, &realSmpte2094_40);
+ ret = realSmpte2094_40.has_value();
+ } else {
+ ALOGE("%s: Unknown metadata type!", __FUNCTION__);
+ }
}
return ret;
@@ -239,31 +237,29 @@
return layout;
}
-template<class M, class E>
+template <class M, class E>
int HandleImporter::unlockInternal(const sp<M> mapper, buffer_handle_t& buf) {
int releaseFence = -1;
auto buffer = const_cast<native_handle_t*>(buf);
- mapper->unlock(
- buffer, [&](const auto& tmpError, const auto& tmpReleaseFence) {
- if (tmpError == E::NONE) {
- auto fenceHandle = tmpReleaseFence.getNativeHandle();
- if (fenceHandle) {
- if (fenceHandle->numInts != 0 || fenceHandle->numFds != 1) {
- ALOGE("%s: bad release fence numInts %d numFds %d",
- __FUNCTION__, fenceHandle->numInts, fenceHandle->numFds);
- return;
- }
- releaseFence = dup(fenceHandle->data[0]);
- if (releaseFence < 0) {
- ALOGE("%s: bad release fence FD %d",
- __FUNCTION__, releaseFence);
- }
+ mapper->unlock(buffer, [&](const auto& tmpError, const auto& tmpReleaseFence) {
+ if (tmpError == E::NONE) {
+ auto fenceHandle = tmpReleaseFence.getNativeHandle();
+ if (fenceHandle) {
+ if (fenceHandle->numInts != 0 || fenceHandle->numFds != 1) {
+ ALOGE("%s: bad release fence numInts %d numFds %d", __FUNCTION__,
+ fenceHandle->numInts, fenceHandle->numFds);
+ return;
}
- } else {
- ALOGE("%s: failed to unlock error %d!", __FUNCTION__, tmpError);
+ releaseFence = dup(fenceHandle->data[0]);
+ if (releaseFence < 0) {
+ ALOGE("%s: bad release fence FD %d", __FUNCTION__, releaseFence);
+ }
}
- });
+ } else {
+ ALOGE("%s: failed to unlock error %d!", __FUNCTION__, tmpError);
+ }
+ });
return releaseFence;
}
@@ -315,14 +311,12 @@
} else if (mMapperV3 != nullptr) {
auto ret = mMapperV3->freeBuffer(const_cast<native_handle_t*>(handle));
if (!ret.isOk()) {
- ALOGE("%s: mapper freeBuffer failed: %s",
- __FUNCTION__, ret.description().c_str());
+ ALOGE("%s: mapper freeBuffer failed: %s", __FUNCTION__, ret.description().c_str());
}
} else {
auto ret = mMapperV2->freeBuffer(const_cast<native_handle_t*>(handle));
if (!ret.isOk()) {
- ALOGE("%s: mapper freeBuffer failed: %s",
- __FUNCTION__, ret.description().c_str());
+ ALOGE("%s: mapper freeBuffer failed: %s", __FUNCTION__, ret.description().c_str());
}
}
}
@@ -337,8 +331,7 @@
return false;
}
} else {
- ALOGE("invalid fence handle with %d file descriptors",
- handle->numFds);
+ ALOGE("invalid fence handle with %d file descriptors", handle->numFds);
return false;
}
@@ -351,8 +344,7 @@
}
}
-void* HandleImporter::lock(
- buffer_handle_t& buf, uint64_t cpuUsage, size_t size) {
+void* HandleImporter::lock(buffer_handle_t& buf, uint64_t cpuUsage, size_t size) {
IMapper::Rect accessRegion{0, 0, static_cast<int>(size), 1};
return lock(buf, cpuUsage, accessRegion);
}
@@ -401,13 +393,13 @@
});
} else {
mMapperV2->lock(buffer, cpuUsage, accessRegion, acquireFenceHandle,
- [&](const auto& tmpError, const auto& tmpPtr) {
- if (tmpError == MapperErrorV2::NONE) {
- ret = tmpPtr;
- } else {
- ALOGE("%s: failed to lock error %d!", __FUNCTION__, tmpError);
- }
- });
+ [&](const auto& tmpError, const auto& tmpPtr) {
+ if (tmpError == MapperErrorV2::NONE) {
+ ret = tmpPtr;
+ } else {
+ ALOGE("%s: failed to lock error %d!", __FUNCTION__, tmpError);
+ }
+ });
}
ALOGV("%s: ptr %p accessRegion.top: %d accessRegion.left: %d accessRegion.width: %d "
@@ -417,9 +409,8 @@
return ret;
}
-YCbCrLayout HandleImporter::lockYCbCr(
- buffer_handle_t& buf, uint64_t cpuUsage,
- const IMapper::Rect& accessRegion) {
+YCbCrLayout HandleImporter::lockYCbCr(buffer_handle_t& buf, uint64_t cpuUsage,
+ const IMapper::Rect& accessRegion) {
Mutex::Autolock lock(mLock);
if (!mInitialized) {
@@ -431,20 +422,18 @@
}
if (mMapperV3 != nullptr) {
- return lockYCbCrInternal<IMapperV3, MapperErrorV3>(
- mMapperV3, buf, cpuUsage, accessRegion);
+ return lockYCbCrInternal<IMapperV3, MapperErrorV3>(mMapperV3, buf, cpuUsage, accessRegion);
}
if (mMapperV2 != nullptr) {
- return lockYCbCrInternal<IMapper, MapperErrorV2>(
- mMapperV2, buf, cpuUsage, accessRegion);
+ return lockYCbCrInternal<IMapper, MapperErrorV2>(mMapperV2, buf, cpuUsage, accessRegion);
}
ALOGE("%s: mMapperV4, mMapperV3 and mMapperV2 are all null!", __FUNCTION__);
return {};
}
-status_t HandleImporter::getMonoPlanarStrideBytes(buffer_handle_t &buf, uint32_t *stride /*out*/) {
+status_t HandleImporter::getMonoPlanarStrideBytes(buffer_handle_t& buf, uint32_t* stride /*out*/) {
if (stride == nullptr) {
return BAD_VALUE;
}
@@ -458,7 +447,7 @@
if (mMapperV4 != nullptr) {
std::vector<PlaneLayout> planeLayouts = getPlaneLayouts(mMapperV4, buf);
if (planeLayouts.size() != 1) {
- ALOGE("%s: Unexpected number of planes %zu!", __FUNCTION__, planeLayouts.size());
+ ALOGE("%s: Unexpected number of planes %zu!", __FUNCTION__, planeLayouts.size());
return BAD_VALUE;
}
@@ -534,10 +523,8 @@
return false;
}
-
-} // namespace helper
-} // namespace V1_0
-} // namespace common
-} // namespace camera
-} // namespace hardware
-} // namespace android
+} // namespace helper
+} // namespace common
+} // namespace camera
+} // namespace hardware
+} // namespace android
diff --git a/camera/common/1.0/default/OWNERS b/camera/common/default/OWNERS
similarity index 100%
rename from camera/common/1.0/default/OWNERS
rename to camera/common/default/OWNERS
diff --git a/camera/common/default/SimpleThread.cpp b/camera/common/default/SimpleThread.cpp
new file mode 100644
index 0000000..46e89ba
--- /dev/null
+++ b/camera/common/default/SimpleThread.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SimpleThread.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace common {
+namespace helper {
+
+SimpleThread::SimpleThread() : mDone(true), mThread() {}
+SimpleThread::~SimpleThread() {
+ // Safe to call requestExitAndWait() from the destructor because requestExitAndWait() ensures
+ // that the thread is joinable before joining on it. This is different from how
+ // android::Thread worked.
+ requestExitAndWait();
+}
+
+void SimpleThread::run() {
+ requestExitAndWait(); // Exit current execution, if any.
+
+ // start thread
+ mDone.store(false, std::memory_order_release);
+ mThread = std::thread(&SimpleThread::runLoop, this);
+}
+
+void SimpleThread::requestExitAndWait() {
+ // Signal thread to stop
+ mDone.store(true, std::memory_order_release);
+
+ // Wait for thread to exit if needed. This should happen in no more than one iteration of
+ // threadLoop
+ if (mThread.joinable()) {
+ mThread.join();
+ }
+ mThread = std::thread();
+}
+
+void SimpleThread::runLoop() {
+ while (!exitPending()) {
+ if (!threadLoop()) {
+ break;
+ }
+ }
+}
+
+} // namespace helper
+} // namespace common
+} // namespace camera
+} // namespace hardware
+} // namespace android
\ No newline at end of file
diff --git a/camera/common/1.0/default/VendorTagDescriptor.cpp b/camera/common/default/VendorTagDescriptor.cpp
similarity index 91%
rename from camera/common/1.0/default/VendorTagDescriptor.cpp
rename to camera/common/default/VendorTagDescriptor.cpp
index d2bee85..1282bd0 100644
--- a/camera/common/1.0/default/VendorTagDescriptor.cpp
+++ b/camera/common/default/VendorTagDescriptor.cpp
@@ -16,9 +16,9 @@
#define LOG_TAG "CamComm1.0-VTDesc"
+#include <camera_metadata_hidden.h>
#include <log/log.h>
#include <system/camera_metadata.h>
-#include <camera_metadata_hidden.h>
#include <utils/Errors.h>
#include <utils/Mutex.h>
#include <utils/SortedVector.h>
@@ -36,15 +36,12 @@
VendorTagDescriptor::~VendorTagDescriptor() {
size_t len = mReverseMapping.size();
- for (size_t i = 0; i < len; ++i) {
+ for (size_t i = 0; i < len; ++i) {
delete mReverseMapping[i];
}
}
-VendorTagDescriptor::VendorTagDescriptor() :
- mTagCount(0),
- mVendorOps() {
-}
+VendorTagDescriptor::VendorTagDescriptor() : mTagCount(0), mVendorOps() {}
VendorTagDescriptor::VendorTagDescriptor(const VendorTagDescriptor& src) {
copyFrom(src);
@@ -127,7 +124,8 @@
return &mSections;
}
-status_t VendorTagDescriptor::lookupTag(const String8& name, const String8& section, /*out*/uint32_t* tag) const {
+status_t VendorTagDescriptor::lookupTag(const String8& name, const String8& section,
+ /*out*/ uint32_t* tag) const {
ssize_t index = mReverseMapping.indexOfKey(section);
if (index < 0) {
ALOGE("%s: Section '%s' does not exist.", __FUNCTION__, section.string());
@@ -147,18 +145,16 @@
}
void VendorTagDescriptor::dump(int fd, int verbosity, int indentation) const {
-
size_t size = mTagToNameMap.size();
if (size == 0) {
- dprintf(fd, "%*sDumping configured vendor tag descriptors: None set\n",
- indentation, "");
+ dprintf(fd, "%*sDumping configured vendor tag descriptors: None set\n", indentation, "");
return;
}
- dprintf(fd, "%*sDumping configured vendor tag descriptors: %zu entries\n",
- indentation, "", size);
+ dprintf(fd, "%*sDumping configured vendor tag descriptors: %zu entries\n", indentation, "",
+ size);
for (size_t i = 0; i < size; ++i) {
- uint32_t tag = mTagToNameMap.keyAt(i);
+ uint32_t tag = mTagToNameMap.keyAt(i);
if (verbosity < 1) {
dprintf(fd, "%*s0x%x\n", indentation + 2, "", tag);
@@ -168,12 +164,11 @@
uint32_t sectionId = mTagToSectionMap.valueFor(tag);
String8 sectionName = mSections[sectionId];
int type = mTagToTypeMap.at(tag);
- const char* typeName = (type >= 0 && type < NUM_TYPES) ?
- camera_metadata_type_names[type] : "UNKNOWN";
- dprintf(fd, "%*s0x%x (%s) with type %d (%s) defined in section %s\n", indentation + 2,
- "", tag, name.string(), type, typeName, sectionName.string());
+ const char* typeName =
+ (type >= 0 && type < NUM_TYPES) ? camera_metadata_type_names[type] : "UNKNOWN";
+ dprintf(fd, "%*s0x%x (%s) with type %d (%s) defined in section %s\n", indentation + 2, "",
+ tag, name.string(), type, typeName, sectionName.string());
}
-
}
int VendorTagDescriptorCache::getTagCount(metadata_vendor_id_t id) const {
@@ -240,7 +235,7 @@
}
int32_t VendorTagDescriptorCache::addVendorDescriptor(
- metadata_vendor_id_t id, sp<hardware::camera::common::V1_0::helper::VendorTagDescriptor> desc) {
+ metadata_vendor_id_t id, sp<hardware::camera::common::helper::VendorTagDescriptor> desc) {
auto entry = mVendorMap.find(id);
if (entry != mVendorMap.end()) {
ALOGE("%s: Vendor descriptor with same id already present!", __func__);
@@ -252,8 +247,8 @@
}
int32_t VendorTagDescriptorCache::getVendorTagDescriptor(
- metadata_vendor_id_t id,
- sp<hardware::camera::common::V1_0::helper::VendorTagDescriptor>* desc /*out*/) {
+ metadata_vendor_id_t id,
+ sp<hardware::camera::common::helper::VendorTagDescriptor>* desc /*out*/) {
auto entry = mVendorMap.find(id);
if (entry == mVendorMap.end()) {
return NAME_NOT_FOUND;
@@ -263,12 +258,11 @@
return NO_ERROR;
}
-} // namespace params
-} // namespace camera2
+} // namespace params
+} // namespace camera2
namespace camera {
namespace common {
-namespace V1_0 {
namespace helper {
extern "C" {
@@ -292,8 +286,8 @@
static sp<VendorTagDescriptorCache> sGlobalVendorTagDescriptorCache;
status_t VendorTagDescriptor::createDescriptorFromOps(const vendor_tag_ops_t* vOps,
- /*out*/
- sp<VendorTagDescriptor>& descriptor) {
+ /*out*/
+ sp<VendorTagDescriptor>& descriptor) {
if (vOps == NULL) {
ALOGE("%s: vendor_tag_ops argument was NULL.", __FUNCTION__);
return BAD_VALUE;
@@ -307,9 +301,9 @@
Vector<uint32_t> tagArray;
LOG_ALWAYS_FATAL_IF(tagArray.resize(tagCount) != tagCount,
- "%s: too many (%u) vendor tags defined.", __FUNCTION__, tagCount);
+ "%s: too many (%u) vendor tags defined.", __FUNCTION__, tagCount);
- vOps->get_all_tags(vOps, /*out*/tagArray.editArray());
+ vOps->get_all_tags(vOps, /*out*/ tagArray.editArray());
sp<VendorTagDescriptor> desc = new VendorTagDescriptor();
desc->mTagCount = tagCount;
@@ -323,13 +317,13 @@
ALOGE("%s: vendor tag %d not in vendor tag section.", __FUNCTION__, tag);
return BAD_VALUE;
}
- const char *tagName = vOps->get_tag_name(vOps, tag);
+ const char* tagName = vOps->get_tag_name(vOps, tag);
if (tagName == NULL) {
ALOGE("%s: no tag name defined for vendor tag %d.", __FUNCTION__, tag);
return BAD_VALUE;
}
desc->mTagToNameMap.add(tag, String8(tagName));
- const char *sectionName = vOps->get_section_name(vOps, tag);
+ const char* sectionName = vOps->get_section_name(vOps, tag);
if (sectionName == NULL) {
ALOGE("%s: no section name defined for vendor tag %d.", __FUNCTION__, tag);
return BAD_VALUE;
@@ -386,9 +380,9 @@
opsPtr->get_tag_name = vendor_tag_descriptor_get_tag_name;
opsPtr->get_tag_type = vendor_tag_descriptor_get_tag_type;
}
- if((res = set_camera_metadata_vendor_ops(opsPtr)) != OK) {
- ALOGE("%s: Could not set vendor tag descriptor, received error %s (%d)."
- , __FUNCTION__, strerror(-res), res);
+ if ((res = set_camera_metadata_vendor_ops(opsPtr)) != OK) {
+ ALOGE("%s: Could not set vendor tag descriptor, received error %s (%d).", __FUNCTION__,
+ strerror(-res), res);
}
return res;
}
@@ -405,7 +399,7 @@
}
status_t VendorTagDescriptorCache::setAsGlobalVendorTagCache(
- const sp<VendorTagDescriptorCache>& cache) {
+ const sp<VendorTagDescriptorCache>& cache) {
status_t res = OK;
Mutex::Autolock al(sLock);
sGlobalVendorTagDescriptorCache = cache;
@@ -530,9 +524,8 @@
} /* extern "C" */
-} // namespace helper
-} // namespace V1_0
-} // namespace common
-} // namespace camera
-} // namespace hardware
-} // namespace android
+} // namespace helper
+} // namespace common
+} // namespace camera
+} // namespace hardware
+} // namespace android
diff --git a/camera/common/1.0/default/include/CameraMetadata.h b/camera/common/default/include/CameraMetadata.h
similarity index 76%
rename from camera/common/1.0/default/include/CameraMetadata.h
rename to camera/common/default/include/CameraMetadata.h
index d5e4d56..b67914e 100644
--- a/camera/common/1.0/default/include/CameraMetadata.h
+++ b/camera/common/default/include/CameraMetadata.h
@@ -26,7 +26,6 @@
namespace hardware {
namespace camera {
namespace common {
-namespace V1_0 {
namespace helper {
class VendorTagDescriptor;
@@ -46,15 +45,15 @@
~CameraMetadata();
/** Takes ownership of passed-in buffer */
- CameraMetadata(camera_metadata_t *buffer);
+ CameraMetadata(camera_metadata_t* buffer);
/** Clones the metadata */
- CameraMetadata(const CameraMetadata &other);
+ CameraMetadata(const CameraMetadata& other);
/**
* Assignment clones metadata buffer.
*/
- CameraMetadata &operator=(const CameraMetadata &other);
- CameraMetadata &operator=(const camera_metadata_t *buffer);
+ CameraMetadata& operator=(const CameraMetadata& other);
+ CameraMetadata& operator=(const camera_metadata_t* buffer);
/**
* Get reference to the underlying metadata buffer. Ownership remains with
@@ -71,7 +70,7 @@
* from getAndLock must be provided to guarantee that the right object is
* being unlocked.
*/
- status_t unlock(const camera_metadata_t *buffer) const;
+ status_t unlock(const camera_metadata_t* buffer) const;
/**
* Release a raw metadata buffer to the caller. After this call,
@@ -98,12 +97,12 @@
* Acquires raw buffer from other CameraMetadata object. After the call, the argument
* object no longer has any metadata.
*/
- void acquire(CameraMetadata &other);
+ void acquire(CameraMetadata& other);
/**
* Append metadata from another CameraMetadata object.
*/
- status_t append(const CameraMetadata &other);
+ status_t append(const CameraMetadata& other);
/**
* Append metadata from a raw camera_metadata buffer
@@ -130,24 +129,16 @@
* will reallocate the buffer if insufficient space exists. Overloaded for
* the various types of valid data.
*/
- status_t update(uint32_t tag,
- const uint8_t *data, size_t data_count);
- status_t update(uint32_t tag,
- const int32_t *data, size_t data_count);
- status_t update(uint32_t tag,
- const float *data, size_t data_count);
- status_t update(uint32_t tag,
- const int64_t *data, size_t data_count);
- status_t update(uint32_t tag,
- const double *data, size_t data_count);
- status_t update(uint32_t tag,
- const camera_metadata_rational_t *data, size_t data_count);
- status_t update(uint32_t tag,
- const String8 &string);
- status_t update(const camera_metadata_ro_entry &entry);
+ status_t update(uint32_t tag, const uint8_t* data, size_t data_count);
+ status_t update(uint32_t tag, const int32_t* data, size_t data_count);
+ status_t update(uint32_t tag, const float* data, size_t data_count);
+ status_t update(uint32_t tag, const int64_t* data, size_t data_count);
+ status_t update(uint32_t tag, const double* data, size_t data_count);
+ status_t update(uint32_t tag, const camera_metadata_rational_t* data, size_t data_count);
+ status_t update(uint32_t tag, const String8& string);
+ status_t update(const camera_metadata_ro_entry& entry);
-
- template<typename T>
+ template <typename T>
status_t update(uint32_t tag, Vector<T> data) {
return update(tag, data.array(), data.size());
}
@@ -177,7 +168,7 @@
* Swap the underlying camera metadata between this and the other
* metadata object.
*/
- void swap(CameraMetadata &other);
+ void swap(CameraMetadata& other);
/**
* Dump contents into FD for debugging. The verbosity levels are
@@ -196,12 +187,12 @@
*
* This is a slow method.
*/
- static status_t getTagFromName(const char *name,
- const VendorTagDescriptor* vTags, uint32_t *tag);
+ static status_t getTagFromName(const char* name, const VendorTagDescriptor* vTags,
+ uint32_t* tag);
private:
- camera_metadata_t *mBuffer;
- mutable bool mLocked;
+ camera_metadata_t* mBuffer;
+ mutable bool mLocked;
/**
* Check if tag has a given type
@@ -211,20 +202,25 @@
/**
* Base update entry method
*/
- status_t updateImpl(uint32_t tag, const void *data, size_t data_count);
+ status_t updateImpl(uint32_t tag, const void* data, size_t data_count);
/**
* Resize metadata buffer if needed by reallocating it and copying it over.
*/
status_t resizeIfNeeded(size_t extraEntries, size_t extraData);
-
};
-} // namespace helper
-} // namespace V1_0
-} // namespace common
-} // namespace camera
-} // namespace hardware
-} // namespace android
+} // namespace helper
+
+// NOTE: Deprecated namespace. This namespace should no longer be used.
+namespace V1_0::helper {
+// Export symbols to the old namespace to preserve compatibility
+typedef android::hardware::camera::common::helper::CameraMetadata CameraMetadata;
+} // namespace V1_0::helper
+
+} // namespace common
+} // namespace camera
+} // namespace hardware
+} // namespace android
#endif
diff --git a/camera/common/1.0/default/include/CameraModule.h b/camera/common/default/include/CameraModule.h
similarity index 72%
rename from camera/common/1.0/default/include/CameraModule.h
rename to camera/common/default/include/CameraModule.h
index c89e934..5c1f8ec 100644
--- a/camera/common/1.0/default/include/CameraModule.h
+++ b/camera/common/default/include/CameraModule.h
@@ -21,8 +21,8 @@
#include <unordered_set>
#include <hardware/camera.h>
-#include <utils/Mutex.h>
#include <utils/KeyedVector.h>
+#include <utils/Mutex.h>
#include <utils/RefBase.h>
#include "CameraMetadata.h"
@@ -31,7 +31,6 @@
namespace hardware {
namespace camera {
namespace common {
-namespace V1_0 {
namespace helper {
/**
* A wrapper class for HAL camera module.
@@ -41,21 +40,21 @@
* camera characteristics keys defined in newer HAL version on an older HAL.
*/
class CameraModule : public RefBase {
-public:
- explicit CameraModule(camera_module_t *module);
+ public:
+ explicit CameraModule(camera_module_t* module);
virtual ~CameraModule();
// Must be called after construction
// Returns OK on success, NO_INIT on failure
int init();
- int getCameraInfo(int cameraId, struct camera_info *info);
+ int getCameraInfo(int cameraId, struct camera_info* info);
int getDeviceVersion(int cameraId);
int getNumberOfCameras(void);
int open(const char* id, struct hw_device_t** device);
bool isOpenLegacyDefined() const;
int openLegacy(const char* id, uint32_t halVersion, struct hw_device_t** device);
- int setCallbacks(const camera_module_callbacks_t *callbacks);
+ int setCallbacks(const camera_module_callbacks_t* callbacks);
bool isVendorTagDefined() const;
void getVendorTagOps(vendor_tag_ops_t* ops);
bool isSetTorchModeSupported() const;
@@ -65,25 +64,24 @@
uint16_t getHalApiVersion() const;
const char* getModuleAuthor() const;
// Only used by CameraModuleFixture native test. Do NOT use elsewhere.
- void *getDso();
+ void* getDso();
// Only used by CameraProvider
void removeCamera(int cameraId);
- int getPhysicalCameraInfo(int physicalCameraId, camera_metadata_t **physicalInfo);
- int isStreamCombinationSupported(int cameraId, camera_stream_combination_t *streams);
+ int getPhysicalCameraInfo(int physicalCameraId, camera_metadata_t** physicalInfo);
+ int isStreamCombinationSupported(int cameraId, camera_stream_combination_t* streams);
void notifyDeviceStateChange(uint64_t deviceState);
- static bool isLogicalMultiCamera(
- const common::V1_0::helper::CameraMetadata& metadata,
- std::unordered_set<std::string>* physicalCameraIds);
+ static bool isLogicalMultiCamera(const common::helper::CameraMetadata& metadata,
+ std::unordered_set<std::string>* physicalCameraIds);
-private:
+ private:
// Derive camera characteristics keys defined after HAL device version
- static void deriveCameraCharacteristicsKeys(uint32_t deviceVersion, CameraMetadata &chars);
+ static void deriveCameraCharacteristicsKeys(uint32_t deviceVersion, CameraMetadata& chars);
// Helper function to append available[request|result|chars]Keys
- static void appendAvailableKeys(CameraMetadata &chars,
- int32_t keyTag, const Vector<int32_t>& appendKeys);
+ static void appendAvailableKeys(CameraMetadata& chars, int32_t keyTag,
+ const Vector<int32_t>& appendKeys);
status_t filterOpenErrorCode(status_t err);
- camera_module_t *mModule;
+ camera_module_t* mModule;
int mNumberOfCameras;
KeyedVector<int, camera_info> mCameraInfoMap;
KeyedVector<int, int> mDeviceVersionMap;
@@ -91,11 +89,17 @@
Mutex mCameraInfoLock;
};
-} // namespace helper
-} // namespace V1_0
-} // namespace common
-} // namespace camera
-} // namespace hardware
-} // namespace android
+} // namespace helper
+
+// NOTE: Deprecated namespace. This namespace should no longer be used for the following symbols
+namespace V1_0::helper {
+// Export symbols to the old namespace to preserve compatibility
+typedef android::hardware::camera::common::helper::CameraModule CameraModule;
+} // namespace V1_0::helper
+
+} // namespace common
+} // namespace camera
+} // namespace hardware
+} // namespace android
#endif
diff --git a/camera/common/1.0/default/include/CameraParameters.h b/camera/common/default/include/CameraParameters.h
similarity index 94%
rename from camera/common/1.0/default/include/CameraParameters.h
rename to camera/common/default/include/CameraParameters.h
index e4ff6f2..d2b5075 100644
--- a/camera/common/1.0/default/include/CameraParameters.h
+++ b/camera/common/default/include/CameraParameters.h
@@ -24,7 +24,6 @@
namespace hardware {
namespace camera {
namespace common {
-namespace V1_0 {
namespace helper {
struct Size {
@@ -42,28 +41,27 @@
}
};
-class CameraParameters
-{
-public:
+class CameraParameters {
+ public:
CameraParameters();
- CameraParameters(const String8 ¶ms) { unflatten(params); }
+ CameraParameters(const String8& params) { unflatten(params); }
~CameraParameters();
String8 flatten() const;
- void unflatten(const String8 ¶ms);
+ void unflatten(const String8& params);
- void set(const char *key, const char *value);
- void set(const char *key, int value);
- void setFloat(const char *key, float value);
- const char *get(const char *key) const;
- int getInt(const char *key) const;
- float getFloat(const char *key) const;
+ void set(const char* key, const char* value);
+ void set(const char* key, int value);
+ void setFloat(const char* key, float value);
+ const char* get(const char* key) const;
+ int getInt(const char* key) const;
+ float getFloat(const char* key) const;
- void remove(const char *key);
+ void remove(const char* key);
void setPreviewSize(int width, int height);
- void getPreviewSize(int *width, int *height) const;
- void getSupportedPreviewSizes(Vector<Size> &sizes) const;
+ void getPreviewSize(int* width, int* height) const;
+ void getSupportedPreviewSizes(Vector<Size>& sizes) const;
// Set the dimensions in pixels to the given width and height
// for video frames. The given width and height must be one
@@ -76,14 +74,14 @@
// supported dimensions returned from getSupportedVideoSizes().
// Must not be called if getSupportedVideoSizes() returns an
// empty Vector of Size.
- void getVideoSize(int *width, int *height) const;
+ void getVideoSize(int* width, int* height) const;
// Retrieve a Vector of supported dimensions (width and height)
// in pixels for video frames. If sizes returned from the method
// is empty, the camera does not support calls to setVideoSize()
// or getVideoSize(). In adddition, it also indicates that
// the camera only has a single output, and does not have
// separate output for video frames and preview frame.
- void getSupportedVideoSizes(Vector<Size> &sizes) const;
+ void getSupportedVideoSizes(Vector<Size>& sizes) const;
// Retrieve the preferred preview size (width and height) in pixels
// for video recording. The given width and height must be one of
// supported preview sizes returned from getSupportedPreviewSizes().
@@ -91,18 +89,18 @@
// Vector of Size. If getSupportedVideoSizes() returns an empty
// Vector of Size, the width and height returned from this method
// is invalid, and is "-1x-1".
- void getPreferredPreviewSizeForVideo(int *width, int *height) const;
+ void getPreferredPreviewSizeForVideo(int* width, int* height) const;
void setPreviewFrameRate(int fps);
int getPreviewFrameRate() const;
- void getPreviewFpsRange(int *min_fps, int *max_fps) const;
- void setPreviewFormat(const char *format);
- const char *getPreviewFormat() const;
+ void getPreviewFpsRange(int* min_fps, int* max_fps) const;
+ void setPreviewFormat(const char* format);
+ const char* getPreviewFormat() const;
void setPictureSize(int width, int height);
- void getPictureSize(int *width, int *height) const;
- void getSupportedPictureSizes(Vector<Size> &sizes) const;
- void setPictureFormat(const char *format);
- const char *getPictureFormat() const;
+ void getPictureSize(int* width, int* height) const;
+ void getSupportedPictureSizes(Vector<Size>& sizes) const;
+ void setPictureFormat(const char* format);
+ const char* getPictureFormat() const;
void dump() const;
status_t dump(int fd, const Vector<String16>& args) const;
@@ -619,9 +617,9 @@
// Pixel color formats for KEY_PREVIEW_FORMAT, KEY_PICTURE_FORMAT,
// and KEY_VIDEO_FRAME_FORMAT
static const char PIXEL_FORMAT_YUV422SP[];
- static const char PIXEL_FORMAT_YUV420SP[]; // NV21
- static const char PIXEL_FORMAT_YUV422I[]; // YUY2
- static const char PIXEL_FORMAT_YUV420P[]; // YV12
+ static const char PIXEL_FORMAT_YUV420SP[]; // NV21
+ static const char PIXEL_FORMAT_YUV422I[]; // YUY2
+ static const char PIXEL_FORMAT_YUV420P[]; // YV12
static const char PIXEL_FORMAT_RGB565[];
static const char PIXEL_FORMAT_RGBA8888[];
static const char PIXEL_FORMAT_JPEG[];
@@ -695,15 +693,22 @@
*/
static int previewFormatToEnum(const char* format);
-private:
- DefaultKeyedVector<String8,String8> mMap;
+ private:
+ DefaultKeyedVector<String8, String8> mMap;
};
-};
-};
-};
-};
-};
-}; // namespace
+}; // namespace helper
+
+// NOTE: Deprecated namespace. This namespace should no longer be used for the following symbols
+namespace V1_0::helper {
+// Export symbols to the old namespace to preserve compatibility
+typedef android::hardware::camera::common::helper::CameraParameters CameraParameters;
+typedef android::hardware::camera::common::helper::Size Size;
+} // namespace V1_0::helper
+
+}; // namespace common
+}; // namespace camera
+}; // namespace hardware
+}; // namespace android
#endif
diff --git a/camera/common/1.0/default/include/Exif.h b/camera/common/default/include/Exif.h
similarity index 95%
rename from camera/common/1.0/default/include/Exif.h
rename to camera/common/default/include/Exif.h
index dc31679..6974b8e 100644
--- a/camera/common/1.0/default/include/Exif.h
+++ b/camera/common/default/include/Exif.h
@@ -23,10 +23,8 @@
namespace hardware {
namespace camera {
namespace common {
-namespace V1_0 {
namespace helper {
-
// This is based on the original ChromeOS ARC implementation of a V4L2 HAL
// ExifUtils can generate APP1 segment with tags which caller set. ExifUtils can
@@ -44,8 +42,7 @@
// uint8_t* app1Buffer = new uint8_t[app1Length];
// memcpy(app1Buffer, utils->GetApp1Buffer(), app1Length);
class ExifUtils {
-
- public:
+ public:
virtual ~ExifUtils();
static ExifUtils* create();
@@ -55,8 +52,7 @@
virtual bool initialize() = 0;
// Set all known fields from a metadata structure
- virtual bool setFromMetadata(const CameraMetadata& metadata,
- const size_t imageWidth,
+ virtual bool setFromMetadata(const CameraMetadata& metadata, const size_t imageWidth,
const size_t imageHeight) = 0;
// Sets the len aperture.
@@ -244,13 +240,17 @@
virtual unsigned int getApp1Length() = 0;
};
+} // namespace helper
-} // namespace helper
-} // namespace V1_0
-} // namespace common
-} // namespace camera
-} // namespace hardware
-} // namespace android
+// NOTE: Deprecated namespace. This namespace should no longer be used for the following symbols
+namespace V1_0::helper {
+// Export symbols to the old namespace to preserve compatibility
+typedef android::hardware::camera::common::helper::ExifUtils ExifUtils;
+} // namespace V1_0::helper
+} // namespace common
+} // namespace camera
+} // namespace hardware
+} // namespace android
#endif // ANDROID_HARDWARE_INTERFACES_CAMERA_COMMON_1_0_EXIF_H
diff --git a/camera/common/1.0/default/include/HandleImporter.h b/camera/common/default/include/HandleImporter.h
similarity index 80%
rename from camera/common/1.0/default/include/HandleImporter.h
rename to camera/common/default/include/HandleImporter.h
index 83fa755..5408ba9 100644
--- a/camera/common/1.0/default/include/HandleImporter.h
+++ b/camera/common/default/include/HandleImporter.h
@@ -30,12 +30,11 @@
namespace hardware {
namespace camera {
namespace common {
-namespace V1_0 {
namespace helper {
// Borrowed from graphics HAL. Use this until gralloc mapper HAL is working
class HandleImporter {
-public:
+ public:
HandleImporter();
// In IComposer, any buffer_handle_t is owned by the caller and we need to
@@ -59,23 +58,23 @@
// Query the stride of the first plane in bytes.
status_t getMonoPlanarStrideBytes(buffer_handle_t& buf, uint32_t* stride /*out*/);
- int unlock(buffer_handle_t& buf); // returns release fence
+ int unlock(buffer_handle_t& buf); // returns release fence
// Query Gralloc4 metadata
bool isSmpte2086Present(const buffer_handle_t& buf);
bool isSmpte2094_10Present(const buffer_handle_t& buf);
bool isSmpte2094_40Present(const buffer_handle_t& buf);
-private:
+ private:
void initializeLocked();
void cleanup();
- template<class M, class E>
+ template <class M, class E>
bool importBufferInternal(const sp<M> mapper, buffer_handle_t& handle);
- template<class M, class E>
+ template <class M, class E>
YCbCrLayout lockYCbCrInternal(const sp<M> mapper, buffer_handle_t& buf, uint64_t cpuUsage,
- const IMapper::Rect& accessRegion);
- template<class M, class E>
+ const IMapper::Rect& accessRegion);
+ template <class M, class E>
int unlockInternal(const sp<M> mapper, buffer_handle_t& buf);
Mutex mLock;
@@ -85,11 +84,17 @@
sp<graphics::mapper::V4_0::IMapper> mMapperV4;
};
-} // namespace helper
-} // namespace V1_0
-} // namespace common
-} // namespace camera
-} // namespace hardware
-} // namespace android
+} // namespace helper
-#endif // CAMERA_COMMON_1_0_HANDLEIMPORTED_H
+// NOTE: Deprecated namespace. This namespace should no longer be used for the following symbols
+namespace V1_0::helper {
+// Export symbols to the old namespace to preserve compatibility
+typedef android::hardware::camera::common::helper::HandleImporter HandleImporter;
+} // namespace V1_0::helper
+
+} // namespace common
+} // namespace camera
+} // namespace hardware
+} // namespace android
+
+#endif // CAMERA_COMMON_1_0_HANDLEIMPORTED_H
diff --git a/camera/common/default/include/SimpleThread.h b/camera/common/default/include/SimpleThread.h
new file mode 100644
index 0000000..d1becd6
--- /dev/null
+++ b/camera/common/default/include/SimpleThread.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.
+ */
+
+#ifndef HARDWARE_INTERFACES_CAMERA_COMMON_SIMPLETHREAD_H_
+#define HARDWARE_INTERFACES_CAMERA_COMMON_SIMPLETHREAD_H_
+
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace common {
+namespace helper {
+
+// A simple looper based on std::thread.
+class SimpleThread {
+ public:
+ SimpleThread();
+ virtual ~SimpleThread();
+
+ // Explicit call to start execution of the thread. No thread is created before this function
+ // is called.
+ virtual void run() final;
+ virtual void requestExitAndWait() final;
+
+ protected:
+ // Main logic of the thread. This function is called repeatedly until it returns false.
+ // Thread execution stops if this function returns false.
+ virtual bool threadLoop() = 0;
+
+ // Returns true if the thread execution should stop. Should be used by threadLoop to check if
+ // the thread has been requested to exit.
+ virtual inline bool exitPending() final { return mDone.load(std::memory_order_acquire); }
+
+ private:
+ // Wraps threadLoop in a simple while loop that allows safe exit
+ virtual void runLoop() final;
+
+ // Flag to signal end of thread execution. This flag is checked before every iteration
+ // of threadLoop.
+ std::atomic_bool mDone;
+ std::thread mThread;
+};
+
+} // namespace helper
+} // namespace common
+} // namespace camera
+} // namespace hardware
+} // namespace android
+
+#endif // HARDWARE_INTERFACES_CAMERA_COMMON_SIMPLETHREAD_H_
diff --git a/camera/common/1.0/default/include/VendorTagDescriptor.h b/camera/common/default/include/VendorTagDescriptor.h
similarity index 61%
rename from camera/common/1.0/default/include/VendorTagDescriptor.h
rename to camera/common/default/include/VendorTagDescriptor.h
index 0f54db5..3133c26 100644
--- a/camera/common/1.0/default/include/VendorTagDescriptor.h
+++ b/camera/common/default/include/VendorTagDescriptor.h
@@ -17,11 +17,11 @@
#ifndef CAMERA_COMMON_1_0_VENDORTAGDESCRIPTOR_H
#define CAMERA_COMMON_1_0_VENDORTAGDESCRIPTOR_H
-#include <utils/Vector.h>
-#include <utils/KeyedVector.h>
-#include <utils/String8.h>
-#include <utils/RefBase.h>
#include <system/camera_vendor_tags.h>
+#include <utils/KeyedVector.h>
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+#include <utils/Vector.h>
#include <stdint.h>
#include <unordered_map>
@@ -37,78 +37,77 @@
* information enumerated by the HAL to clients of the camera service.
*/
class VendorTagDescriptor {
- public:
- virtual ~VendorTagDescriptor();
+ public:
+ virtual ~VendorTagDescriptor();
- VendorTagDescriptor();
- VendorTagDescriptor(const VendorTagDescriptor& src);
- VendorTagDescriptor& operator=(const VendorTagDescriptor& rhs);
+ VendorTagDescriptor();
+ VendorTagDescriptor(const VendorTagDescriptor& src);
+ VendorTagDescriptor& operator=(const VendorTagDescriptor& rhs);
- void copyFrom(const VendorTagDescriptor& src);
+ void copyFrom(const VendorTagDescriptor& src);
- /**
- * The following 'get*' methods implement the corresponding
- * functions defined in
- * system/media/camera/include/system/camera_vendor_tags.h
- */
+ /**
+ * The following 'get*' methods implement the corresponding
+ * functions defined in
+ * system/media/camera/include/system/camera_vendor_tags.h
+ */
- // Returns the number of vendor tags defined.
- int getTagCount() const;
+ // Returns the number of vendor tags defined.
+ int getTagCount() const;
- // Returns an array containing the id's of vendor tags defined.
- void getTagArray(uint32_t* tagArray) const;
+ // Returns an array containing the id's of vendor tags defined.
+ void getTagArray(uint32_t* tagArray) const;
- // Returns the section name string for a given vendor tag id.
- const char* getSectionName(uint32_t tag) const;
+ // Returns the section name string for a given vendor tag id.
+ const char* getSectionName(uint32_t tag) const;
- // Returns the index in section vectors returned in getAllSectionNames()
- // for a given vendor tag id. -1 if input tag does not exist.
- ssize_t getSectionIndex(uint32_t tag) const;
+ // Returns the index in section vectors returned in getAllSectionNames()
+ // for a given vendor tag id. -1 if input tag does not exist.
+ ssize_t getSectionIndex(uint32_t tag) const;
- // Returns the tag name string for a given vendor tag id.
- const char* getTagName(uint32_t tag) const;
+ // Returns the tag name string for a given vendor tag id.
+ const char* getTagName(uint32_t tag) const;
- // Returns the tag type for a given vendor tag id.
- int getTagType(uint32_t tag) const;
+ // Returns the tag type for a given vendor tag id.
+ int getTagType(uint32_t tag) const;
- /**
- * Convenience method to get a vector containing all vendor tag
- * sections, or an empty vector if none are defined.
- * The pointer is valid for the lifetime of the VendorTagDescriptor,
- * or until copyFrom is invoked.
- */
- const SortedVector<String8>* getAllSectionNames() const;
+ /**
+ * Convenience method to get a vector containing all vendor tag
+ * sections, or an empty vector if none are defined.
+ * The pointer is valid for the lifetime of the VendorTagDescriptor,
+ * or until copyFrom is invoked.
+ */
+ const SortedVector<String8>* getAllSectionNames() const;
- /**
- * Lookup the tag id for a given tag name and section.
- *
- * Returns OK on success, or a negative error code.
- */
- status_t lookupTag(const String8& name, const String8& section, /*out*/uint32_t* tag) const;
+ /**
+ * Lookup the tag id for a given tag name and section.
+ *
+ * Returns OK on success, or a negative error code.
+ */
+ status_t lookupTag(const String8& name, const String8& section, /*out*/ uint32_t* tag) const;
- /**
- * Dump the currently configured vendor tags to a file descriptor.
- */
- void dump(int fd, int verbosity, int indentation) const;
+ /**
+ * Dump the currently configured vendor tags to a file descriptor.
+ */
+ void dump(int fd, int verbosity, int indentation) const;
- protected:
- KeyedVector<String8, KeyedVector<String8, uint32_t>*> mReverseMapping;
- KeyedVector<uint32_t, String8> mTagToNameMap;
- KeyedVector<uint32_t, uint32_t> mTagToSectionMap; // Value is offset in mSections
+ protected:
+ KeyedVector<String8, KeyedVector<String8, uint32_t>*> mReverseMapping;
+ KeyedVector<uint32_t, String8> mTagToNameMap;
+ KeyedVector<uint32_t, uint32_t> mTagToSectionMap; // Value is offset in mSections
- std::unordered_map<uint32_t, int32_t> mTagToTypeMap;
- SortedVector<String8> mSections;
- // must be int32_t to be compatible with Parcel::writeInt32
- int32_t mTagCount;
+ std::unordered_map<uint32_t, int32_t> mTagToTypeMap;
+ SortedVector<String8> mSections;
+ // must be int32_t to be compatible with Parcel::writeInt32
+ int32_t mTagCount;
- vendor_tag_ops mVendorOps;
+ vendor_tag_ops mVendorOps;
};
} /* namespace params */
} /* namespace camera2 */
namespace camera {
namespace common {
-namespace V1_0 {
namespace helper {
/**
@@ -119,12 +118,9 @@
* Parcelable objects cannot require being kept in an sp<> and still work with auto-generated AIDL
* interface implementations.
*/
-class VendorTagDescriptor :
- public ::android::hardware::camera2::params::VendorTagDescriptor,
- public LightRefBase<VendorTagDescriptor> {
-
+class VendorTagDescriptor : public ::android::hardware::camera2::params::VendorTagDescriptor,
+ public LightRefBase<VendorTagDescriptor> {
public:
-
/**
* Create a VendorTagDescriptor object from the given vendor_tag_ops_t
* struct.
@@ -132,8 +128,8 @@
* Returns OK on success, or a negative error code.
*/
static status_t createDescriptorFromOps(const vendor_tag_ops_t* vOps,
- /*out*/
- sp<VendorTagDescriptor>& descriptor);
+ /*out*/
+ sp<VendorTagDescriptor>& descriptor);
/**
* Sets the global vendor tag descriptor to use for this process.
@@ -154,11 +150,9 @@
* Clears the global vendor tag descriptor used by this process.
*/
static void clearGlobalVendorTagDescriptor();
-
};
} /* namespace helper */
-} /* namespace V1_0 */
} /* namespace common */
} /* namespace camera */
@@ -166,9 +160,8 @@
namespace params {
class VendorTagDescriptorCache {
- public:
- typedef android::hardware::camera::common::V1_0::helper::VendorTagDescriptor
- VendorTagDescriptor;
+ public:
+ typedef android::hardware::camera::common::helper::VendorTagDescriptor VendorTagDescriptor;
VendorTagDescriptorCache(){};
int32_t addVendorDescriptor(metadata_vendor_id_t id, sp<VendorTagDescriptor> desc);
@@ -194,7 +187,7 @@
*/
void dump(int fd, int verbosity, int indentation) const;
- protected:
+ protected:
std::unordered_map<metadata_vendor_id_t, sp<VendorTagDescriptor>> mVendorMap;
struct vendor_tag_cache_ops mVendorCacheOps;
};
@@ -204,13 +197,12 @@
namespace camera {
namespace common {
-namespace V1_0 {
namespace helper {
class VendorTagDescriptorCache
: public ::android::hardware::camera2::params::VendorTagDescriptorCache,
public LightRefBase<VendorTagDescriptorCache> {
- public:
+ public:
/**
* Sets the global vendor tag descriptor cache to use for this process.
* Camera metadata operations that access vendor tags will use the
@@ -232,11 +224,19 @@
static void clearGlobalVendorTagCache();
};
-} // namespace helper
-} // namespace V1_0
-} // namespace common
-} // namespace camera
-} // namespace hardware
-} // namespace android
+} // namespace helper
+
+// NOTE: Deprecated namespace. This namespace should no longer be used for the following symbols
+namespace V1_0::helper {
+// Export symbols to the old namespace to preserve compatibility
+typedef android::hardware::camera::common::helper::VendorTagDescriptor VendorTagDescriptor;
+typedef android::hardware::camera::common::helper::VendorTagDescriptorCache
+ VendorTagDescriptorCache;
+} // namespace V1_0::helper
+
+} // namespace common
+} // namespace camera
+} // namespace hardware
+} // namespace android
#endif /* CAMERA_COMMON_1_0_VENDORTAGDESCRIPTOR_H */
diff --git a/camera/device/aidl/Android.bp b/camera/device/aidl/Android.bp
index c184677..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",
@@ -27,6 +28,9 @@
sdk_version: "module_current",
enabled: false,
},
+ rust: {
+ enabled: true,
+ }
},
versions_with_info: [
{
diff --git a/camera/device/default/Android.bp b/camera/device/default/Android.bp
new file mode 100644
index 0000000..b577597
--- /dev/null
+++ b/camera/device/default/Android.bp
@@ -0,0 +1,71 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_shared {
+ name: "camera.device-external-impl",
+ defaults: ["hidl_defaults"],
+ proprietary: true,
+ srcs: [
+ "ExternalCameraDevice.cpp",
+ "ExternalCameraDeviceSession.cpp",
+ "ExternalCameraOfflineSession.cpp",
+ "ExternalCameraUtils.cpp",
+ "convert.cpp",
+ ],
+ shared_libs: [
+ "android.hardware.camera.common-V1-ndk",
+ "android.hardware.camera.device-V1-ndk",
+ "android.hardware.graphics.allocator-V1-ndk",
+ "android.hardware.graphics.common-V4-ndk",
+ "android.hardware.graphics.mapper@2.0",
+ "android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
+ "android.hidl.allocator@1.0",
+ "android.hidl.memory@1.0",
+ "libbinder_ndk",
+ "libcamera_metadata",
+ "libcutils",
+ "libexif",
+ "libfmq",
+ "libgralloctypes",
+ "libhardware",
+ "libhidlbase",
+ "libhidlmemory",
+ "libjpeg",
+ "liblog",
+ "libsync",
+ "libtinyxml2",
+ "libutils",
+ "libyuv",
+ ],
+ static_libs: [
+ "android.hardware.camera.common@1.0-helper",
+ "libaidlcommonsupport",
+ ],
+ header_libs: [
+ "media_plugin_headers",
+ ],
+ export_include_dirs: ["."],
+}
diff --git a/camera/device/default/ExternalCameraDevice.cpp b/camera/device/default/ExternalCameraDevice.cpp
new file mode 100644
index 0000000..677fb42
--- /dev/null
+++ b/camera/device/default/ExternalCameraDevice.cpp
@@ -0,0 +1,1001 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "ExtCamDev"
+// #define LOG_NDEBUG 0
+#include <log/log.h>
+
+#include "ExternalCameraDevice.h"
+
+#include <aidl/android/hardware/camera/common/Status.h>
+#include <convert.h>
+#include <linux/videodev2.h>
+#include <regex>
+#include <set>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace implementation {
+
+using ::aidl::android::hardware::camera::common::Status;
+
+namespace {
+// Only support MJPEG for now as it seems to be the one supports higher fps
+// Other formats to consider in the future:
+// * V4L2_PIX_FMT_YVU420 (== YV12)
+// * V4L2_PIX_FMT_YVYU (YVYU: can be converted to YV12 or other YUV420_888 formats)
+const std::array<uint32_t, /*size*/ 2> kSupportedFourCCs{
+ {V4L2_PIX_FMT_MJPEG, V4L2_PIX_FMT_Z16}}; // double braces required in C++11
+
+constexpr int MAX_RETRY = 5; // Allow retry v4l2 open failures a few times.
+constexpr int OPEN_RETRY_SLEEP_US = 100'000; // 100ms * MAX_RETRY = 0.5 seconds
+
+const std::regex kDevicePathRE("/dev/video([0-9]+)");
+} // namespace
+
+std::string ExternalCameraDevice::kDeviceVersion = "1.1";
+
+ExternalCameraDevice::ExternalCameraDevice(const std::string& devicePath,
+ const ExternalCameraConfig& config)
+ : mCameraId("-1"), mDevicePath(devicePath), mCfg(config) {
+ std::smatch sm;
+ if (std::regex_match(mDevicePath, sm, kDevicePathRE)) {
+ mCameraId = std::to_string(mCfg.cameraIdOffset + std::stoi(sm[1]));
+ } else {
+ ALOGE("%s: device path match failed for %s", __FUNCTION__, mDevicePath.c_str());
+ }
+}
+
+ExternalCameraDevice::~ExternalCameraDevice() {}
+
+ndk::ScopedAStatus ExternalCameraDevice::getCameraCharacteristics(CameraMetadata* _aidl_return) {
+ Mutex::Autolock _l(mLock);
+ if (_aidl_return == nullptr) {
+ return fromStatus(Status::ILLEGAL_ARGUMENT);
+ }
+
+ if (isInitFailedLocked()) {
+ return fromStatus(Status::INTERNAL_ERROR);
+ }
+
+ const camera_metadata_t* rawMetadata = mCameraCharacteristics.getAndLock();
+ convertToAidl(rawMetadata, _aidl_return);
+ mCameraCharacteristics.unlock(rawMetadata);
+ return fromStatus(Status::OK);
+}
+
+ndk::ScopedAStatus ExternalCameraDevice::getPhysicalCameraCharacteristics(const std::string&,
+ CameraMetadata*) {
+ ALOGE("%s: Physical camera functions are not supported for external cameras.", __FUNCTION__);
+ return fromStatus(Status::ILLEGAL_ARGUMENT);
+}
+
+ndk::ScopedAStatus ExternalCameraDevice::getResourceCost(CameraResourceCost* _aidl_return) {
+ if (_aidl_return == nullptr) {
+ return fromStatus(Status::ILLEGAL_ARGUMENT);
+ }
+
+ _aidl_return->resourceCost = 100;
+ return fromStatus(Status::OK);
+}
+
+ndk::ScopedAStatus ExternalCameraDevice::isStreamCombinationSupported(
+ const StreamConfiguration& in_streams, bool* _aidl_return) {
+ if (isInitFailed()) {
+ ALOGE("%s: camera %s. camera init failed!", __FUNCTION__, mCameraId.c_str());
+ return fromStatus(Status::INTERNAL_ERROR);
+ }
+ Status s = ExternalCameraDeviceSession::isStreamCombinationSupported(in_streams,
+ mSupportedFormats, mCfg);
+ *_aidl_return = s == Status::OK;
+ return fromStatus(Status::OK);
+}
+
+ndk::ScopedAStatus ExternalCameraDevice::open(
+ const std::shared_ptr<ICameraDeviceCallback>& in_callback,
+ std::shared_ptr<ICameraDeviceSession>* _aidl_return) {
+ if (_aidl_return == nullptr) {
+ ALOGE("%s: cannot open camera %s. return session ptr is null!", __FUNCTION__,
+ mCameraId.c_str());
+ return fromStatus(Status::ILLEGAL_ARGUMENT);
+ }
+
+ Mutex::Autolock _l(mLock);
+ if (isInitFailedLocked()) {
+ ALOGE("%s: cannot open camera %s. camera init failed!", __FUNCTION__, mCameraId.c_str());
+ return fromStatus(Status::INTERNAL_ERROR);
+ }
+
+ std::shared_ptr<ExternalCameraDeviceSession> session;
+ ALOGV("%s: Initializing device for camera %s", __FUNCTION__, mCameraId.c_str());
+ session = mSession.lock();
+
+ if (session != nullptr && !session->isClosed()) {
+ ALOGE("%s: cannot open an already opened camera!", __FUNCTION__);
+ return fromStatus(Status::CAMERA_IN_USE);
+ }
+
+ int numAttempt = 0;
+ unique_fd fd(::open(mDevicePath.c_str(), O_RDWR));
+ while (fd.get() < 0 && numAttempt < MAX_RETRY) {
+ // Previous retry attempts failed. Retry opening the device at most MAX_RETRY times
+ ALOGW("%s: v4l2 device %s open failed, wait 33ms and try again", __FUNCTION__,
+ mDevicePath.c_str());
+ usleep(OPEN_RETRY_SLEEP_US); // sleep and try again
+ fd.reset(::open(mDevicePath.c_str(), O_RDWR));
+ numAttempt++;
+ }
+
+ if (fd.get() < 0) {
+ ALOGE("%s: v4l2 device open %s failed: %s", __FUNCTION__, mDevicePath.c_str(),
+ strerror(errno));
+ return fromStatus(Status::INTERNAL_ERROR);
+ }
+
+ session = createSession(in_callback, mCfg, mSupportedFormats, mCroppingType,
+ mCameraCharacteristics, mCameraId, std::move(fd));
+ if (session == nullptr) {
+ ALOGE("%s: camera device session allocation failed", __FUNCTION__);
+ return fromStatus(Status::INTERNAL_ERROR);
+ }
+
+ if (session->isInitFailed()) {
+ ALOGE("%s: camera device session init failed", __FUNCTION__);
+ return fromStatus(Status::INTERNAL_ERROR);
+ }
+
+ mSession = session;
+ *_aidl_return = session;
+ return fromStatus(Status::OK);
+}
+
+ndk::ScopedAStatus ExternalCameraDevice::openInjectionSession(
+ const std::shared_ptr<ICameraDeviceCallback>&, std::shared_ptr<ICameraInjectionSession>*) {
+ return fromStatus(Status::OPERATION_NOT_SUPPORTED);
+}
+
+ndk::ScopedAStatus ExternalCameraDevice::setTorchMode(bool) {
+ return fromStatus(Status::OPERATION_NOT_SUPPORTED);
+}
+
+ndk::ScopedAStatus ExternalCameraDevice::turnOnTorchWithStrengthLevel(int32_t) {
+ return fromStatus(Status::OPERATION_NOT_SUPPORTED);
+}
+
+ndk::ScopedAStatus ExternalCameraDevice::getTorchStrengthLevel(int32_t*) {
+ return fromStatus(Status::OPERATION_NOT_SUPPORTED);
+}
+
+std::shared_ptr<ExternalCameraDeviceSession> ExternalCameraDevice::createSession(
+ const std::shared_ptr<ICameraDeviceCallback>& cb, const ExternalCameraConfig& cfg,
+ const std::vector<SupportedV4L2Format>& sortedFormats, const CroppingType& croppingType,
+ const common::V1_0::helper::CameraMetadata& chars, const std::string& cameraId,
+ unique_fd v4l2Fd) {
+ return ndk::SharedRefBase::make<ExternalCameraDeviceSession>(
+ cb, cfg, sortedFormats, croppingType, chars, cameraId, std::move(v4l2Fd));
+}
+
+bool ExternalCameraDevice::isInitFailed() {
+ Mutex::Autolock _l(mLock);
+ return isInitFailedLocked();
+}
+
+bool ExternalCameraDevice::isInitFailedLocked() {
+ if (!mInitialized) {
+ status_t ret = initCameraCharacteristics();
+ if (ret != OK) {
+ ALOGE("%s: init camera characteristics failed: errorno %d", __FUNCTION__, ret);
+ mInitFailed = true;
+ }
+ mInitialized = true;
+ }
+ return mInitFailed;
+}
+
+void ExternalCameraDevice::initSupportedFormatsLocked(int fd) {
+ std::vector<SupportedV4L2Format> horizontalFmts =
+ getCandidateSupportedFormatsLocked(fd, HORIZONTAL, mCfg.fpsLimits, mCfg.depthFpsLimits,
+ mCfg.minStreamSize, mCfg.depthEnabled);
+ std::vector<SupportedV4L2Format> verticalFmts =
+ getCandidateSupportedFormatsLocked(fd, VERTICAL, mCfg.fpsLimits, mCfg.depthFpsLimits,
+ mCfg.minStreamSize, mCfg.depthEnabled);
+
+ size_t horiSize = horizontalFmts.size();
+ size_t vertSize = verticalFmts.size();
+
+ if (horiSize == 0 && vertSize == 0) {
+ ALOGE("%s: cannot find suitable cropping type!", __FUNCTION__);
+ return;
+ }
+
+ if (horiSize == 0) {
+ mSupportedFormats = verticalFmts;
+ mCroppingType = VERTICAL;
+ return;
+ } else if (vertSize == 0) {
+ mSupportedFormats = horizontalFmts;
+ mCroppingType = HORIZONTAL;
+ return;
+ }
+
+ const auto& maxHoriSize = horizontalFmts[horizontalFmts.size() - 1];
+ const auto& maxVertSize = verticalFmts[verticalFmts.size() - 1];
+
+ // Try to keep the largest possible output size
+ // When they are the same or ambiguous, pick the one support more sizes
+ if (maxHoriSize.width == maxVertSize.width && maxHoriSize.height == maxVertSize.height) {
+ if (horiSize > vertSize) {
+ mSupportedFormats = horizontalFmts;
+ mCroppingType = HORIZONTAL;
+ } else {
+ mSupportedFormats = verticalFmts;
+ mCroppingType = VERTICAL;
+ }
+ } else if (maxHoriSize.width >= maxVertSize.width && maxHoriSize.height >= maxVertSize.height) {
+ mSupportedFormats = horizontalFmts;
+ mCroppingType = HORIZONTAL;
+ } else if (maxHoriSize.width <= maxVertSize.width && maxHoriSize.height <= maxVertSize.height) {
+ mSupportedFormats = verticalFmts;
+ mCroppingType = VERTICAL;
+ } else {
+ if (horiSize > vertSize) {
+ mSupportedFormats = horizontalFmts;
+ mCroppingType = HORIZONTAL;
+ } else {
+ mSupportedFormats = verticalFmts;
+ mCroppingType = VERTICAL;
+ }
+ }
+}
+
+status_t ExternalCameraDevice::initCameraCharacteristics() {
+ if (!mCameraCharacteristics.isEmpty()) {
+ // Camera Characteristics previously initialized. Skip.
+ return OK;
+ }
+
+ // init camera characteristics
+ unique_fd fd(::open(mDevicePath.c_str(), O_RDWR));
+ if (fd.get() < 0) {
+ ALOGE("%s: v4l2 device open %s failed", __FUNCTION__, mDevicePath.c_str());
+ return DEAD_OBJECT;
+ }
+
+ status_t ret;
+ ret = initDefaultCharsKeys(&mCameraCharacteristics);
+ if (ret != OK) {
+ ALOGE("%s: init default characteristics key failed: errorno %d", __FUNCTION__, ret);
+ mCameraCharacteristics.clear();
+ return ret;
+ }
+
+ ret = initCameraControlsCharsKeys(fd.get(), &mCameraCharacteristics);
+ if (ret != OK) {
+ ALOGE("%s: init camera control characteristics key failed: errorno %d", __FUNCTION__, ret);
+ mCameraCharacteristics.clear();
+ return ret;
+ }
+
+ ret = initOutputCharsKeys(fd.get(), &mCameraCharacteristics);
+ if (ret != OK) {
+ ALOGE("%s: init output characteristics key failed: errorno %d", __FUNCTION__, ret);
+ mCameraCharacteristics.clear();
+ return ret;
+ }
+
+ ret = initAvailableCapabilities(&mCameraCharacteristics);
+ if (ret != OK) {
+ ALOGE("%s: init available capabilities key failed: errorno %d", __FUNCTION__, ret);
+ mCameraCharacteristics.clear();
+ return ret;
+ }
+
+ return OK;
+}
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#define UPDATE(tag, data, size) \
+ do { \
+ if (metadata->update((tag), (data), (size))) { \
+ ALOGE("Update " #tag " failed!"); \
+ return -EINVAL; \
+ } \
+ } while (0)
+
+status_t ExternalCameraDevice::initAvailableCapabilities(
+ ::android::hardware::camera::common::V1_0::helper::CameraMetadata* metadata) {
+ if (mSupportedFormats.empty()) {
+ ALOGE("%s: Supported formats list is empty", __FUNCTION__);
+ return UNKNOWN_ERROR;
+ }
+
+ bool hasDepth = false;
+ bool hasColor = false;
+ for (const auto& fmt : mSupportedFormats) {
+ switch (fmt.fourcc) {
+ case V4L2_PIX_FMT_Z16:
+ hasDepth = true;
+ break;
+ case V4L2_PIX_FMT_MJPEG:
+ hasColor = true;
+ break;
+ default:
+ ALOGW("%s: Unsupported format found", __FUNCTION__);
+ }
+ }
+
+ std::vector<uint8_t> availableCapabilities;
+ if (hasDepth) {
+ availableCapabilities.push_back(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT);
+ }
+ if (hasColor) {
+ availableCapabilities.push_back(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
+ }
+ if (!availableCapabilities.empty()) {
+ UPDATE(ANDROID_REQUEST_AVAILABLE_CAPABILITIES, availableCapabilities.data(),
+ availableCapabilities.size());
+ }
+
+ return OK;
+}
+
+status_t ExternalCameraDevice::initDefaultCharsKeys(
+ ::android::hardware::camera::common::V1_0::helper::CameraMetadata* metadata) {
+ const uint8_t hardware_level = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL;
+ UPDATE(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL, &hardware_level, 1);
+
+ // android.colorCorrection
+ const uint8_t availableAberrationModes[] = {ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF};
+ UPDATE(ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES, availableAberrationModes,
+ ARRAY_SIZE(availableAberrationModes));
+
+ // android.control
+ const uint8_t antibandingMode = ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO;
+ UPDATE(ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES, &antibandingMode, 1);
+
+ const int32_t controlMaxRegions[] = {/*AE*/ 0, /*AWB*/ 0, /*AF*/ 0};
+ UPDATE(ANDROID_CONTROL_MAX_REGIONS, controlMaxRegions, ARRAY_SIZE(controlMaxRegions));
+
+ const uint8_t videoStabilizationMode = ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF;
+ UPDATE(ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES, &videoStabilizationMode, 1);
+
+ const uint8_t awbAvailableMode = ANDROID_CONTROL_AWB_MODE_AUTO;
+ UPDATE(ANDROID_CONTROL_AWB_AVAILABLE_MODES, &awbAvailableMode, 1);
+
+ const uint8_t aeAvailableMode = ANDROID_CONTROL_AE_MODE_ON;
+ UPDATE(ANDROID_CONTROL_AE_AVAILABLE_MODES, &aeAvailableMode, 1);
+
+ const uint8_t availableFffect = ANDROID_CONTROL_EFFECT_MODE_OFF;
+ UPDATE(ANDROID_CONTROL_AVAILABLE_EFFECTS, &availableFffect, 1);
+
+ const uint8_t controlAvailableModes[] = {ANDROID_CONTROL_MODE_OFF, ANDROID_CONTROL_MODE_AUTO};
+ UPDATE(ANDROID_CONTROL_AVAILABLE_MODES, controlAvailableModes,
+ ARRAY_SIZE(controlAvailableModes));
+
+ // android.edge
+ const uint8_t edgeMode = ANDROID_EDGE_MODE_OFF;
+ UPDATE(ANDROID_EDGE_AVAILABLE_EDGE_MODES, &edgeMode, 1);
+
+ // android.flash
+ const uint8_t flashInfo = ANDROID_FLASH_INFO_AVAILABLE_FALSE;
+ UPDATE(ANDROID_FLASH_INFO_AVAILABLE, &flashInfo, 1);
+
+ // android.hotPixel
+ const uint8_t hotPixelMode = ANDROID_HOT_PIXEL_MODE_OFF;
+ UPDATE(ANDROID_HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES, &hotPixelMode, 1);
+
+ // android.jpeg
+ const int32_t jpegAvailableThumbnailSizes[] = {0, 0, 176, 144, 240, 144, 256,
+ 144, 240, 160, 256, 154, 240, 180};
+ UPDATE(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES, jpegAvailableThumbnailSizes,
+ ARRAY_SIZE(jpegAvailableThumbnailSizes));
+
+ const int32_t jpegMaxSize = mCfg.maxJpegBufSize;
+ UPDATE(ANDROID_JPEG_MAX_SIZE, &jpegMaxSize, 1);
+
+ // android.lens
+ const uint8_t focusDistanceCalibration =
+ ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED;
+ UPDATE(ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION, &focusDistanceCalibration, 1);
+
+ const uint8_t opticalStabilizationMode = ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF;
+ UPDATE(ANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION, &opticalStabilizationMode, 1);
+
+ const uint8_t facing = ANDROID_LENS_FACING_EXTERNAL;
+ UPDATE(ANDROID_LENS_FACING, &facing, 1);
+
+ // android.noiseReduction
+ const uint8_t noiseReductionMode = ANDROID_NOISE_REDUCTION_MODE_OFF;
+ UPDATE(ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES, &noiseReductionMode, 1);
+ UPDATE(ANDROID_NOISE_REDUCTION_MODE, &noiseReductionMode, 1);
+
+ const int32_t partialResultCount = 1;
+ UPDATE(ANDROID_REQUEST_PARTIAL_RESULT_COUNT, &partialResultCount, 1);
+
+ // This means pipeline latency of X frame intervals. The maximum number is 4.
+ const uint8_t requestPipelineMaxDepth = 4;
+ UPDATE(ANDROID_REQUEST_PIPELINE_MAX_DEPTH, &requestPipelineMaxDepth, 1);
+
+ // Three numbers represent the maximum numbers of different types of output
+ // streams simultaneously. The types are raw sensor, processed (but not
+ // stalling), and processed (but stalling). For usb limited mode, raw sensor
+ // is not supported. Stalling stream is JPEG. Non-stalling streams are
+ // YUV_420_888 or YV12.
+ const int32_t requestMaxNumOutputStreams[] = {
+ /*RAW*/ 0,
+ /*Processed*/ ExternalCameraDeviceSession::kMaxProcessedStream,
+ /*Stall*/ ExternalCameraDeviceSession::kMaxStallStream};
+ UPDATE(ANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS, requestMaxNumOutputStreams,
+ ARRAY_SIZE(requestMaxNumOutputStreams));
+
+ // Limited mode doesn't support reprocessing.
+ const int32_t requestMaxNumInputStreams = 0;
+ UPDATE(ANDROID_REQUEST_MAX_NUM_INPUT_STREAMS, &requestMaxNumInputStreams, 1);
+
+ // android.scaler
+ // TODO: b/72263447 V4L2_CID_ZOOM_*
+ const float scalerAvailableMaxDigitalZoom[] = {1};
+ UPDATE(ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM, scalerAvailableMaxDigitalZoom,
+ ARRAY_SIZE(scalerAvailableMaxDigitalZoom));
+
+ const uint8_t croppingType = ANDROID_SCALER_CROPPING_TYPE_CENTER_ONLY;
+ UPDATE(ANDROID_SCALER_CROPPING_TYPE, &croppingType, 1);
+
+ const int32_t testPatternModes[] = {ANDROID_SENSOR_TEST_PATTERN_MODE_OFF,
+ ANDROID_SENSOR_TEST_PATTERN_MODE_SOLID_COLOR};
+ UPDATE(ANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES, testPatternModes,
+ ARRAY_SIZE(testPatternModes));
+
+ const uint8_t timestampSource = ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN;
+ UPDATE(ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE, ×tampSource, 1);
+
+ // Orientation is a bit odd for external camera, but consider it as the orientation
+ // between the external camera sensor (which is usually landscape) and the device's
+ // natural display orientation. For devices with natural landscape display (ex: tablet/TV), the
+ // orientation should be 0. For devices with natural portrait display (phone), the orientation
+ // should be 270.
+ const int32_t orientation = mCfg.orientation;
+ UPDATE(ANDROID_SENSOR_ORIENTATION, &orientation, 1);
+
+ // android.shading
+ const uint8_t availableMode = ANDROID_SHADING_MODE_OFF;
+ UPDATE(ANDROID_SHADING_AVAILABLE_MODES, &availableMode, 1);
+
+ // android.statistics
+ const uint8_t faceDetectMode = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;
+ UPDATE(ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES, &faceDetectMode, 1);
+
+ const int32_t maxFaceCount = 0;
+ UPDATE(ANDROID_STATISTICS_INFO_MAX_FACE_COUNT, &maxFaceCount, 1);
+
+ const uint8_t availableHotpixelMode = ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE_OFF;
+ UPDATE(ANDROID_STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES, &availableHotpixelMode, 1);
+
+ const uint8_t lensShadingMapMode = ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF;
+ UPDATE(ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES, &lensShadingMapMode, 1);
+
+ // android.sync
+ const int32_t maxLatency = ANDROID_SYNC_MAX_LATENCY_UNKNOWN;
+ UPDATE(ANDROID_SYNC_MAX_LATENCY, &maxLatency, 1);
+
+ /* Other sensor/RAW related keys:
+ * android.sensor.info.colorFilterArrangement -> no need if we don't do RAW
+ * android.sensor.info.physicalSize -> not available
+ * android.sensor.info.whiteLevel -> not available/not needed
+ * android.sensor.info.lensShadingApplied -> not needed
+ * android.sensor.info.preCorrectionActiveArraySize -> not available/not needed
+ * android.sensor.blackLevelPattern -> not available/not needed
+ */
+
+ const int32_t availableRequestKeys[] = {ANDROID_COLOR_CORRECTION_ABERRATION_MODE,
+ ANDROID_CONTROL_AE_ANTIBANDING_MODE,
+ ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,
+ ANDROID_CONTROL_AE_LOCK,
+ ANDROID_CONTROL_AE_MODE,
+ ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,
+ ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
+ ANDROID_CONTROL_AF_MODE,
+ ANDROID_CONTROL_AF_TRIGGER,
+ ANDROID_CONTROL_AWB_LOCK,
+ ANDROID_CONTROL_AWB_MODE,
+ ANDROID_CONTROL_CAPTURE_INTENT,
+ ANDROID_CONTROL_EFFECT_MODE,
+ ANDROID_CONTROL_MODE,
+ ANDROID_CONTROL_SCENE_MODE,
+ ANDROID_CONTROL_VIDEO_STABILIZATION_MODE,
+ ANDROID_FLASH_MODE,
+ ANDROID_JPEG_ORIENTATION,
+ ANDROID_JPEG_QUALITY,
+ ANDROID_JPEG_THUMBNAIL_QUALITY,
+ ANDROID_JPEG_THUMBNAIL_SIZE,
+ ANDROID_LENS_OPTICAL_STABILIZATION_MODE,
+ ANDROID_NOISE_REDUCTION_MODE,
+ ANDROID_SCALER_CROP_REGION,
+ ANDROID_SENSOR_TEST_PATTERN_MODE,
+ ANDROID_STATISTICS_FACE_DETECT_MODE,
+ ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE};
+ UPDATE(ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS, availableRequestKeys,
+ ARRAY_SIZE(availableRequestKeys));
+
+ const int32_t availableResultKeys[] = {ANDROID_COLOR_CORRECTION_ABERRATION_MODE,
+ ANDROID_CONTROL_AE_ANTIBANDING_MODE,
+ ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,
+ ANDROID_CONTROL_AE_LOCK,
+ ANDROID_CONTROL_AE_MODE,
+ ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,
+ ANDROID_CONTROL_AE_STATE,
+ ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
+ ANDROID_CONTROL_AF_MODE,
+ ANDROID_CONTROL_AF_STATE,
+ ANDROID_CONTROL_AF_TRIGGER,
+ ANDROID_CONTROL_AWB_LOCK,
+ ANDROID_CONTROL_AWB_MODE,
+ ANDROID_CONTROL_AWB_STATE,
+ ANDROID_CONTROL_CAPTURE_INTENT,
+ ANDROID_CONTROL_EFFECT_MODE,
+ ANDROID_CONTROL_MODE,
+ ANDROID_CONTROL_SCENE_MODE,
+ ANDROID_CONTROL_VIDEO_STABILIZATION_MODE,
+ ANDROID_FLASH_MODE,
+ ANDROID_FLASH_STATE,
+ ANDROID_JPEG_ORIENTATION,
+ ANDROID_JPEG_QUALITY,
+ ANDROID_JPEG_THUMBNAIL_QUALITY,
+ ANDROID_JPEG_THUMBNAIL_SIZE,
+ ANDROID_LENS_OPTICAL_STABILIZATION_MODE,
+ ANDROID_NOISE_REDUCTION_MODE,
+ ANDROID_REQUEST_PIPELINE_DEPTH,
+ ANDROID_SCALER_CROP_REGION,
+ ANDROID_SENSOR_TIMESTAMP,
+ ANDROID_STATISTICS_FACE_DETECT_MODE,
+ ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE,
+ ANDROID_STATISTICS_LENS_SHADING_MAP_MODE,
+ ANDROID_STATISTICS_SCENE_FLICKER};
+ UPDATE(ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, availableResultKeys,
+ ARRAY_SIZE(availableResultKeys));
+
+ UPDATE(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, AVAILABLE_CHARACTERISTICS_KEYS.data(),
+ AVAILABLE_CHARACTERISTICS_KEYS.size());
+
+ return OK;
+}
+
+status_t ExternalCameraDevice::initCameraControlsCharsKeys(
+ int, ::android::hardware::camera::common::V1_0::helper::CameraMetadata* metadata) {
+ // android.sensor.info.sensitivityRange -> V4L2_CID_ISO_SENSITIVITY
+ // android.sensor.info.exposureTimeRange -> V4L2_CID_EXPOSURE_ABSOLUTE
+ // android.sensor.info.maxFrameDuration -> TBD
+ // android.lens.info.minimumFocusDistance -> V4L2_CID_FOCUS_ABSOLUTE
+ // android.lens.info.hyperfocalDistance
+ // android.lens.info.availableFocalLengths -> not available?
+
+ // android.control
+ // No AE compensation support for now.
+ // TODO: V4L2_CID_EXPOSURE_BIAS
+ const int32_t controlAeCompensationRange[] = {0, 0};
+ UPDATE(ANDROID_CONTROL_AE_COMPENSATION_RANGE, controlAeCompensationRange,
+ ARRAY_SIZE(controlAeCompensationRange));
+ const camera_metadata_rational_t controlAeCompensationStep[] = {{0, 1}};
+ UPDATE(ANDROID_CONTROL_AE_COMPENSATION_STEP, controlAeCompensationStep,
+ ARRAY_SIZE(controlAeCompensationStep));
+
+ // TODO: Check V4L2_CID_AUTO_FOCUS_*.
+ const uint8_t afAvailableModes[] = {ANDROID_CONTROL_AF_MODE_AUTO, ANDROID_CONTROL_AF_MODE_OFF};
+ UPDATE(ANDROID_CONTROL_AF_AVAILABLE_MODES, afAvailableModes, ARRAY_SIZE(afAvailableModes));
+
+ // TODO: V4L2_CID_SCENE_MODE
+ const uint8_t availableSceneMode = ANDROID_CONTROL_SCENE_MODE_DISABLED;
+ UPDATE(ANDROID_CONTROL_AVAILABLE_SCENE_MODES, &availableSceneMode, 1);
+
+ // TODO: V4L2_CID_3A_LOCK
+ const uint8_t aeLockAvailable = ANDROID_CONTROL_AE_LOCK_AVAILABLE_FALSE;
+ UPDATE(ANDROID_CONTROL_AE_LOCK_AVAILABLE, &aeLockAvailable, 1);
+ const uint8_t awbLockAvailable = ANDROID_CONTROL_AWB_LOCK_AVAILABLE_FALSE;
+ UPDATE(ANDROID_CONTROL_AWB_LOCK_AVAILABLE, &awbLockAvailable, 1);
+
+ // TODO: V4L2_CID_ZOOM_*
+ const float scalerAvailableMaxDigitalZoom[] = {1};
+ UPDATE(ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM, scalerAvailableMaxDigitalZoom,
+ ARRAY_SIZE(scalerAvailableMaxDigitalZoom));
+
+ return OK;
+}
+
+status_t ExternalCameraDevice::initOutputCharsKeys(
+ int fd, ::android::hardware::camera::common::V1_0::helper::CameraMetadata* metadata) {
+ initSupportedFormatsLocked(fd);
+ if (mSupportedFormats.empty()) {
+ ALOGE("%s: Init supported format list failed", __FUNCTION__);
+ return UNKNOWN_ERROR;
+ }
+
+ bool hasDepth = false;
+ bool hasColor = false;
+
+ // For V4L2_PIX_FMT_Z16
+ std::array<int, /*size*/ 1> halDepthFormats{{HAL_PIXEL_FORMAT_Y16}};
+ // For V4L2_PIX_FMT_MJPEG
+ std::array<int, /*size*/ 3> halFormats{{HAL_PIXEL_FORMAT_BLOB, HAL_PIXEL_FORMAT_YCbCr_420_888,
+ HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED}};
+
+ for (const auto& supportedFormat : mSupportedFormats) {
+ switch (supportedFormat.fourcc) {
+ case V4L2_PIX_FMT_Z16:
+ hasDepth = true;
+ break;
+ case V4L2_PIX_FMT_MJPEG:
+ hasColor = true;
+ break;
+ default:
+ ALOGW("%s: format %c%c%c%c is not supported!", __FUNCTION__,
+ supportedFormat.fourcc & 0xFF, (supportedFormat.fourcc >> 8) & 0xFF,
+ (supportedFormat.fourcc >> 16) & 0xFF, (supportedFormat.fourcc >> 24) & 0xFF);
+ }
+ }
+
+ if (hasDepth) {
+ status_t ret = initOutputCharsKeysByFormat(
+ metadata, V4L2_PIX_FMT_Z16, halDepthFormats,
+ ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS_OUTPUT,
+ ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS,
+ ANDROID_DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS,
+ ANDROID_DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS);
+ if (ret != OK) {
+ ALOGE("%s: Unable to initialize depth format keys: %s", __FUNCTION__,
+ statusToString(ret).c_str());
+ return ret;
+ }
+ }
+ if (hasColor) {
+ status_t ret =
+ initOutputCharsKeysByFormat(metadata, V4L2_PIX_FMT_MJPEG, halFormats,
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+ ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,
+ ANDROID_SCALER_AVAILABLE_STALL_DURATIONS);
+ if (ret != OK) {
+ ALOGE("%s: Unable to initialize color format keys: %s", __FUNCTION__,
+ statusToString(ret).c_str());
+ return ret;
+ }
+ }
+
+ status_t ret = calculateMinFps(metadata);
+ if (ret != OK) {
+ ALOGE("%s: Unable to update fps metadata: %s", __FUNCTION__, statusToString(ret).c_str());
+ return ret;
+ }
+
+ SupportedV4L2Format maximumFormat{.width = 0, .height = 0};
+ for (const auto& supportedFormat : mSupportedFormats) {
+ if (supportedFormat.width >= maximumFormat.width &&
+ supportedFormat.height >= maximumFormat.height) {
+ maximumFormat = supportedFormat;
+ }
+ }
+ int32_t activeArraySize[] = {0, 0, static_cast<int32_t>(maximumFormat.width),
+ static_cast<int32_t>(maximumFormat.height)};
+ UPDATE(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE, activeArraySize,
+ ARRAY_SIZE(activeArraySize));
+ UPDATE(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE, activeArraySize, ARRAY_SIZE(activeArraySize));
+
+ int32_t pixelArraySize[] = {static_cast<int32_t>(maximumFormat.width),
+ static_cast<int32_t>(maximumFormat.height)};
+ UPDATE(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE, pixelArraySize, ARRAY_SIZE(pixelArraySize));
+ return OK;
+}
+
+template <size_t SIZE>
+status_t ExternalCameraDevice::initOutputCharsKeysByFormat(
+ ::android::hardware::camera::common::V1_0::helper::CameraMetadata* metadata,
+ uint32_t fourcc, const std::array<int, SIZE>& halFormats, int streamConfigTag,
+ int streamConfigurationKey, int minFrameDurationKey, int stallDurationKey) {
+ if (mSupportedFormats.empty()) {
+ ALOGE("%s: Init supported format list failed", __FUNCTION__);
+ return UNKNOWN_ERROR;
+ }
+
+ std::vector<int32_t> streamConfigurations;
+ std::vector<int64_t> minFrameDurations;
+ std::vector<int64_t> stallDurations;
+
+ for (const auto& supportedFormat : mSupportedFormats) {
+ if (supportedFormat.fourcc != fourcc) {
+ // Skip 4CCs not meant for the halFormats
+ continue;
+ }
+ for (const auto& format : halFormats) {
+ streamConfigurations.push_back(format);
+ streamConfigurations.push_back(supportedFormat.width);
+ streamConfigurations.push_back(supportedFormat.height);
+ streamConfigurations.push_back(streamConfigTag);
+ }
+
+ int64_t minFrameDuration = std::numeric_limits<int64_t>::max();
+ for (const auto& fr : supportedFormat.frameRates) {
+ // 1000000000LL < (2^32 - 1) and
+ // fr.durationNumerator is uint32_t, so no overflow here
+ int64_t frameDuration = 1000000000LL * fr.durationNumerator / fr.durationDenominator;
+ if (frameDuration < minFrameDuration) {
+ minFrameDuration = frameDuration;
+ }
+ }
+
+ for (const auto& format : halFormats) {
+ minFrameDurations.push_back(format);
+ minFrameDurations.push_back(supportedFormat.width);
+ minFrameDurations.push_back(supportedFormat.height);
+ minFrameDurations.push_back(minFrameDuration);
+ }
+
+ // The stall duration is 0 for non-jpeg formats. For JPEG format, stall
+ // duration can be 0 if JPEG is small. Here we choose 1 sec for JPEG.
+ // TODO: b/72261675. Maybe set this dynamically
+ for (const auto& format : halFormats) {
+ const int64_t NS_TO_SECOND = 1E9;
+ int64_t stall_duration = (format == HAL_PIXEL_FORMAT_BLOB) ? NS_TO_SECOND : 0;
+ stallDurations.push_back(format);
+ stallDurations.push_back(supportedFormat.width);
+ stallDurations.push_back(supportedFormat.height);
+ stallDurations.push_back(stall_duration);
+ }
+ }
+
+ UPDATE(streamConfigurationKey, streamConfigurations.data(), streamConfigurations.size());
+
+ UPDATE(minFrameDurationKey, minFrameDurations.data(), minFrameDurations.size());
+
+ UPDATE(stallDurationKey, stallDurations.data(), stallDurations.size());
+
+ return OK;
+}
+
+status_t ExternalCameraDevice::calculateMinFps(
+ ::android::hardware::camera::common::V1_0::helper::CameraMetadata* metadata) {
+ std::set<int32_t> framerates;
+ int32_t minFps = std::numeric_limits<int32_t>::max();
+
+ for (const auto& supportedFormat : mSupportedFormats) {
+ for (const auto& fr : supportedFormat.frameRates) {
+ int32_t frameRateInt = static_cast<int32_t>(fr.getFramesPerSecond());
+ if (minFps > frameRateInt) {
+ minFps = frameRateInt;
+ }
+ framerates.insert(frameRateInt);
+ }
+ }
+
+ std::vector<int32_t> fpsRanges;
+ // FPS ranges
+ for (const auto& framerate : framerates) {
+ // Empirical: webcams often have close to 2x fps error and cannot support fixed fps range
+ fpsRanges.push_back(framerate / 2);
+ fpsRanges.push_back(framerate);
+ }
+ minFps /= 2;
+ int64_t maxFrameDuration = 1000000000LL / minFps;
+
+ UPDATE(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, fpsRanges.data(), fpsRanges.size());
+
+ UPDATE(ANDROID_SENSOR_INFO_MAX_FRAME_DURATION, &maxFrameDuration, 1);
+
+ return OK;
+}
+
+#undef ARRAY_SIZE
+#undef UPDATE
+
+void ExternalCameraDevice::getFrameRateList(int fd, double fpsUpperBound,
+ SupportedV4L2Format* format) {
+ format->frameRates.clear();
+
+ v4l2_frmivalenum frameInterval{
+ .index = 0,
+ .pixel_format = format->fourcc,
+ .width = static_cast<__u32>(format->width),
+ .height = static_cast<__u32>(format->height),
+ };
+
+ for (frameInterval.index = 0;
+ TEMP_FAILURE_RETRY(ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frameInterval)) == 0;
+ ++frameInterval.index) {
+ if (frameInterval.type == V4L2_FRMIVAL_TYPE_DISCRETE) {
+ if (frameInterval.discrete.numerator != 0) {
+ SupportedV4L2Format::FrameRate fr = {frameInterval.discrete.numerator,
+ frameInterval.discrete.denominator};
+ double framerate = fr.getFramesPerSecond();
+ if (framerate > fpsUpperBound) {
+ continue;
+ }
+ ALOGV("index:%d, format:%c%c%c%c, w %d, h %d, framerate %f", frameInterval.index,
+ frameInterval.pixel_format & 0xFF, (frameInterval.pixel_format >> 8) & 0xFF,
+ (frameInterval.pixel_format >> 16) & 0xFF,
+ (frameInterval.pixel_format >> 24) & 0xFF, frameInterval.width,
+ frameInterval.height, framerate);
+ format->frameRates.push_back(fr);
+ }
+ }
+ }
+
+ if (format->frameRates.empty()) {
+ ALOGE("%s: failed to get supported frame rates for format:%c%c%c%c w %d h %d", __FUNCTION__,
+ frameInterval.pixel_format & 0xFF, (frameInterval.pixel_format >> 8) & 0xFF,
+ (frameInterval.pixel_format >> 16) & 0xFF, (frameInterval.pixel_format >> 24) & 0xFF,
+ frameInterval.width, frameInterval.height);
+ }
+}
+
+void ExternalCameraDevice::updateFpsBounds(
+ int fd, CroppingType cropType,
+ const std::vector<ExternalCameraConfig::FpsLimitation>& fpsLimits,
+ SupportedV4L2Format format, std::vector<SupportedV4L2Format>& outFmts) {
+ double fpsUpperBound = -1.0;
+ for (const auto& limit : fpsLimits) {
+ if (cropType == VERTICAL) {
+ if (format.width <= limit.size.width) {
+ fpsUpperBound = limit.fpsUpperBound;
+ break;
+ }
+ } else { // HORIZONTAL
+ if (format.height <= limit.size.height) {
+ fpsUpperBound = limit.fpsUpperBound;
+ break;
+ }
+ }
+ }
+ if (fpsUpperBound < 0.f) {
+ return;
+ }
+
+ getFrameRateList(fd, fpsUpperBound, &format);
+ if (!format.frameRates.empty()) {
+ outFmts.push_back(format);
+ }
+}
+
+std::vector<SupportedV4L2Format> ExternalCameraDevice::getCandidateSupportedFormatsLocked(
+ int fd, CroppingType cropType,
+ const std::vector<ExternalCameraConfig::FpsLimitation>& fpsLimits,
+ const std::vector<ExternalCameraConfig::FpsLimitation>& depthFpsLimits,
+ const Size& minStreamSize, bool depthEnabled) {
+ std::vector<SupportedV4L2Format> outFmts;
+ struct v4l2_fmtdesc fmtdesc {
+ .index = 0, .type = V4L2_BUF_TYPE_VIDEO_CAPTURE
+ };
+ int ret = 0;
+ while (ret == 0) {
+ ret = TEMP_FAILURE_RETRY(ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc));
+ ALOGV("index:%d,ret:%d, format:%c%c%c%c", fmtdesc.index, ret, fmtdesc.pixelformat & 0xFF,
+ (fmtdesc.pixelformat >> 8) & 0xFF, (fmtdesc.pixelformat >> 16) & 0xFF,
+ (fmtdesc.pixelformat >> 24) & 0xFF);
+
+ if (ret != 0 || (fmtdesc.flags & V4L2_FMT_FLAG_EMULATED)) {
+ // Skip if IOCTL failed, or if the format is emulated
+ fmtdesc.index++;
+ continue;
+ }
+ auto it =
+ std::find(kSupportedFourCCs.begin(), kSupportedFourCCs.end(), fmtdesc.pixelformat);
+ if (it == kSupportedFourCCs.end()) {
+ fmtdesc.index++;
+ continue;
+ }
+
+ // Found supported format
+ v4l2_frmsizeenum frameSize{.index = 0, .pixel_format = fmtdesc.pixelformat};
+ for (; TEMP_FAILURE_RETRY(ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frameSize)) == 0;
+ ++frameSize.index) {
+ if (frameSize.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
+ ALOGV("index:%d, format:%c%c%c%c, w %d, h %d", frameSize.index,
+ fmtdesc.pixelformat & 0xFF, (fmtdesc.pixelformat >> 8) & 0xFF,
+ (fmtdesc.pixelformat >> 16) & 0xFF, (fmtdesc.pixelformat >> 24) & 0xFF,
+ frameSize.discrete.width, frameSize.discrete.height);
+
+ // Disregard h > w formats so all aspect ratio (h/w) <= 1.0
+ // This will simplify the crop/scaling logic down the road
+ if (frameSize.discrete.height > frameSize.discrete.width) {
+ continue;
+ }
+
+ // Discard all formats which is smaller than minStreamSize
+ if (frameSize.discrete.width < minStreamSize.width ||
+ frameSize.discrete.height < minStreamSize.height) {
+ continue;
+ }
+
+ SupportedV4L2Format format{
+ .width = static_cast<int32_t>(frameSize.discrete.width),
+ .height = static_cast<int32_t>(frameSize.discrete.height),
+ .fourcc = fmtdesc.pixelformat};
+
+ if (format.fourcc == V4L2_PIX_FMT_Z16 && depthEnabled) {
+ updateFpsBounds(fd, cropType, depthFpsLimits, format, outFmts);
+ } else {
+ updateFpsBounds(fd, cropType, fpsLimits, format, outFmts);
+ }
+ }
+ }
+ fmtdesc.index++;
+ }
+ trimSupportedFormats(cropType, &outFmts);
+ return outFmts;
+}
+
+void ExternalCameraDevice::trimSupportedFormats(CroppingType cropType,
+ std::vector<SupportedV4L2Format>* pFmts) {
+ std::vector<SupportedV4L2Format>& sortedFmts = *pFmts;
+ if (cropType == VERTICAL) {
+ std::sort(sortedFmts.begin(), sortedFmts.end(),
+ [](const SupportedV4L2Format& a, const SupportedV4L2Format& b) -> bool {
+ if (a.width == b.width) {
+ return a.height < b.height;
+ }
+ return a.width < b.width;
+ });
+ } else {
+ std::sort(sortedFmts.begin(), sortedFmts.end(),
+ [](const SupportedV4L2Format& a, const SupportedV4L2Format& b) -> bool {
+ if (a.height == b.height) {
+ return a.width < b.width;
+ }
+ return a.height < b.height;
+ });
+ }
+
+ if (sortedFmts.empty()) {
+ ALOGE("%s: input format list is empty!", __FUNCTION__);
+ return;
+ }
+
+ const auto& maxSize = sortedFmts[sortedFmts.size() - 1];
+ float maxSizeAr = ASPECT_RATIO(maxSize);
+
+ // Remove formats that has aspect ratio not croppable from largest size
+ std::vector<SupportedV4L2Format> out;
+ for (const auto& fmt : sortedFmts) {
+ float ar = ASPECT_RATIO(fmt);
+ if (isAspectRatioClose(ar, maxSizeAr)) {
+ out.push_back(fmt);
+ } else if (cropType == HORIZONTAL && ar < maxSizeAr) {
+ out.push_back(fmt);
+ } else if (cropType == VERTICAL && ar > maxSizeAr) {
+ out.push_back(fmt);
+ } else {
+ ALOGV("%s: size (%d,%d) is removed due to unable to crop %s from (%d,%d)", __FUNCTION__,
+ fmt.width, fmt.height, cropType == VERTICAL ? "vertically" : "horizontally",
+ maxSize.width, maxSize.height);
+ }
+ }
+ sortedFmts = out;
+}
+
+binder_status_t ExternalCameraDevice::dump(int fd, const char** args, uint32_t numArgs) {
+ std::shared_ptr<ExternalCameraDeviceSession> session = mSession.lock();
+ if (session == nullptr) {
+ dprintf(fd, "No active camera device session instance\n");
+ return STATUS_OK;
+ }
+
+ return session->dump(fd, args, numArgs);
+}
+
+} // namespace implementation
+} // namespace device
+} // namespace camera
+} // namespace hardware
+} // namespace android
\ No newline at end of file
diff --git a/camera/device/default/ExternalCameraDevice.h b/camera/device/default/ExternalCameraDevice.h
new file mode 100644
index 0000000..bcae194
--- /dev/null
+++ b/camera/device/default/ExternalCameraDevice.h
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HARDWARE_INTERFACES_CAMERA_DEVICE_DEFAULT_EXTERNALCAMERADEVICE_H_
+#define HARDWARE_INTERFACES_CAMERA_DEVICE_DEFAULT_EXTERNALCAMERADEVICE_H_
+
+#include <ExternalCameraDeviceSession.h>
+#include <ExternalCameraUtils.h>
+#include <aidl/android/hardware/camera/device/BnCameraDevice.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace implementation {
+
+using ::aidl::android::hardware::camera::common::CameraResourceCost;
+using ::aidl::android::hardware::camera::device::BnCameraDevice;
+using ::aidl::android::hardware::camera::device::CameraMetadata;
+using ::aidl::android::hardware::camera::device::ICameraDeviceCallback;
+using ::aidl::android::hardware::camera::device::ICameraDeviceSession;
+using ::aidl::android::hardware::camera::device::ICameraInjectionSession;
+using ::aidl::android::hardware::camera::device::StreamConfiguration;
+using ::android::hardware::camera::external::common::ExternalCameraConfig;
+
+class ExternalCameraDevice : public BnCameraDevice {
+ public:
+ // Called by external camera provider HAL.
+ // Provider HAL must ensure the uniqueness of CameraDevice object per cameraId, or there could
+ // be multiple CameraDevice trying to access the same physical camera. Also, provider will have
+ // to keep track of all CameraDevice objects in order to notify CameraDevice when the underlying
+ // camera is detached.
+ ExternalCameraDevice(const std::string& devicePath, const ExternalCameraConfig& config);
+ ~ExternalCameraDevice() override;
+
+ ndk::ScopedAStatus getCameraCharacteristics(CameraMetadata* _aidl_return) override;
+ ndk::ScopedAStatus getPhysicalCameraCharacteristics(const std::string& in_physicalCameraId,
+ CameraMetadata* _aidl_return) override;
+ ndk::ScopedAStatus getResourceCost(CameraResourceCost* _aidl_return) override;
+ ndk::ScopedAStatus isStreamCombinationSupported(const StreamConfiguration& in_streams,
+ bool* _aidl_return) override;
+ ndk::ScopedAStatus open(const std::shared_ptr<ICameraDeviceCallback>& in_callback,
+ std::shared_ptr<ICameraDeviceSession>* _aidl_return) override;
+ ndk::ScopedAStatus openInjectionSession(
+ const std::shared_ptr<ICameraDeviceCallback>& in_callback,
+ std::shared_ptr<ICameraInjectionSession>* _aidl_return) override;
+ ndk::ScopedAStatus setTorchMode(bool in_on) override;
+ ndk::ScopedAStatus turnOnTorchWithStrengthLevel(int32_t in_torchStrength) override;
+ ndk::ScopedAStatus getTorchStrengthLevel(int32_t* _aidl_return) override;
+
+ binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
+
+ // Caller must use this method to check if CameraDevice ctor failed
+ bool isInitFailed();
+
+ // Device version to be used by the external camera provider.
+ // Should be of the form <major>.<minor>
+ static std::string kDeviceVersion;
+
+ private:
+ virtual std::shared_ptr<ExternalCameraDeviceSession> createSession(
+ const std::shared_ptr<ICameraDeviceCallback>&, const ExternalCameraConfig& cfg,
+ const std::vector<SupportedV4L2Format>& sortedFormats, const CroppingType& croppingType,
+ const common::V1_0::helper::CameraMetadata& chars, const std::string& cameraId,
+ unique_fd v4l2Fd);
+
+ bool isInitFailedLocked();
+
+ // Init supported w/h/format/fps in mSupportedFormats. Caller still owns fd
+ void initSupportedFormatsLocked(int fd);
+
+ // Calls into virtual member function. Do not use it in constructor
+ status_t initCameraCharacteristics();
+ // Init available capabilities keys
+ virtual status_t initAvailableCapabilities(
+ ::android::hardware::camera::common::V1_0::helper::CameraMetadata*);
+ // Init non-device dependent keys
+ virtual status_t initDefaultCharsKeys(
+ ::android::hardware::camera::common::V1_0::helper::CameraMetadata*);
+ // Init camera control chars keys. Caller still owns fd
+ status_t initCameraControlsCharsKeys(
+ int fd, ::android::hardware::camera::common::V1_0::helper::CameraMetadata*);
+ // Init camera output configuration related keys. Caller still owns fd
+ status_t initOutputCharsKeys(
+ int fd, ::android::hardware::camera::common::V1_0::helper::CameraMetadata*);
+
+ // Helper function for initOutputCharskeys
+ template <size_t SIZE>
+ status_t initOutputCharsKeysByFormat(
+ ::android::hardware::camera::common::V1_0::helper::CameraMetadata* metadata,
+ uint32_t fourcc, const std::array<int, SIZE>& halFormats, int streamConfigTag,
+ int streamConfiguration, int minFrameDuration, int stallDuration);
+
+ status_t calculateMinFps(::android::hardware::camera::common::V1_0::helper::CameraMetadata*);
+
+ static void getFrameRateList(int fd, double fpsUpperBound, SupportedV4L2Format* format);
+
+ static void updateFpsBounds(int fd, CroppingType cropType,
+ const std::vector<ExternalCameraConfig::FpsLimitation>& fpsLimits,
+ SupportedV4L2Format format,
+ std::vector<SupportedV4L2Format>& outFmts);
+
+ // Get candidate supported formats list of input cropping type.
+ static std::vector<SupportedV4L2Format> getCandidateSupportedFormatsLocked(
+ int fd, CroppingType cropType,
+ const std::vector<ExternalCameraConfig::FpsLimitation>& fpsLimits,
+ const std::vector<ExternalCameraConfig::FpsLimitation>& depthFpsLimits,
+ const Size& minStreamSize, bool depthEnabled);
+ // Trim supported format list by the cropping type. Also sort output formats by width/height
+ static void trimSupportedFormats(CroppingType cropType,
+ /*inout*/ std::vector<SupportedV4L2Format>* pFmts);
+
+ Mutex mLock;
+ bool mInitialized = false;
+ bool mInitFailed = false;
+ std::string mCameraId;
+ std::string mDevicePath;
+ const ExternalCameraConfig& mCfg;
+ std::vector<SupportedV4L2Format> mSupportedFormats;
+ CroppingType mCroppingType;
+
+ std::weak_ptr<ExternalCameraDeviceSession> mSession =
+ std::weak_ptr<ExternalCameraDeviceSession>();
+
+ ::android::hardware::camera::common::V1_0::helper::CameraMetadata mCameraCharacteristics;
+
+ const std::vector<int32_t> AVAILABLE_CHARACTERISTICS_KEYS = {
+ ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,
+ ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,
+ ANDROID_CONTROL_AE_AVAILABLE_MODES,
+ ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,
+ ANDROID_CONTROL_AE_COMPENSATION_RANGE,
+ ANDROID_CONTROL_AE_COMPENSATION_STEP,
+ ANDROID_CONTROL_AE_LOCK_AVAILABLE,
+ ANDROID_CONTROL_AF_AVAILABLE_MODES,
+ ANDROID_CONTROL_AVAILABLE_EFFECTS,
+ ANDROID_CONTROL_AVAILABLE_MODES,
+ ANDROID_CONTROL_AVAILABLE_SCENE_MODES,
+ ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,
+ ANDROID_CONTROL_AWB_AVAILABLE_MODES,
+ ANDROID_CONTROL_AWB_LOCK_AVAILABLE,
+ ANDROID_CONTROL_MAX_REGIONS,
+ ANDROID_FLASH_INFO_AVAILABLE,
+ ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL,
+ ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,
+ ANDROID_LENS_FACING,
+ ANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,
+ ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION,
+ ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,
+ ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
+ ANDROID_REQUEST_MAX_NUM_INPUT_STREAMS,
+ ANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS,
+ ANDROID_REQUEST_PARTIAL_RESULT_COUNT,
+ ANDROID_REQUEST_PIPELINE_MAX_DEPTH,
+ ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+ ANDROID_SCALER_CROPPING_TYPE,
+ ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,
+ ANDROID_SENSOR_INFO_MAX_FRAME_DURATION,
+ ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,
+ ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE,
+ ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE,
+ ANDROID_SENSOR_ORIENTATION,
+ ANDROID_SHADING_AVAILABLE_MODES,
+ ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES,
+ ANDROID_STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES,
+ ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES,
+ ANDROID_STATISTICS_INFO_MAX_FACE_COUNT,
+ ANDROID_SYNC_MAX_LATENCY};
+};
+
+} // namespace implementation
+} // namespace device
+} // namespace camera
+} // namespace hardware
+} // namespace android
+
+#endif // HARDWARE_INTERFACES_CAMERA_DEVICE_DEFAULT_EXTERNALCAMERADEVICE_H_
diff --git a/camera/device/default/ExternalCameraDeviceSession.cpp b/camera/device/default/ExternalCameraDeviceSession.cpp
new file mode 100644
index 0000000..736bc3c
--- /dev/null
+++ b/camera/device/default/ExternalCameraDeviceSession.cpp
@@ -0,0 +1,2947 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "ExtCamDevSsn"
+// #define LOG_NDEBUG 0
+#include <log/log.h>
+
+#include "ExternalCameraDeviceSession.h"
+
+#include <Exif.h>
+#include <ExternalCameraOfflineSession.h>
+#include <aidl/android/hardware/camera/device/CameraBlob.h>
+#include <aidl/android/hardware/camera/device/CameraBlobId.h>
+#include <aidl/android/hardware/camera/device/ErrorMsg.h>
+#include <aidl/android/hardware/camera/device/ShutterMsg.h>
+#include <aidl/android/hardware/camera/device/StreamBufferRet.h>
+#include <aidl/android/hardware/camera/device/StreamBuffersVal.h>
+#include <aidl/android/hardware/camera/device/StreamConfigurationMode.h>
+#include <aidl/android/hardware/camera/device/StreamRotation.h>
+#include <aidl/android/hardware/camera/device/StreamType.h>
+#include <aidl/android/hardware/graphics/common/Dataspace.h>
+#include <aidlcommonsupport/NativeHandle.h>
+#include <convert.h>
+#include <linux/videodev2.h>
+#include <sync/sync.h>
+#include <utils/Trace.h>
+#include <deque>
+
+#define HAVE_JPEG // required for libyuv.h to export MJPEG decode APIs
+#include <libyuv.h>
+#include <libyuv/convert.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace implementation {
+
+namespace {
+
+// Size of request/result metadata fast message queue. Change to 0 to always use hwbinder buffer.
+static constexpr size_t kMetadataMsgQueueSize = 1 << 18 /* 256kB */;
+
+const int kBadFramesAfterStreamOn = 1; // drop x frames after streamOn to get rid of some initial
+ // bad frames. TODO: develop a better bad frame detection
+ // method
+constexpr int MAX_RETRY = 15; // Allow retry some ioctl failures a few times to account for some
+ // webcam showing temporarily ioctl failures.
+constexpr int IOCTL_RETRY_SLEEP_US = 33000; // 33ms * MAX_RETRY = 0.5 seconds
+
+// Constants for tryLock during dumpstate
+static constexpr int kDumpLockRetries = 50;
+static constexpr int kDumpLockSleep = 60000;
+
+bool tryLock(Mutex& mutex) {
+ bool locked = false;
+ for (int i = 0; i < kDumpLockRetries; ++i) {
+ if (mutex.tryLock() == NO_ERROR) {
+ locked = true;
+ break;
+ }
+ usleep(kDumpLockSleep);
+ }
+ return locked;
+}
+
+bool tryLock(std::mutex& mutex) {
+ bool locked = false;
+ for (int i = 0; i < kDumpLockRetries; ++i) {
+ if (mutex.try_lock()) {
+ locked = true;
+ break;
+ }
+ usleep(kDumpLockSleep);
+ }
+ return locked;
+}
+
+} // anonymous namespace
+
+using ::aidl::android::hardware::camera::device::BufferRequestStatus;
+using ::aidl::android::hardware::camera::device::CameraBlob;
+using ::aidl::android::hardware::camera::device::CameraBlobId;
+using ::aidl::android::hardware::camera::device::ErrorMsg;
+using ::aidl::android::hardware::camera::device::ShutterMsg;
+using ::aidl::android::hardware::camera::device::StreamBuffer;
+using ::aidl::android::hardware::camera::device::StreamBufferRet;
+using ::aidl::android::hardware::camera::device::StreamBuffersVal;
+using ::aidl::android::hardware::camera::device::StreamConfigurationMode;
+using ::aidl::android::hardware::camera::device::StreamRotation;
+using ::aidl::android::hardware::camera::device::StreamType;
+using ::aidl::android::hardware::graphics::common::Dataspace;
+using ::android::hardware::camera::common::V1_0::helper::ExifUtils;
+
+// Static instances
+const int ExternalCameraDeviceSession::kMaxProcessedStream;
+const int ExternalCameraDeviceSession::kMaxStallStream;
+HandleImporter ExternalCameraDeviceSession::sHandleImporter;
+
+ExternalCameraDeviceSession::ExternalCameraDeviceSession(
+ const std::shared_ptr<ICameraDeviceCallback>& callback, const ExternalCameraConfig& cfg,
+ const std::vector<SupportedV4L2Format>& sortedFormats, const CroppingType& croppingType,
+ const common::V1_0::helper::CameraMetadata& chars, const std::string& cameraId,
+ unique_fd v4l2Fd)
+ : mCallback(callback),
+ mCfg(cfg),
+ mCameraCharacteristics(chars),
+ mSupportedFormats(sortedFormats),
+ mCroppingType(croppingType),
+ mCameraId(cameraId),
+ mV4l2Fd(std::move(v4l2Fd)),
+ mMaxThumbResolution(getMaxThumbResolution()),
+ mMaxJpegResolution(getMaxJpegResolution()) {}
+
+Size ExternalCameraDeviceSession::getMaxThumbResolution() const {
+ return getMaxThumbnailResolution(mCameraCharacteristics);
+}
+
+Size ExternalCameraDeviceSession::getMaxJpegResolution() const {
+ Size ret{0, 0};
+ for (auto& fmt : mSupportedFormats) {
+ if (fmt.width * fmt.height > ret.width * ret.height) {
+ ret = Size{fmt.width, fmt.height};
+ }
+ }
+ return ret;
+}
+
+bool ExternalCameraDeviceSession::initialize() {
+ if (mV4l2Fd.get() < 0) {
+ ALOGE("%s: invalid v4l2 device fd %d!", __FUNCTION__, mV4l2Fd.get());
+ return true;
+ }
+
+ struct v4l2_capability capability;
+ int ret = ioctl(mV4l2Fd.get(), VIDIOC_QUERYCAP, &capability);
+ std::string make, model;
+ if (ret < 0) {
+ ALOGW("%s v4l2 QUERYCAP failed", __FUNCTION__);
+ mExifMake = "Generic UVC webcam";
+ mExifModel = "Generic UVC webcam";
+ } else {
+ // capability.card is UTF-8 encoded
+ char card[32];
+ int j = 0;
+ for (int i = 0; i < 32; i++) {
+ if (capability.card[i] < 128) {
+ card[j++] = capability.card[i];
+ }
+ if (capability.card[i] == '\0') {
+ break;
+ }
+ }
+ if (j == 0 || card[j - 1] != '\0') {
+ mExifMake = "Generic UVC webcam";
+ mExifModel = "Generic UVC webcam";
+ } else {
+ mExifMake = card;
+ mExifModel = card;
+ }
+ }
+
+ initOutputThread();
+ if (mOutputThread == nullptr) {
+ ALOGE("%s: init OutputThread failed!", __FUNCTION__);
+ return true;
+ }
+ mOutputThread->setExifMakeModel(mExifMake, mExifModel);
+
+ status_t status = initDefaultRequests();
+ if (status != OK) {
+ ALOGE("%s: init default requests failed!", __FUNCTION__);
+ return true;
+ }
+
+ mRequestMetadataQueue =
+ std::make_unique<RequestMetadataQueue>(kMetadataMsgQueueSize, false /* non blocking */);
+ if (!mRequestMetadataQueue->isValid()) {
+ ALOGE("%s: invalid request fmq", __FUNCTION__);
+ return true;
+ }
+
+ mResultMetadataQueue =
+ std::make_shared<ResultMetadataQueue>(kMetadataMsgQueueSize, false /* non blocking */);
+ if (!mResultMetadataQueue->isValid()) {
+ ALOGE("%s: invalid result fmq", __FUNCTION__);
+ return true;
+ }
+
+ mOutputThread->run();
+ return false;
+}
+
+bool ExternalCameraDeviceSession::isInitFailed() {
+ Mutex::Autolock _l(mLock);
+ if (!mInitialized) {
+ mInitFail = initialize();
+ mInitialized = true;
+ }
+ return mInitFail;
+}
+
+void ExternalCameraDeviceSession::initOutputThread() {
+ // Grab a shared_ptr to 'this' from ndk::SharedRefBase::ref()
+ std::shared_ptr<ExternalCameraDeviceSession> thiz = ref<ExternalCameraDeviceSession>();
+
+ if (mSupportBufMgr) {
+ mBufferRequestThread = std::make_shared<BufferRequestThread>(/*parent=*/thiz, mCallback);
+ mBufferRequestThread->run();
+ }
+ mOutputThread = std::make_shared<OutputThread>(/*parent=*/thiz, mCroppingType,
+ mCameraCharacteristics, mBufferRequestThread);
+}
+
+void ExternalCameraDeviceSession::closeOutputThread() {
+ closeOutputThreadImpl();
+}
+
+void ExternalCameraDeviceSession::closeOutputThreadImpl() {
+ if (mOutputThread != nullptr) {
+ mOutputThread->flush();
+ mOutputThread->requestExitAndWait();
+ mOutputThread.reset();
+ }
+}
+
+Status ExternalCameraDeviceSession::initStatus() const {
+ Mutex::Autolock _l(mLock);
+ Status status = Status::OK;
+ if (mInitFail || mClosed) {
+ ALOGI("%s: session initFailed %d closed %d", __FUNCTION__, mInitFail, mClosed);
+ status = Status::INTERNAL_ERROR;
+ }
+ return status;
+}
+
+ExternalCameraDeviceSession::~ExternalCameraDeviceSession() {
+ if (!isClosed()) {
+ ALOGE("ExternalCameraDeviceSession deleted before close!");
+ close(/*callerIsDtor*/ true);
+ }
+}
+
+ScopedAStatus ExternalCameraDeviceSession::constructDefaultRequestSettings(
+ RequestTemplate in_type, CameraMetadata* _aidl_return) {
+ CameraMetadata emptyMetadata;
+ Status status = initStatus();
+ if (status != Status::OK) {
+ return fromStatus(status);
+ }
+ switch (in_type) {
+ case RequestTemplate::PREVIEW:
+ case RequestTemplate::STILL_CAPTURE:
+ case RequestTemplate::VIDEO_RECORD:
+ case RequestTemplate::VIDEO_SNAPSHOT: {
+ *_aidl_return = mDefaultRequests[in_type];
+ break;
+ }
+ case RequestTemplate::MANUAL:
+ case RequestTemplate::ZERO_SHUTTER_LAG:
+ // Don't support MANUAL, ZSL templates
+ status = Status::ILLEGAL_ARGUMENT;
+ break;
+ default:
+ ALOGE("%s: unknown request template type %d", __FUNCTION__, static_cast<int>(in_type));
+ status = Status::ILLEGAL_ARGUMENT;
+ break;
+ }
+ return fromStatus(status);
+}
+
+ScopedAStatus ExternalCameraDeviceSession::configureStreams(
+ const StreamConfiguration& in_requestedConfiguration,
+ std::vector<HalStream>* _aidl_return) {
+ uint32_t blobBufferSize = 0;
+ _aidl_return->clear();
+ Mutex::Autolock _il(mInterfaceLock);
+
+ Status status =
+ isStreamCombinationSupported(in_requestedConfiguration, mSupportedFormats, mCfg);
+ if (status != Status::OK) {
+ return fromStatus(status);
+ }
+
+ status = initStatus();
+ if (status != Status::OK) {
+ return fromStatus(status);
+ }
+
+ {
+ std::lock_guard<std::mutex> lk(mInflightFramesLock);
+ if (!mInflightFrames.empty()) {
+ ALOGE("%s: trying to configureStreams while there are still %zu inflight frames!",
+ __FUNCTION__, mInflightFrames.size());
+ return fromStatus(Status::INTERNAL_ERROR);
+ }
+ }
+
+ Mutex::Autolock _l(mLock);
+ {
+ Mutex::Autolock _cl(mCbsLock);
+ // Add new streams
+ for (const auto& stream : in_requestedConfiguration.streams) {
+ if (mStreamMap.count(stream.id) == 0) {
+ mStreamMap[stream.id] = stream;
+ mCirculatingBuffers.emplace(stream.id, CirculatingBuffers{});
+ }
+ }
+
+ // Cleanup removed streams
+ for (auto it = mStreamMap.begin(); it != mStreamMap.end();) {
+ int id = it->first;
+ bool found = false;
+ for (const auto& stream : in_requestedConfiguration.streams) {
+ if (id == stream.id) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ // Unmap all buffers of deleted stream
+ cleanupBuffersLocked(id);
+ it = mStreamMap.erase(it);
+ } else {
+ ++it;
+ }
+ }
+ }
+
+ // Now select a V4L2 format to produce all output streams
+ float desiredAr = (mCroppingType == VERTICAL) ? kMaxAspectRatio : kMinAspectRatio;
+ uint32_t maxDim = 0;
+ for (const auto& stream : in_requestedConfiguration.streams) {
+ float aspectRatio = ASPECT_RATIO(stream);
+ ALOGI("%s: request stream %dx%d", __FUNCTION__, stream.width, stream.height);
+ if ((mCroppingType == VERTICAL && aspectRatio < desiredAr) ||
+ (mCroppingType == HORIZONTAL && aspectRatio > desiredAr)) {
+ desiredAr = aspectRatio;
+ }
+
+ // The dimension that's not cropped
+ uint32_t dim = (mCroppingType == VERTICAL) ? stream.width : stream.height;
+ if (dim > maxDim) {
+ maxDim = dim;
+ }
+ }
+
+ // Find the smallest format that matches the desired aspect ratio and is wide/high enough
+ SupportedV4L2Format v4l2Fmt{.width = 0, .height = 0};
+ for (const auto& fmt : mSupportedFormats) {
+ uint32_t dim = (mCroppingType == VERTICAL) ? fmt.width : fmt.height;
+ if (dim >= maxDim) {
+ float aspectRatio = ASPECT_RATIO(fmt);
+ if (isAspectRatioClose(aspectRatio, desiredAr)) {
+ v4l2Fmt = fmt;
+ // since mSupportedFormats is sorted by width then height, the first matching fmt
+ // will be the smallest one with matching aspect ratio
+ break;
+ }
+ }
+ }
+
+ if (v4l2Fmt.width == 0) {
+ // Cannot find exact good aspect ratio candidate, try to find a close one
+ for (const auto& fmt : mSupportedFormats) {
+ uint32_t dim = (mCroppingType == VERTICAL) ? fmt.width : fmt.height;
+ if (dim >= maxDim) {
+ float aspectRatio = ASPECT_RATIO(fmt);
+ if ((mCroppingType == VERTICAL && aspectRatio < desiredAr) ||
+ (mCroppingType == HORIZONTAL && aspectRatio > desiredAr)) {
+ v4l2Fmt = fmt;
+ break;
+ }
+ }
+ }
+ }
+
+ if (v4l2Fmt.width == 0) {
+ ALOGE("%s: unable to find a resolution matching (%s at least %d, aspect ratio %f)",
+ __FUNCTION__, (mCroppingType == VERTICAL) ? "width" : "height", maxDim, desiredAr);
+ return fromStatus(Status::ILLEGAL_ARGUMENT);
+ }
+
+ if (configureV4l2StreamLocked(v4l2Fmt) != 0) {
+ ALOGE("V4L configuration failed!, format:%c%c%c%c, w %d, h %d", v4l2Fmt.fourcc & 0xFF,
+ (v4l2Fmt.fourcc >> 8) & 0xFF, (v4l2Fmt.fourcc >> 16) & 0xFF,
+ (v4l2Fmt.fourcc >> 24) & 0xFF, v4l2Fmt.width, v4l2Fmt.height);
+ return fromStatus(Status::INTERNAL_ERROR);
+ }
+
+ Size v4lSize = {v4l2Fmt.width, v4l2Fmt.height};
+ Size thumbSize{0, 0};
+ camera_metadata_ro_entry entry =
+ mCameraCharacteristics.find(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES);
+ for (uint32_t i = 0; i < entry.count; i += 2) {
+ Size sz{entry.data.i32[i], entry.data.i32[i + 1]};
+ if (sz.width * sz.height > thumbSize.width * thumbSize.height) {
+ thumbSize = sz;
+ }
+ }
+
+ if (thumbSize.width * thumbSize.height == 0) {
+ ALOGE("%s: non-zero thumbnail size not available", __FUNCTION__);
+ return fromStatus(Status::INTERNAL_ERROR);
+ }
+
+ mBlobBufferSize = blobBufferSize;
+ status = mOutputThread->allocateIntermediateBuffers(
+ v4lSize, mMaxThumbResolution, in_requestedConfiguration.streams, blobBufferSize);
+ if (status != Status::OK) {
+ ALOGE("%s: allocating intermediate buffers failed!", __FUNCTION__);
+ return fromStatus(status);
+ }
+
+ std::vector<HalStream>& out = *_aidl_return;
+ out.resize(in_requestedConfiguration.streams.size());
+ for (size_t i = 0; i < in_requestedConfiguration.streams.size(); i++) {
+ out[i].overrideDataSpace = in_requestedConfiguration.streams[i].dataSpace;
+ out[i].id = in_requestedConfiguration.streams[i].id;
+ // TODO: double check should we add those CAMERA flags
+ mStreamMap[in_requestedConfiguration.streams[i].id].usage = out[i].producerUsage =
+ static_cast<BufferUsage>(((int64_t)in_requestedConfiguration.streams[i].usage) |
+ ((int64_t)BufferUsage::CPU_WRITE_OFTEN) |
+ ((int64_t)BufferUsage::CAMERA_OUTPUT));
+ out[i].consumerUsage = static_cast<BufferUsage>(0);
+ out[i].maxBuffers = static_cast<int32_t>(mV4L2BufferCount);
+
+ switch (in_requestedConfiguration.streams[i].format) {
+ case PixelFormat::BLOB:
+ case PixelFormat::YCBCR_420_888:
+ case PixelFormat::YV12: // Used by SurfaceTexture
+ case PixelFormat::Y16:
+ // No override
+ out[i].overrideFormat = in_requestedConfiguration.streams[i].format;
+ break;
+ case PixelFormat::IMPLEMENTATION_DEFINED:
+ // Implementation Defined
+ // This should look at the Stream's dataspace flag to determine the format or leave
+ // it as is if the rest of the system knows how to handle a private format. To keep
+ // this HAL generic, this is being overridden to YUV420
+ out[i].overrideFormat = PixelFormat::YCBCR_420_888;
+ // Save overridden format in mStreamMap
+ mStreamMap[in_requestedConfiguration.streams[i].id].format = out[i].overrideFormat;
+ break;
+ default:
+ ALOGE("%s: unsupported format 0x%x", __FUNCTION__,
+ in_requestedConfiguration.streams[i].format);
+ return fromStatus(Status::ILLEGAL_ARGUMENT);
+ }
+ }
+
+ mFirstRequest = true;
+ mLastStreamConfigCounter = in_requestedConfiguration.streamConfigCounter;
+ return fromStatus(Status::OK);
+}
+
+ScopedAStatus ExternalCameraDeviceSession::flush() {
+ ATRACE_CALL();
+ Mutex::Autolock _il(mInterfaceLock);
+ Status status = initStatus();
+ if (status != Status::OK) {
+ return fromStatus(status);
+ }
+ mOutputThread->flush();
+ return fromStatus(Status::OK);
+}
+
+ScopedAStatus ExternalCameraDeviceSession::getCaptureRequestMetadataQueue(
+ MQDescriptor<int8_t, SynchronizedReadWrite>* _aidl_return) {
+ Mutex::Autolock _il(mInterfaceLock);
+ *_aidl_return = mRequestMetadataQueue->dupeDesc();
+ return fromStatus(Status::OK);
+}
+
+ScopedAStatus ExternalCameraDeviceSession::getCaptureResultMetadataQueue(
+ MQDescriptor<int8_t, SynchronizedReadWrite>* _aidl_return) {
+ Mutex::Autolock _il(mInterfaceLock);
+ *_aidl_return = mResultMetadataQueue->dupeDesc();
+ return fromStatus(Status::OK);
+}
+
+ScopedAStatus ExternalCameraDeviceSession::isReconfigurationRequired(
+ const CameraMetadata& in_oldSessionParams, const CameraMetadata& in_newSessionParams,
+ bool* _aidl_return) {
+ // reconfiguration required if there is any change in the session params
+ *_aidl_return = in_oldSessionParams != in_newSessionParams;
+ return fromStatus(Status::OK);
+}
+
+ScopedAStatus ExternalCameraDeviceSession::processCaptureRequest(
+ const std::vector<CaptureRequest>& in_requests,
+ const std::vector<BufferCache>& in_cachesToRemove, int32_t* _aidl_return) {
+ Mutex::Autolock _il(mInterfaceLock);
+ updateBufferCaches(in_cachesToRemove);
+
+ int32_t& numRequestProcessed = *_aidl_return;
+ numRequestProcessed = 0;
+ Status s = Status::OK;
+ for (size_t i = 0; i < in_requests.size(); i++, numRequestProcessed++) {
+ s = processOneCaptureRequest(in_requests[i]);
+ if (s != Status::OK) {
+ break;
+ }
+ }
+
+ return fromStatus(s);
+}
+
+Status ExternalCameraDeviceSession::processOneCaptureRequest(const CaptureRequest& request) {
+ ATRACE_CALL();
+ Status status = initStatus();
+ if (status != Status::OK) {
+ return status;
+ }
+
+ if (request.inputBuffer.streamId != -1) {
+ ALOGE("%s: external camera does not support reprocessing!", __FUNCTION__);
+ return Status::ILLEGAL_ARGUMENT;
+ }
+
+ Mutex::Autolock _l(mLock);
+ if (!mV4l2Streaming) {
+ ALOGE("%s: cannot process request in streamOff state!", __FUNCTION__);
+ return Status::INTERNAL_ERROR;
+ }
+
+ const camera_metadata_t* rawSettings = nullptr;
+ bool converted;
+ CameraMetadata settingsFmq; // settings from FMQ
+
+ if (request.fmqSettingsSize > 0) {
+ // non-blocking read; client must write metadata before calling
+ // processOneCaptureRequest
+ settingsFmq.metadata.resize(request.fmqSettingsSize);
+ bool read = mRequestMetadataQueue->read(
+ reinterpret_cast<int8_t*>(settingsFmq.metadata.data()), request.fmqSettingsSize);
+ if (read) {
+ converted = convertFromAidl(settingsFmq, &rawSettings);
+ } else {
+ ALOGE("%s: capture request settings metadata couldn't be read from fmq!", __FUNCTION__);
+ converted = false;
+ }
+ } else {
+ converted = convertFromAidl(request.settings, &rawSettings);
+ }
+
+ if (converted && rawSettings != nullptr) {
+ mLatestReqSetting = rawSettings;
+ }
+
+ if (!converted) {
+ ALOGE("%s: capture request settings metadata is corrupt!", __FUNCTION__);
+ return Status::ILLEGAL_ARGUMENT;
+ }
+
+ if (mFirstRequest && rawSettings == nullptr) {
+ ALOGE("%s: capture request settings must not be null for first request!", __FUNCTION__);
+ return Status::ILLEGAL_ARGUMENT;
+ }
+
+ std::vector<buffer_handle_t*> allBufPtrs;
+ std::vector<int> allFences;
+ size_t numOutputBufs = request.outputBuffers.size();
+
+ if (numOutputBufs == 0) {
+ ALOGE("%s: capture request must have at least one output buffer!", __FUNCTION__);
+ return Status::ILLEGAL_ARGUMENT;
+ }
+
+ camera_metadata_entry fpsRange = mLatestReqSetting.find(ANDROID_CONTROL_AE_TARGET_FPS_RANGE);
+ if (fpsRange.count == 2) {
+ double requestFpsMax = fpsRange.data.i32[1];
+ double closestFps = 0.0;
+ double fpsError = 1000.0;
+ bool fpsSupported = false;
+ for (const auto& fr : mV4l2StreamingFmt.frameRates) {
+ double f = fr.getFramesPerSecond();
+ if (std::fabs(requestFpsMax - f) < 1.0) {
+ fpsSupported = true;
+ break;
+ }
+ if (std::fabs(requestFpsMax - f) < fpsError) {
+ fpsError = std::fabs(requestFpsMax - f);
+ closestFps = f;
+ }
+ }
+ if (!fpsSupported) {
+ /* This can happen in a few scenarios:
+ * 1. The application is sending an FPS range not supported by the configured outputs.
+ * 2. The application is sending a valid FPS range for all configured outputs, but
+ * the selected V4L2 size can only run at slower speed. This should be very rare
+ * though: for this to happen a sensor needs to support at least 3 different aspect
+ * ratio outputs, and when (at least) two outputs are both not the main aspect ratio
+ * of the webcam, a third size that's larger might be picked and runs into this
+ * issue.
+ */
+ ALOGW("%s: cannot reach fps %d! Will do %f instead", __FUNCTION__, fpsRange.data.i32[1],
+ closestFps);
+ requestFpsMax = closestFps;
+ }
+
+ if (requestFpsMax != mV4l2StreamingFps) {
+ {
+ std::unique_lock<std::mutex> lk(mV4l2BufferLock);
+ while (mNumDequeuedV4l2Buffers != 0) {
+ // Wait until pipeline is idle before reconfigure stream
+ int waitRet = waitForV4L2BufferReturnLocked(lk);
+ if (waitRet != 0) {
+ ALOGE("%s: wait for pipeline idle failed!", __FUNCTION__);
+ return Status::INTERNAL_ERROR;
+ }
+ }
+ }
+ configureV4l2StreamLocked(mV4l2StreamingFmt, requestFpsMax);
+ }
+ }
+
+ status = importRequestLocked(request, allBufPtrs, allFences);
+ if (status != Status::OK) {
+ return status;
+ }
+
+ nsecs_t shutterTs = 0;
+ std::unique_ptr<V4L2Frame> frameIn = dequeueV4l2FrameLocked(&shutterTs);
+ if (frameIn == nullptr) {
+ ALOGE("%s: V4L2 deque frame failed!", __FUNCTION__);
+ return Status::INTERNAL_ERROR;
+ }
+
+ std::shared_ptr<HalRequest> halReq = std::make_shared<HalRequest>();
+ halReq->frameNumber = request.frameNumber;
+ halReq->setting = mLatestReqSetting;
+ halReq->frameIn = std::move(frameIn);
+ halReq->shutterTs = shutterTs;
+ halReq->buffers.resize(numOutputBufs);
+ for (size_t i = 0; i < numOutputBufs; i++) {
+ HalStreamBuffer& halBuf = halReq->buffers[i];
+ int streamId = halBuf.streamId = request.outputBuffers[i].streamId;
+ halBuf.bufferId = request.outputBuffers[i].bufferId;
+ const Stream& stream = mStreamMap[streamId];
+ halBuf.width = stream.width;
+ halBuf.height = stream.height;
+ halBuf.format = stream.format;
+ halBuf.usage = stream.usage;
+ halBuf.bufPtr = allBufPtrs[i];
+ halBuf.acquireFence = allFences[i];
+ halBuf.fenceTimeout = false;
+ }
+ {
+ std::lock_guard<std::mutex> lk(mInflightFramesLock);
+ mInflightFrames.insert(halReq->frameNumber);
+ }
+ // Send request to OutputThread for the rest of processing
+ mOutputThread->submitRequest(halReq);
+ mFirstRequest = false;
+ return Status::OK;
+}
+
+ScopedAStatus ExternalCameraDeviceSession::signalStreamFlush(
+ const std::vector<int32_t>& /*in_streamIds*/, int32_t in_streamConfigCounter) {
+ {
+ Mutex::Autolock _l(mLock);
+ if (in_streamConfigCounter < mLastStreamConfigCounter) {
+ // stale call. new streams have been configured since this call was issued.
+ // Do nothing.
+ return fromStatus(Status::OK);
+ }
+ }
+
+ // TODO: implement if needed.
+ return fromStatus(Status::OK);
+}
+
+ScopedAStatus ExternalCameraDeviceSession::switchToOffline(
+ const std::vector<int32_t>& in_streamsToKeep,
+ CameraOfflineSessionInfo* out_offlineSessionInfo,
+ std::shared_ptr<ICameraOfflineSession>* _aidl_return) {
+ std::vector<NotifyMsg> msgs;
+ std::vector<CaptureResult> results;
+ CameraOfflineSessionInfo info;
+ std::shared_ptr<ICameraOfflineSession> session;
+ Status st = switchToOffline(in_streamsToKeep, &msgs, &results, &info, &session);
+
+ mCallback->notify(msgs);
+ invokeProcessCaptureResultCallback(results, /* tryWriteFmq= */ true);
+ freeReleaseFences(results);
+
+ // setup return values
+ *out_offlineSessionInfo = info;
+ *_aidl_return = session;
+ return fromStatus(st);
+}
+
+Status ExternalCameraDeviceSession::switchToOffline(
+ const std::vector<int32_t>& offlineStreams, std::vector<NotifyMsg>* msgs,
+ std::vector<CaptureResult>* results, CameraOfflineSessionInfo* info,
+ std::shared_ptr<ICameraOfflineSession>* session) {
+ ATRACE_CALL();
+ if (offlineStreams.size() > 1) {
+ ALOGE("%s: more than one offline stream is not supported", __FUNCTION__);
+ return Status::ILLEGAL_ARGUMENT;
+ }
+
+ if (msgs == nullptr || results == nullptr || info == nullptr || session == nullptr) {
+ ALOGE("%s, output arguments (%p, %p, %p, %p) must not be null", __FUNCTION__, msgs, results,
+ info, session);
+ }
+
+ Mutex::Autolock _il(mInterfaceLock);
+ Status status = initStatus();
+ if (status != Status::OK) {
+ return status;
+ }
+
+ Mutex::Autolock _l(mLock);
+ for (auto streamId : offlineStreams) {
+ if (!supportOfflineLocked(streamId)) {
+ return Status::ILLEGAL_ARGUMENT;
+ }
+ }
+
+ // pause output thread and get all remaining inflight requests
+ auto remainingReqs = mOutputThread->switchToOffline();
+ std::vector<std::shared_ptr<HalRequest>> halReqs;
+
+ // Send out buffer/request error for remaining requests and filter requests
+ // to be handled in offline mode
+ for (auto& halReq : remainingReqs) {
+ bool dropReq = canDropRequest(offlineStreams, halReq);
+ if (dropReq) {
+ // Request is dropped completely. Just send request error and
+ // there is no need to send the request to offline session
+ processCaptureRequestError(halReq, msgs, results);
+ continue;
+ }
+
+ // All requests reach here must have at least one offline stream output
+ NotifyMsg shutter;
+ aidl::android::hardware::camera::device::ShutterMsg shutterMsg = {
+ .frameNumber = static_cast<int32_t>(halReq->frameNumber),
+ .timestamp = halReq->shutterTs};
+ shutter.set<NotifyMsg::Tag::shutter>(shutterMsg);
+ msgs->push_back(shutter);
+
+ std::vector<HalStreamBuffer> offlineBuffers;
+ for (const auto& buffer : halReq->buffers) {
+ bool dropBuffer = true;
+ for (auto offlineStreamId : offlineStreams) {
+ if (buffer.streamId == offlineStreamId) {
+ dropBuffer = false;
+ break;
+ }
+ }
+ if (dropBuffer) {
+ aidl::android::hardware::camera::device::ErrorMsg errorMsg = {
+ .frameNumber = static_cast<int32_t>(halReq->frameNumber),
+ .errorStreamId = buffer.streamId,
+ .errorCode = ErrorCode::ERROR_BUFFER};
+
+ NotifyMsg error;
+ error.set<NotifyMsg::Tag::error>(errorMsg);
+ msgs->push_back(error);
+
+ results->push_back({
+ .frameNumber = static_cast<int32_t>(halReq->frameNumber),
+ .outputBuffers = {},
+ .inputBuffer = {.streamId = -1},
+ .partialResult = 0, // buffer only result
+ });
+
+ CaptureResult& result = results->back();
+ result.outputBuffers.resize(1);
+ StreamBuffer& outputBuffer = result.outputBuffers[0];
+ outputBuffer.streamId = buffer.streamId;
+ outputBuffer.bufferId = buffer.bufferId;
+ outputBuffer.status = BufferStatus::ERROR;
+ if (buffer.acquireFence >= 0) {
+ native_handle_t* handle = native_handle_create(/*numFds*/ 1, /*numInts*/ 0);
+ handle->data[0] = buffer.acquireFence;
+ outputBuffer.releaseFence = android::makeToAidl(handle);
+ }
+ } else {
+ offlineBuffers.push_back(buffer);
+ }
+ }
+ halReq->buffers = offlineBuffers;
+ halReqs.push_back(halReq);
+ }
+
+ // convert hal requests to offline request
+ std::deque<std::shared_ptr<HalRequest>> offlineReqs(halReqs.size());
+ size_t i = 0;
+ for (auto& v4lReq : halReqs) {
+ offlineReqs[i] = std::make_shared<HalRequest>();
+ offlineReqs[i]->frameNumber = v4lReq->frameNumber;
+ offlineReqs[i]->setting = v4lReq->setting;
+ offlineReqs[i]->shutterTs = v4lReq->shutterTs;
+ offlineReqs[i]->buffers = v4lReq->buffers;
+ std::shared_ptr<V4L2Frame> v4l2Frame(static_cast<V4L2Frame*>(v4lReq->frameIn.get()));
+ offlineReqs[i]->frameIn = std::make_shared<AllocatedV4L2Frame>(v4l2Frame);
+ i++;
+ // enqueue V4L2 frame
+ enqueueV4l2Frame(v4l2Frame);
+ }
+
+ // Collect buffer caches/streams
+ std::vector<Stream> streamInfos(offlineStreams.size());
+ std::map<int, CirculatingBuffers> circulatingBuffers;
+ {
+ Mutex::Autolock _cbsl(mCbsLock);
+ for (auto streamId : offlineStreams) {
+ circulatingBuffers[streamId] = mCirculatingBuffers.at(streamId);
+ mCirculatingBuffers.erase(streamId);
+ streamInfos.push_back(mStreamMap.at(streamId));
+ mStreamMap.erase(streamId);
+ }
+ }
+
+ fillOfflineSessionInfo(offlineStreams, offlineReqs, circulatingBuffers, info);
+ // create the offline session object
+ bool afTrigger;
+ {
+ std::lock_guard<std::mutex> _lk(mAfTriggerLock);
+ afTrigger = mAfTrigger;
+ }
+
+ std::shared_ptr<ExternalCameraOfflineSession> sessionImpl =
+ ndk::SharedRefBase::make<ExternalCameraOfflineSession>(
+ mCroppingType, mCameraCharacteristics, mCameraId, mExifMake, mExifModel,
+ mBlobBufferSize, afTrigger, streamInfos, offlineReqs, circulatingBuffers);
+
+ bool initFailed = sessionImpl->initialize();
+ if (initFailed) {
+ ALOGE("%s: offline session initialize failed!", __FUNCTION__);
+ return Status::INTERNAL_ERROR;
+ }
+
+ // cleanup stream and buffer caches
+ {
+ Mutex::Autolock _cbsl(mCbsLock);
+ for (auto pair : mStreamMap) {
+ cleanupBuffersLocked(/*Stream ID*/ pair.first);
+ }
+ mCirculatingBuffers.clear();
+ }
+ mStreamMap.clear();
+
+ // update inflight records
+ {
+ std::lock_guard<std::mutex> _lk(mInflightFramesLock);
+ mInflightFrames.clear();
+ }
+
+ // stop v4l2 streaming
+ if (v4l2StreamOffLocked() != 0) {
+ ALOGE("%s: stop V4L2 streaming failed!", __FUNCTION__);
+ return Status::INTERNAL_ERROR;
+ }
+
+ // No need to return session if there is no offline requests left
+ if (!offlineReqs.empty()) {
+ *session = sessionImpl;
+ } else {
+ *session = nullptr;
+ }
+
+ return Status::OK;
+}
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+#define UPDATE(md, tag, data, size) \
+ do { \
+ if ((md).update((tag), (data), (size))) { \
+ ALOGE("Update " #tag " failed!"); \
+ return BAD_VALUE; \
+ } \
+ } while (0)
+
+status_t ExternalCameraDeviceSession::initDefaultRequests() {
+ common::V1_0::helper::CameraMetadata md;
+
+ const uint8_t aberrationMode = ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF;
+ UPDATE(md, ANDROID_COLOR_CORRECTION_ABERRATION_MODE, &aberrationMode, 1);
+
+ const int32_t exposureCompensation = 0;
+ UPDATE(md, ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION, &exposureCompensation, 1);
+
+ const uint8_t videoStabilizationMode = ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF;
+ UPDATE(md, ANDROID_CONTROL_VIDEO_STABILIZATION_MODE, &videoStabilizationMode, 1);
+
+ const uint8_t awbMode = ANDROID_CONTROL_AWB_MODE_AUTO;
+ UPDATE(md, ANDROID_CONTROL_AWB_MODE, &awbMode, 1);
+
+ const uint8_t aeMode = ANDROID_CONTROL_AE_MODE_ON;
+ UPDATE(md, ANDROID_CONTROL_AE_MODE, &aeMode, 1);
+
+ const uint8_t aePrecaptureTrigger = ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_IDLE;
+ UPDATE(md, ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER, &aePrecaptureTrigger, 1);
+
+ const uint8_t afMode = ANDROID_CONTROL_AF_MODE_AUTO;
+ UPDATE(md, ANDROID_CONTROL_AF_MODE, &afMode, 1);
+
+ const uint8_t afTrigger = ANDROID_CONTROL_AF_TRIGGER_IDLE;
+ UPDATE(md, ANDROID_CONTROL_AF_TRIGGER, &afTrigger, 1);
+
+ const uint8_t sceneMode = ANDROID_CONTROL_SCENE_MODE_DISABLED;
+ UPDATE(md, ANDROID_CONTROL_SCENE_MODE, &sceneMode, 1);
+
+ const uint8_t effectMode = ANDROID_CONTROL_EFFECT_MODE_OFF;
+ UPDATE(md, ANDROID_CONTROL_EFFECT_MODE, &effectMode, 1);
+
+ const uint8_t flashMode = ANDROID_FLASH_MODE_OFF;
+ UPDATE(md, ANDROID_FLASH_MODE, &flashMode, 1);
+
+ const int32_t thumbnailSize[] = {240, 180};
+ UPDATE(md, ANDROID_JPEG_THUMBNAIL_SIZE, thumbnailSize, 2);
+
+ const uint8_t jpegQuality = 90;
+ UPDATE(md, ANDROID_JPEG_QUALITY, &jpegQuality, 1);
+ UPDATE(md, ANDROID_JPEG_THUMBNAIL_QUALITY, &jpegQuality, 1);
+
+ const int32_t jpegOrientation = 0;
+ UPDATE(md, ANDROID_JPEG_ORIENTATION, &jpegOrientation, 1);
+
+ const uint8_t oisMode = ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF;
+ UPDATE(md, ANDROID_LENS_OPTICAL_STABILIZATION_MODE, &oisMode, 1);
+
+ const uint8_t nrMode = ANDROID_NOISE_REDUCTION_MODE_OFF;
+ UPDATE(md, ANDROID_NOISE_REDUCTION_MODE, &nrMode, 1);
+
+ const int32_t testPatternModes = ANDROID_SENSOR_TEST_PATTERN_MODE_OFF;
+ UPDATE(md, ANDROID_SENSOR_TEST_PATTERN_MODE, &testPatternModes, 1);
+
+ const uint8_t fdMode = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;
+ UPDATE(md, ANDROID_STATISTICS_FACE_DETECT_MODE, &fdMode, 1);
+
+ const uint8_t hotpixelMode = ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE_OFF;
+ UPDATE(md, ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE, &hotpixelMode, 1);
+
+ bool support30Fps = false;
+ int32_t maxFps = std::numeric_limits<int32_t>::min();
+ for (const auto& supportedFormat : mSupportedFormats) {
+ for (const auto& fr : supportedFormat.frameRates) {
+ int32_t framerateInt = static_cast<int32_t>(fr.getFramesPerSecond());
+ if (maxFps < framerateInt) {
+ maxFps = framerateInt;
+ }
+ if (framerateInt == 30) {
+ support30Fps = true;
+ break;
+ }
+ }
+ if (support30Fps) {
+ break;
+ }
+ }
+
+ int32_t defaultFramerate = support30Fps ? 30 : maxFps;
+ int32_t defaultFpsRange[] = {defaultFramerate / 2, defaultFramerate};
+ UPDATE(md, ANDROID_CONTROL_AE_TARGET_FPS_RANGE, defaultFpsRange, ARRAY_SIZE(defaultFpsRange));
+
+ uint8_t antibandingMode = ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO;
+ UPDATE(md, ANDROID_CONTROL_AE_ANTIBANDING_MODE, &antibandingMode, 1);
+
+ const uint8_t controlMode = ANDROID_CONTROL_MODE_AUTO;
+ UPDATE(md, ANDROID_CONTROL_MODE, &controlMode, 1);
+
+ for (const auto& type : ndk::enum_range<RequestTemplate>()) {
+ common::V1_0::helper::CameraMetadata mdCopy = md;
+ uint8_t intent = ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW;
+ switch (type) {
+ case RequestTemplate::PREVIEW:
+ intent = ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW;
+ break;
+ case RequestTemplate::STILL_CAPTURE:
+ intent = ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE;
+ break;
+ case RequestTemplate::VIDEO_RECORD:
+ intent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_RECORD;
+ break;
+ case RequestTemplate::VIDEO_SNAPSHOT:
+ intent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT;
+ break;
+ default:
+ ALOGV("%s: unsupported RequestTemplate type %d", __FUNCTION__, type);
+ continue;
+ }
+ UPDATE(mdCopy, ANDROID_CONTROL_CAPTURE_INTENT, &intent, 1);
+ camera_metadata_t* mdPtr = mdCopy.release();
+ uint8_t* rawMd = reinterpret_cast<uint8_t*>(mdPtr);
+ CameraMetadata aidlMd;
+ aidlMd.metadata.assign(rawMd, rawMd + get_camera_metadata_size(mdPtr));
+ mDefaultRequests[type] = aidlMd;
+ free_camera_metadata(mdPtr);
+ }
+ return OK;
+}
+
+status_t ExternalCameraDeviceSession::fillCaptureResult(common::V1_0::helper::CameraMetadata& md,
+ nsecs_t timestamp) {
+ bool afTrigger = false;
+ {
+ std::lock_guard<std::mutex> lk(mAfTriggerLock);
+ afTrigger = mAfTrigger;
+ if (md.exists(ANDROID_CONTROL_AF_TRIGGER)) {
+ camera_metadata_entry entry = md.find(ANDROID_CONTROL_AF_TRIGGER);
+ if (entry.data.u8[0] == ANDROID_CONTROL_AF_TRIGGER_START) {
+ mAfTrigger = afTrigger = true;
+ } else if (entry.data.u8[0] == ANDROID_CONTROL_AF_TRIGGER_CANCEL) {
+ mAfTrigger = afTrigger = false;
+ }
+ }
+ }
+
+ // For USB camera, the USB camera handles everything and we don't have control
+ // over AF. We only simply fake the AF metadata based on the request
+ // received here.
+ uint8_t afState;
+ if (afTrigger) {
+ afState = ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED;
+ } else {
+ afState = ANDROID_CONTROL_AF_STATE_INACTIVE;
+ }
+ UPDATE(md, ANDROID_CONTROL_AF_STATE, &afState, 1);
+
+ camera_metadata_ro_entry activeArraySize =
+ mCameraCharacteristics.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
+
+ return fillCaptureResultCommon(md, timestamp, activeArraySize);
+}
+
+int ExternalCameraDeviceSession::configureV4l2StreamLocked(const SupportedV4L2Format& v4l2Fmt,
+ double requestFps) {
+ ATRACE_CALL();
+ int ret = v4l2StreamOffLocked();
+ if (ret != OK) {
+ ALOGE("%s: stop v4l2 streaming failed: ret %d", __FUNCTION__, ret);
+ return ret;
+ }
+
+ // VIDIOC_S_FMT w/h/fmt
+ v4l2_format fmt;
+ fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ fmt.fmt.pix.width = v4l2Fmt.width;
+ fmt.fmt.pix.height = v4l2Fmt.height;
+ fmt.fmt.pix.pixelformat = v4l2Fmt.fourcc;
+
+ {
+ int numAttempt = 0;
+ do {
+ ret = TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_S_FMT, &fmt));
+ if (numAttempt == MAX_RETRY) {
+ break;
+ }
+ numAttempt++;
+ if (ret < 0) {
+ ALOGW("%s: VIDIOC_S_FMT failed, wait 33ms and try again", __FUNCTION__);
+ usleep(IOCTL_RETRY_SLEEP_US); // sleep and try again
+ }
+ } while (ret < 0);
+ if (ret < 0) {
+ ALOGE("%s: S_FMT ioctl failed: %s", __FUNCTION__, strerror(errno));
+ return -errno;
+ }
+ }
+
+ if (v4l2Fmt.width != fmt.fmt.pix.width || v4l2Fmt.height != fmt.fmt.pix.height ||
+ v4l2Fmt.fourcc != fmt.fmt.pix.pixelformat) {
+ ALOGE("%s: S_FMT expect %c%c%c%c %dx%d, got %c%c%c%c %dx%d instead!", __FUNCTION__,
+ v4l2Fmt.fourcc & 0xFF, (v4l2Fmt.fourcc >> 8) & 0xFF, (v4l2Fmt.fourcc >> 16) & 0xFF,
+ (v4l2Fmt.fourcc >> 24) & 0xFF, v4l2Fmt.width, v4l2Fmt.height,
+ fmt.fmt.pix.pixelformat & 0xFF, (fmt.fmt.pix.pixelformat >> 8) & 0xFF,
+ (fmt.fmt.pix.pixelformat >> 16) & 0xFF, (fmt.fmt.pix.pixelformat >> 24) & 0xFF,
+ fmt.fmt.pix.width, fmt.fmt.pix.height);
+ return -EINVAL;
+ }
+
+ uint32_t bufferSize = fmt.fmt.pix.sizeimage;
+ ALOGI("%s: V4L2 buffer size is %d", __FUNCTION__, bufferSize);
+ uint32_t expectedMaxBufferSize = kMaxBytesPerPixel * fmt.fmt.pix.width * fmt.fmt.pix.height;
+ if ((bufferSize == 0) || (bufferSize > expectedMaxBufferSize)) {
+ ALOGE("%s: V4L2 buffer size: %u looks invalid. Expected maximum size: %u", __FUNCTION__,
+ bufferSize, expectedMaxBufferSize);
+ return -EINVAL;
+ }
+ mMaxV4L2BufferSize = bufferSize;
+
+ const double kDefaultFps = 30.0;
+ double fps = std::numeric_limits<double>::max();
+ if (requestFps != 0.0) {
+ fps = requestFps;
+ } else {
+ double maxFps = -1.0;
+ // Try to pick the slowest fps that is at least 30
+ for (const auto& fr : v4l2Fmt.frameRates) {
+ double f = fr.getFramesPerSecond();
+ if (maxFps < f) {
+ maxFps = f;
+ }
+ if (f >= kDefaultFps && f < fps) {
+ fps = f;
+ }
+ }
+ // No fps > 30 found, use the highest fps available within supported formats.
+ if (fps == std::numeric_limits<double>::max()) {
+ fps = maxFps;
+ }
+ }
+
+ int fpsRet = setV4l2FpsLocked(fps);
+ if (fpsRet != 0 && fpsRet != -EINVAL) {
+ ALOGE("%s: set fps failed: %s", __FUNCTION__, strerror(fpsRet));
+ return fpsRet;
+ }
+
+ uint32_t v4lBufferCount = (fps >= kDefaultFps) ? mCfg.numVideoBuffers : mCfg.numStillBuffers;
+
+ // VIDIOC_REQBUFS: create buffers
+ v4l2_requestbuffers req_buffers{};
+ req_buffers.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ req_buffers.memory = V4L2_MEMORY_MMAP;
+ req_buffers.count = v4lBufferCount;
+ if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_REQBUFS, &req_buffers)) < 0) {
+ ALOGE("%s: VIDIOC_REQBUFS failed: %s", __FUNCTION__, strerror(errno));
+ return -errno;
+ }
+
+ // Driver can indeed return more buffer if it needs more to operate
+ if (req_buffers.count < v4lBufferCount) {
+ ALOGE("%s: VIDIOC_REQBUFS expected %d buffers, got %d instead", __FUNCTION__,
+ v4lBufferCount, req_buffers.count);
+ return NO_MEMORY;
+ }
+
+ // VIDIOC_QUERYBUF: get buffer offset in the V4L2 fd
+ // VIDIOC_QBUF: send buffer to driver
+ mV4L2BufferCount = req_buffers.count;
+ for (uint32_t i = 0; i < req_buffers.count; i++) {
+ v4l2_buffer buffer = {
+ .index = i, .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, .memory = V4L2_MEMORY_MMAP};
+
+ if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_QUERYBUF, &buffer)) < 0) {
+ ALOGE("%s: QUERYBUF %d failed: %s", __FUNCTION__, i, strerror(errno));
+ return -errno;
+ }
+
+ if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_QBUF, &buffer)) < 0) {
+ ALOGE("%s: QBUF %d failed: %s", __FUNCTION__, i, strerror(errno));
+ return -errno;
+ }
+ }
+
+ {
+ // VIDIOC_STREAMON: start streaming
+ v4l2_buf_type capture_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ int numAttempt = 0;
+ do {
+ ret = TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_STREAMON, &capture_type));
+ if (numAttempt == MAX_RETRY) {
+ break;
+ }
+ if (ret < 0) {
+ ALOGW("%s: VIDIOC_STREAMON failed, wait 33ms and try again", __FUNCTION__);
+ usleep(IOCTL_RETRY_SLEEP_US); // sleep 100 ms and try again
+ }
+ } while (ret < 0);
+
+ if (ret < 0) {
+ ALOGE("%s: VIDIOC_STREAMON ioctl failed: %s", __FUNCTION__, strerror(errno));
+ return -errno;
+ }
+ }
+
+ // Swallow first few frames after streamOn to account for bad frames from some devices
+ for (int i = 0; i < kBadFramesAfterStreamOn; i++) {
+ v4l2_buffer buffer{};
+ buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buffer.memory = V4L2_MEMORY_MMAP;
+ if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_DQBUF, &buffer)) < 0) {
+ ALOGE("%s: DQBUF fails: %s", __FUNCTION__, strerror(errno));
+ return -errno;
+ }
+
+ if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_QBUF, &buffer)) < 0) {
+ ALOGE("%s: QBUF index %d fails: %s", __FUNCTION__, buffer.index, strerror(errno));
+ return -errno;
+ }
+ }
+
+ ALOGI("%s: start V4L2 streaming %dx%d@%ffps", __FUNCTION__, v4l2Fmt.width, v4l2Fmt.height, fps);
+ mV4l2StreamingFmt = v4l2Fmt;
+ mV4l2Streaming = true;
+ return OK;
+}
+
+std::unique_ptr<V4L2Frame> ExternalCameraDeviceSession::dequeueV4l2FrameLocked(nsecs_t* shutterTs) {
+ ATRACE_CALL();
+ std::unique_ptr<V4L2Frame> ret = nullptr;
+ if (shutterTs == nullptr) {
+ ALOGE("%s: shutterTs must not be null!", __FUNCTION__);
+ return ret;
+ }
+
+ {
+ std::unique_lock<std::mutex> lk(mV4l2BufferLock);
+ if (mNumDequeuedV4l2Buffers == mV4L2BufferCount) {
+ int waitRet = waitForV4L2BufferReturnLocked(lk);
+ if (waitRet != 0) {
+ return ret;
+ }
+ }
+ }
+
+ ATRACE_BEGIN("VIDIOC_DQBUF");
+ v4l2_buffer buffer{};
+ buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buffer.memory = V4L2_MEMORY_MMAP;
+ if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_DQBUF, &buffer)) < 0) {
+ ALOGE("%s: DQBUF fails: %s", __FUNCTION__, strerror(errno));
+ return ret;
+ }
+ ATRACE_END();
+
+ if (buffer.index >= mV4L2BufferCount) {
+ ALOGE("%s: Invalid buffer id: %d", __FUNCTION__, buffer.index);
+ return ret;
+ }
+
+ if (buffer.flags & V4L2_BUF_FLAG_ERROR) {
+ ALOGE("%s: v4l2 buf error! buf flag 0x%x", __FUNCTION__, buffer.flags);
+ // TODO: try to dequeue again
+ }
+
+ if (buffer.bytesused > mMaxV4L2BufferSize) {
+ ALOGE("%s: v4l2 buffer bytes used: %u maximum %u", __FUNCTION__, buffer.bytesused,
+ mMaxV4L2BufferSize);
+ return ret;
+ }
+
+ if (buffer.flags & V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC) {
+ // Ideally we should also check for V4L2_BUF_FLAG_TSTAMP_SRC_SOE, but
+ // even V4L2_BUF_FLAG_TSTAMP_SRC_EOF is better than capture a timestamp now
+ *shutterTs = static_cast<nsecs_t>(buffer.timestamp.tv_sec) * 1000000000LL +
+ buffer.timestamp.tv_usec * 1000LL;
+ } else {
+ *shutterTs = systemTime(SYSTEM_TIME_MONOTONIC);
+ }
+
+ {
+ std::lock_guard<std::mutex> lk(mV4l2BufferLock);
+ mNumDequeuedV4l2Buffers++;
+ }
+
+ return std::make_unique<V4L2Frame>(mV4l2StreamingFmt.width, mV4l2StreamingFmt.height,
+ mV4l2StreamingFmt.fourcc, buffer.index, mV4l2Fd.get(),
+ buffer.bytesused, buffer.m.offset);
+}
+
+void ExternalCameraDeviceSession::enqueueV4l2Frame(const std::shared_ptr<V4L2Frame>& frame) {
+ ATRACE_CALL();
+ frame->unmap();
+ ATRACE_BEGIN("VIDIOC_QBUF");
+ v4l2_buffer buffer{};
+ buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buffer.memory = V4L2_MEMORY_MMAP;
+ buffer.index = frame->mBufferIndex;
+ if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_QBUF, &buffer)) < 0) {
+ ALOGE("%s: QBUF index %d fails: %s", __FUNCTION__, frame->mBufferIndex, strerror(errno));
+ return;
+ }
+ ATRACE_END();
+
+ {
+ std::lock_guard<std::mutex> lk(mV4l2BufferLock);
+ mNumDequeuedV4l2Buffers--;
+ }
+ mV4L2BufferReturned.notify_one();
+}
+
+bool ExternalCameraDeviceSession::isSupported(
+ const Stream& stream, const std::vector<SupportedV4L2Format>& supportedFormats,
+ const ExternalCameraConfig& devCfg) {
+ Dataspace ds = stream.dataSpace;
+ PixelFormat fmt = stream.format;
+ uint32_t width = stream.width;
+ uint32_t height = stream.height;
+ // TODO: check usage flags
+
+ if (stream.streamType != StreamType::OUTPUT) {
+ ALOGE("%s: does not support non-output stream type", __FUNCTION__);
+ return false;
+ }
+
+ if (stream.rotation != StreamRotation::ROTATION_0) {
+ ALOGE("%s: does not support stream rotation", __FUNCTION__);
+ return false;
+ }
+
+ switch (fmt) {
+ case PixelFormat::BLOB:
+ if (ds != Dataspace::JFIF) {
+ ALOGI("%s: BLOB format does not support dataSpace %x", __FUNCTION__, ds);
+ return false;
+ }
+ break;
+ case PixelFormat::IMPLEMENTATION_DEFINED:
+ case PixelFormat::YCBCR_420_888:
+ case PixelFormat::YV12:
+ // TODO: check what dataspace we can support here.
+ // intentional no-ops.
+ break;
+ case PixelFormat::Y16:
+ if (!devCfg.depthEnabled) {
+ ALOGI("%s: Depth is not Enabled", __FUNCTION__);
+ return false;
+ }
+ if (!(static_cast<int32_t>(ds) & static_cast<int32_t>(Dataspace::DEPTH))) {
+ ALOGI("%s: Y16 supports only dataSpace DEPTH", __FUNCTION__);
+ return false;
+ }
+ break;
+ default:
+ ALOGI("%s: does not support format %x", __FUNCTION__, fmt);
+ return false;
+ }
+
+ // Assume we can convert any V4L2 format to any of supported output format for now, i.e.
+ // ignoring v4l2Fmt.fourcc for now. Might need more subtle check if we support more v4l format
+ // in the futrue.
+ for (const auto& v4l2Fmt : supportedFormats) {
+ if (width == v4l2Fmt.width && height == v4l2Fmt.height) {
+ return true;
+ }
+ }
+ ALOGI("%s: resolution %dx%d is not supported", __FUNCTION__, width, height);
+ return false;
+}
+
+Status ExternalCameraDeviceSession::importRequestLocked(const CaptureRequest& request,
+ std::vector<buffer_handle_t*>& allBufPtrs,
+ std::vector<int>& allFences) {
+ return importRequestLockedImpl(request, allBufPtrs, allFences);
+}
+
+Status ExternalCameraDeviceSession::importRequestLockedImpl(
+ const CaptureRequest& request, std::vector<buffer_handle_t*>& allBufPtrs,
+ std::vector<int>& allFences) {
+ size_t numOutputBufs = request.outputBuffers.size();
+ size_t numBufs = numOutputBufs;
+ // Validate all I/O buffers
+ std::vector<buffer_handle_t> allBufs;
+ std::vector<uint64_t> allBufIds;
+ allBufs.resize(numBufs);
+ allBufIds.resize(numBufs);
+ allBufPtrs.resize(numBufs);
+ allFences.resize(numBufs);
+ std::vector<int32_t> streamIds(numBufs);
+
+ for (size_t i = 0; i < numOutputBufs; i++) {
+ allBufs[i] = ::android::makeFromAidl(request.outputBuffers[i].buffer);
+ allBufIds[i] = request.outputBuffers[i].bufferId;
+ allBufPtrs[i] = &allBufs[i];
+ streamIds[i] = request.outputBuffers[i].streamId;
+ }
+
+ {
+ Mutex::Autolock _l(mCbsLock);
+ for (size_t i = 0; i < numBufs; i++) {
+ Status st = importBufferLocked(streamIds[i], allBufIds[i], allBufs[i], &allBufPtrs[i]);
+ if (st != Status::OK) {
+ // Detailed error logs printed in importBuffer
+ return st;
+ }
+ }
+ }
+
+ // All buffers are imported. Now validate output buffer acquire fences
+ for (size_t i = 0; i < numOutputBufs; i++) {
+ if (!sHandleImporter.importFence(
+ ::android::makeFromAidl(request.outputBuffers[i].acquireFence), allFences[i])) {
+ ALOGE("%s: output buffer %zu acquire fence is invalid", __FUNCTION__, i);
+ cleanupInflightFences(allFences, i);
+ return Status::INTERNAL_ERROR;
+ }
+ }
+ return Status::OK;
+}
+
+Status ExternalCameraDeviceSession::importBuffer(int32_t streamId, uint64_t bufId,
+ buffer_handle_t buf,
+ /*out*/ buffer_handle_t** outBufPtr) {
+ Mutex::Autolock _l(mCbsLock);
+ return importBufferLocked(streamId, bufId, buf, outBufPtr);
+}
+
+Status ExternalCameraDeviceSession::importBufferLocked(int32_t streamId, uint64_t bufId,
+ buffer_handle_t buf,
+ buffer_handle_t** outBufPtr) {
+ return importBufferImpl(mCirculatingBuffers, sHandleImporter, streamId, bufId, buf, outBufPtr);
+}
+
+ScopedAStatus ExternalCameraDeviceSession::close() {
+ close(false);
+ return fromStatus(Status::OK);
+}
+
+void ExternalCameraDeviceSession::close(bool callerIsDtor) {
+ Mutex::Autolock _il(mInterfaceLock);
+ bool closed = isClosed();
+ if (!closed) {
+ if (callerIsDtor) {
+ closeOutputThreadImpl();
+ } else {
+ closeOutputThread();
+ }
+
+ Mutex::Autolock _l(mLock);
+ // free all buffers
+ {
+ Mutex::Autolock _cbsl(mCbsLock);
+ for (auto pair : mStreamMap) {
+ cleanupBuffersLocked(/*Stream ID*/ pair.first);
+ }
+ }
+ v4l2StreamOffLocked();
+ ALOGV("%s: closing V4L2 camera FD %d", __FUNCTION__, mV4l2Fd.get());
+ mV4l2Fd.reset();
+ mClosed = true;
+ }
+}
+
+bool ExternalCameraDeviceSession::isClosed() {
+ Mutex::Autolock _l(mLock);
+ return mClosed;
+}
+
+ScopedAStatus ExternalCameraDeviceSession::repeatingRequestEnd(
+ int32_t /*in_frameNumber*/, const std::vector<int32_t>& /*in_streamIds*/) {
+ // TODO: Figure this one out.
+ return fromStatus(Status::OK);
+}
+
+int ExternalCameraDeviceSession::v4l2StreamOffLocked() {
+ if (!mV4l2Streaming) {
+ return OK;
+ }
+
+ {
+ std::lock_guard<std::mutex> lk(mV4l2BufferLock);
+ if (mNumDequeuedV4l2Buffers != 0) {
+ ALOGE("%s: there are %zu inflight V4L buffers", __FUNCTION__, mNumDequeuedV4l2Buffers);
+ return -1;
+ }
+ }
+ mV4L2BufferCount = 0;
+
+ // VIDIOC_STREAMOFF
+ v4l2_buf_type capture_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_STREAMOFF, &capture_type)) < 0) {
+ ALOGE("%s: STREAMOFF failed: %s", __FUNCTION__, strerror(errno));
+ return -errno;
+ }
+
+ // VIDIOC_REQBUFS: clear buffers
+ v4l2_requestbuffers req_buffers{};
+ req_buffers.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ req_buffers.memory = V4L2_MEMORY_MMAP;
+ req_buffers.count = 0;
+ if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_REQBUFS, &req_buffers)) < 0) {
+ ALOGE("%s: REQBUFS failed: %s", __FUNCTION__, strerror(errno));
+ return -errno;
+ }
+
+ mV4l2Streaming = false;
+ return OK;
+}
+
+int ExternalCameraDeviceSession::setV4l2FpsLocked(double fps) {
+ // VIDIOC_G_PARM/VIDIOC_S_PARM: set fps
+ v4l2_streamparm streamparm = {.type = V4L2_BUF_TYPE_VIDEO_CAPTURE};
+ // The following line checks that the driver knows about framerate get/set.
+ int ret = TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_G_PARM, &streamparm));
+ if (ret != 0) {
+ if (errno == -EINVAL) {
+ ALOGW("%s: device does not support VIDIOC_G_PARM", __FUNCTION__);
+ }
+ return -errno;
+ }
+ // Now check if the device is able to accept a capture framerate set.
+ if (!(streamparm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME)) {
+ ALOGW("%s: device does not support V4L2_CAP_TIMEPERFRAME", __FUNCTION__);
+ return -EINVAL;
+ }
+
+ // fps is float, approximate by a fraction.
+ const int kFrameRatePrecision = 10000;
+ streamparm.parm.capture.timeperframe.numerator = kFrameRatePrecision;
+ streamparm.parm.capture.timeperframe.denominator = (fps * kFrameRatePrecision);
+
+ if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_S_PARM, &streamparm)) < 0) {
+ ALOGE("%s: failed to set framerate to %f: %s", __FUNCTION__, fps, strerror(errno));
+ return -1;
+ }
+
+ double retFps = streamparm.parm.capture.timeperframe.denominator /
+ static_cast<double>(streamparm.parm.capture.timeperframe.numerator);
+ if (std::fabs(fps - retFps) > 1.0) {
+ ALOGE("%s: expect fps %f, got %f instead", __FUNCTION__, fps, retFps);
+ return -1;
+ }
+ mV4l2StreamingFps = fps;
+ return 0;
+}
+
+void ExternalCameraDeviceSession::cleanupInflightFences(std::vector<int>& allFences,
+ size_t numFences) {
+ for (size_t j = 0; j < numFences; j++) {
+ sHandleImporter.closeFence(allFences[j]);
+ }
+}
+
+void ExternalCameraDeviceSession::cleanupBuffersLocked(int id) {
+ for (auto& pair : mCirculatingBuffers.at(id)) {
+ sHandleImporter.freeBuffer(pair.second);
+ }
+ mCirculatingBuffers[id].clear();
+ mCirculatingBuffers.erase(id);
+}
+
+void ExternalCameraDeviceSession::notifyShutter(int32_t frameNumber, nsecs_t shutterTs) {
+ NotifyMsg msg;
+ msg.set<NotifyMsg::Tag::shutter>(ShutterMsg{
+ .frameNumber = frameNumber,
+ .timestamp = shutterTs,
+ });
+ mCallback->notify({msg});
+}
+void ExternalCameraDeviceSession::notifyError(int32_t frameNumber, int32_t streamId, ErrorCode ec) {
+ NotifyMsg msg;
+ msg.set<NotifyMsg::Tag::error>(ErrorMsg{
+ .frameNumber = frameNumber,
+ .errorStreamId = streamId,
+ .errorCode = ec,
+ });
+ mCallback->notify({msg});
+}
+
+void ExternalCameraDeviceSession::invokeProcessCaptureResultCallback(
+ std::vector<CaptureResult>& results, bool tryWriteFmq) {
+ if (mProcessCaptureResultLock.tryLock() != OK) {
+ const nsecs_t NS_TO_SECOND = 1000000000;
+ ALOGV("%s: previous call is not finished! waiting 1s...", __FUNCTION__);
+ if (mProcessCaptureResultLock.timedLock(/* 1s */ NS_TO_SECOND) != OK) {
+ ALOGE("%s: cannot acquire lock in 1s, cannot proceed", __FUNCTION__);
+ return;
+ }
+ }
+ if (tryWriteFmq && mResultMetadataQueue->availableToWrite() > 0) {
+ for (CaptureResult& result : results) {
+ CameraMetadata& md = result.result;
+ if (!md.metadata.empty()) {
+ if (mResultMetadataQueue->write(reinterpret_cast<int8_t*>(md.metadata.data()),
+ md.metadata.size())) {
+ result.fmqResultSize = md.metadata.size();
+ md.metadata.resize(0);
+ } else {
+ ALOGW("%s: couldn't utilize fmq, fall back to hwbinder", __FUNCTION__);
+ result.fmqResultSize = 0;
+ }
+ } else {
+ result.fmqResultSize = 0;
+ }
+ }
+ }
+ auto status = mCallback->processCaptureResult(results);
+ if (!status.isOk()) {
+ ALOGE("%s: processCaptureResult ERROR : %d:%d", __FUNCTION__, status.getExceptionCode(),
+ status.getServiceSpecificError());
+ }
+
+ mProcessCaptureResultLock.unlock();
+}
+
+int ExternalCameraDeviceSession::waitForV4L2BufferReturnLocked(std::unique_lock<std::mutex>& lk) {
+ ATRACE_CALL();
+ auto timeout = std::chrono::seconds(kBufferWaitTimeoutSec);
+ mLock.unlock();
+ auto st = mV4L2BufferReturned.wait_for(lk, timeout);
+ // Here we introduce an order where mV4l2BufferLock is acquired before mLock, while
+ // the normal lock acquisition order is reversed. This is fine because in most of
+ // cases we are protected by mInterfaceLock. The only thread that can cause deadlock
+ // is the OutputThread, where we do need to make sure we don't acquire mLock then
+ // mV4l2BufferLock
+ mLock.lock();
+ if (st == std::cv_status::timeout) {
+ ALOGE("%s: wait for V4L2 buffer return timeout!", __FUNCTION__);
+ return -1;
+ }
+ return 0;
+}
+
+bool ExternalCameraDeviceSession::supportOfflineLocked(int32_t streamId) {
+ const Stream& stream = mStreamMap[streamId];
+ if (stream.format == PixelFormat::BLOB &&
+ static_cast<int32_t>(stream.dataSpace) == static_cast<int32_t>(Dataspace::JFIF)) {
+ return true;
+ }
+ // TODO: support YUV output stream?
+ return false;
+}
+
+bool ExternalCameraDeviceSession::canDropRequest(const std::vector<int32_t>& offlineStreams,
+ std::shared_ptr<HalRequest> halReq) {
+ for (const auto& buffer : halReq->buffers) {
+ for (auto offlineStreamId : offlineStreams) {
+ if (buffer.streamId == offlineStreamId) {
+ return false;
+ }
+ }
+ }
+ // Only drop a request completely if it has no offline output
+ return true;
+}
+
+void ExternalCameraDeviceSession::fillOfflineSessionInfo(
+ const std::vector<int32_t>& offlineStreams,
+ std::deque<std::shared_ptr<HalRequest>>& offlineReqs,
+ const std::map<int, CirculatingBuffers>& circulatingBuffers,
+ CameraOfflineSessionInfo* info) {
+ if (info == nullptr) {
+ ALOGE("%s: output info must not be null!", __FUNCTION__);
+ return;
+ }
+
+ info->offlineStreams.resize(offlineStreams.size());
+ info->offlineRequests.resize(offlineReqs.size());
+
+ // Fill in offline reqs and count outstanding buffers
+ for (size_t i = 0; i < offlineReqs.size(); i++) {
+ info->offlineRequests[i].frameNumber = offlineReqs[i]->frameNumber;
+ info->offlineRequests[i].pendingStreams.resize(offlineReqs[i]->buffers.size());
+ for (size_t bIdx = 0; bIdx < offlineReqs[i]->buffers.size(); bIdx++) {
+ int32_t streamId = offlineReqs[i]->buffers[bIdx].streamId;
+ info->offlineRequests[i].pendingStreams[bIdx] = streamId;
+ }
+ }
+
+ for (size_t i = 0; i < offlineStreams.size(); i++) {
+ int32_t streamId = offlineStreams[i];
+ info->offlineStreams[i].id = streamId;
+ // outstanding buffers are 0 since we are doing hal buffer management and
+ // offline session will ask for those buffers later
+ info->offlineStreams[i].numOutstandingBuffers = 0;
+ const CirculatingBuffers& bufIdMap = circulatingBuffers.at(streamId);
+ info->offlineStreams[i].circulatingBufferIds.resize(bufIdMap.size());
+ size_t bIdx = 0;
+ for (const auto& pair : bufIdMap) {
+ // Fill in bufferId
+ info->offlineStreams[i].circulatingBufferIds[bIdx++] = pair.first;
+ }
+ }
+}
+
+Status ExternalCameraDeviceSession::isStreamCombinationSupported(
+ const StreamConfiguration& config, const std::vector<SupportedV4L2Format>& supportedFormats,
+ const ExternalCameraConfig& devCfg) {
+ if (config.operationMode != StreamConfigurationMode::NORMAL_MODE) {
+ ALOGE("%s: unsupported operation mode: %d", __FUNCTION__, config.operationMode);
+ return Status::ILLEGAL_ARGUMENT;
+ }
+
+ if (config.streams.size() == 0) {
+ ALOGE("%s: cannot configure zero stream", __FUNCTION__);
+ return Status::ILLEGAL_ARGUMENT;
+ }
+
+ int numProcessedStream = 0;
+ int numStallStream = 0;
+ for (const auto& stream : config.streams) {
+ // Check if the format/width/height combo is supported
+ if (!isSupported(stream, supportedFormats, devCfg)) {
+ return Status::ILLEGAL_ARGUMENT;
+ }
+ if (stream.format == PixelFormat::BLOB) {
+ numStallStream++;
+ } else {
+ numProcessedStream++;
+ }
+ }
+
+ if (numProcessedStream > kMaxProcessedStream) {
+ ALOGE("%s: too many processed streams (expect <= %d, got %d)", __FUNCTION__,
+ kMaxProcessedStream, numProcessedStream);
+ return Status::ILLEGAL_ARGUMENT;
+ }
+
+ if (numStallStream > kMaxStallStream) {
+ ALOGE("%s: too many stall streams (expect <= %d, got %d)", __FUNCTION__, kMaxStallStream,
+ numStallStream);
+ return Status::ILLEGAL_ARGUMENT;
+ }
+
+ return Status::OK;
+}
+void ExternalCameraDeviceSession::updateBufferCaches(
+ const std::vector<BufferCache>& cachesToRemove) {
+ Mutex::Autolock _l(mCbsLock);
+ for (auto& cache : cachesToRemove) {
+ auto cbsIt = mCirculatingBuffers.find(cache.streamId);
+ if (cbsIt == mCirculatingBuffers.end()) {
+ // The stream could have been removed
+ continue;
+ }
+ CirculatingBuffers& cbs = cbsIt->second;
+ auto it = cbs.find(cache.bufferId);
+ if (it != cbs.end()) {
+ sHandleImporter.freeBuffer(it->second);
+ cbs.erase(it);
+ } else {
+ ALOGE("%s: stream %d buffer %" PRIu64 " is not cached", __FUNCTION__, cache.streamId,
+ cache.bufferId);
+ }
+ }
+}
+
+Status ExternalCameraDeviceSession::processCaptureRequestError(
+ const std::shared_ptr<HalRequest>& req, std::vector<NotifyMsg>* outMsgs,
+ std::vector<CaptureResult>* outResults) {
+ ATRACE_CALL();
+ // Return V4L2 buffer to V4L2 buffer queue
+ std::shared_ptr<V4L2Frame> v4l2Frame = std::static_pointer_cast<V4L2Frame>(req->frameIn);
+ enqueueV4l2Frame(v4l2Frame);
+
+ if (outMsgs == nullptr) {
+ notifyShutter(req->frameNumber, req->shutterTs);
+ notifyError(/*frameNum*/ req->frameNumber, /*stream*/ -1, ErrorCode::ERROR_REQUEST);
+ } else {
+ NotifyMsg shutter;
+ shutter.set<NotifyMsg::Tag::shutter>(
+ ShutterMsg{.frameNumber = req->frameNumber, .timestamp = req->shutterTs});
+
+ NotifyMsg error;
+ error.set<NotifyMsg::Tag::error>(ErrorMsg{.frameNumber = req->frameNumber,
+ .errorStreamId = -1,
+ .errorCode = ErrorCode::ERROR_REQUEST});
+ outMsgs->push_back(shutter);
+ outMsgs->push_back(error);
+ }
+
+ // Fill output buffers
+ CaptureResult result;
+ result.frameNumber = req->frameNumber;
+ result.partialResult = 1;
+ result.inputBuffer.streamId = -1;
+ result.outputBuffers.resize(req->buffers.size());
+ for (size_t i = 0; i < req->buffers.size(); i++) {
+ result.outputBuffers[i].streamId = req->buffers[i].streamId;
+ result.outputBuffers[i].bufferId = req->buffers[i].bufferId;
+ result.outputBuffers[i].status = BufferStatus::ERROR;
+ if (req->buffers[i].acquireFence >= 0) {
+ native_handle_t* handle = native_handle_create(/*numFds*/ 1, /*numInts*/ 0);
+ handle->data[0] = req->buffers[i].acquireFence;
+ result.outputBuffers[i].releaseFence = ::android::makeToAidl(handle);
+ }
+ }
+
+ // update inflight records
+ {
+ std::lock_guard<std::mutex> lk(mInflightFramesLock);
+ mInflightFrames.erase(req->frameNumber);
+ }
+
+ if (outResults == nullptr) {
+ // Callback into framework
+ std::vector<CaptureResult> results(1);
+ results[0] = std::move(result);
+ invokeProcessCaptureResultCallback(results, /* tryWriteFmq */ true);
+ freeReleaseFences(results);
+ } else {
+ outResults->push_back(std::move(result));
+ }
+ return Status::OK;
+}
+
+Status ExternalCameraDeviceSession::processCaptureResult(std::shared_ptr<HalRequest>& req) {
+ ATRACE_CALL();
+ // Return V4L2 buffer to V4L2 buffer queue
+ std::shared_ptr<V4L2Frame> v4l2Frame = std::static_pointer_cast<V4L2Frame>(req->frameIn);
+ enqueueV4l2Frame(v4l2Frame);
+
+ // NotifyShutter
+ notifyShutter(req->frameNumber, req->shutterTs);
+
+ // Fill output buffers;
+ std::vector<CaptureResult> results(1);
+ CaptureResult& result = results[0];
+ result.frameNumber = req->frameNumber;
+ result.partialResult = 1;
+ result.inputBuffer.streamId = -1;
+ result.outputBuffers.resize(req->buffers.size());
+ for (size_t i = 0; i < req->buffers.size(); i++) {
+ result.outputBuffers[i].streamId = req->buffers[i].streamId;
+ result.outputBuffers[i].bufferId = req->buffers[i].bufferId;
+ if (req->buffers[i].fenceTimeout) {
+ result.outputBuffers[i].status = BufferStatus::ERROR;
+ if (req->buffers[i].acquireFence >= 0) {
+ native_handle_t* handle = native_handle_create(/*numFds*/ 1, /*numInts*/ 0);
+ handle->data[0] = req->buffers[i].acquireFence;
+ result.outputBuffers[i].releaseFence = ::android::makeToAidl(handle);
+ }
+ notifyError(req->frameNumber, req->buffers[i].streamId, ErrorCode::ERROR_BUFFER);
+ } else {
+ result.outputBuffers[i].status = BufferStatus::OK;
+ // TODO: refactor
+ if (req->buffers[i].acquireFence >= 0) {
+ native_handle_t* handle = native_handle_create(/*numFds*/ 1, /*numInts*/ 0);
+ handle->data[0] = req->buffers[i].acquireFence;
+ result.outputBuffers[i].releaseFence = ::android::makeToAidl(handle);
+ }
+ }
+ }
+
+ // Fill capture result metadata
+ fillCaptureResult(req->setting, req->shutterTs);
+ const camera_metadata_t* rawResult = req->setting.getAndLock();
+ convertToAidl(rawResult, &result.result);
+ req->setting.unlock(rawResult);
+
+ // update inflight records
+ {
+ std::lock_guard<std::mutex> lk(mInflightFramesLock);
+ mInflightFrames.erase(req->frameNumber);
+ }
+
+ // Callback into framework
+ invokeProcessCaptureResultCallback(results, /* tryWriteFmq */ true);
+ freeReleaseFences(results);
+ return Status::OK;
+}
+
+ssize_t ExternalCameraDeviceSession::getJpegBufferSize(int32_t width, int32_t height) const {
+ // Constant from camera3.h
+ const ssize_t kMinJpegBufferSize = 256 * 1024 + sizeof(CameraBlob);
+ // Get max jpeg size (area-wise).
+ if (mMaxJpegResolution.width == 0) {
+ ALOGE("%s: No supported JPEG stream", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ // Get max jpeg buffer size
+ ssize_t maxJpegBufferSize = 0;
+ camera_metadata_ro_entry jpegBufMaxSize = mCameraCharacteristics.find(ANDROID_JPEG_MAX_SIZE);
+ if (jpegBufMaxSize.count == 0) {
+ ALOGE("%s: Can't find maximum JPEG size in static metadata!", __FUNCTION__);
+ return BAD_VALUE;
+ }
+ maxJpegBufferSize = jpegBufMaxSize.data.i32[0];
+
+ if (maxJpegBufferSize <= kMinJpegBufferSize) {
+ ALOGE("%s: ANDROID_JPEG_MAX_SIZE (%zd) <= kMinJpegBufferSize (%zd)", __FUNCTION__,
+ maxJpegBufferSize, kMinJpegBufferSize);
+ return BAD_VALUE;
+ }
+
+ // Calculate final jpeg buffer size for the given resolution.
+ float scaleFactor =
+ ((float)(width * height)) / (mMaxJpegResolution.width * mMaxJpegResolution.height);
+ ssize_t jpegBufferSize =
+ scaleFactor * (maxJpegBufferSize - kMinJpegBufferSize) + kMinJpegBufferSize;
+ if (jpegBufferSize > maxJpegBufferSize) {
+ jpegBufferSize = maxJpegBufferSize;
+ }
+
+ return jpegBufferSize;
+}
+binder_status_t ExternalCameraDeviceSession::dump(int fd, const char** /*args*/,
+ uint32_t /*numArgs*/) {
+ bool intfLocked = tryLock(mInterfaceLock);
+ if (!intfLocked) {
+ dprintf(fd, "!! ExternalCameraDeviceSession interface may be deadlocked !!\n");
+ }
+
+ if (isClosed()) {
+ dprintf(fd, "External camera %s is closed\n", mCameraId.c_str());
+ return STATUS_OK;
+ }
+
+ bool streaming = false;
+ size_t v4L2BufferCount = 0;
+ SupportedV4L2Format streamingFmt;
+ {
+ bool sessionLocked = tryLock(mLock);
+ if (!sessionLocked) {
+ dprintf(fd, "!! ExternalCameraDeviceSession mLock may be deadlocked !!\n");
+ }
+ streaming = mV4l2Streaming;
+ streamingFmt = mV4l2StreamingFmt;
+ v4L2BufferCount = mV4L2BufferCount;
+
+ if (sessionLocked) {
+ mLock.unlock();
+ }
+ }
+
+ std::unordered_set<uint32_t> inflightFrames;
+ {
+ bool iffLocked = tryLock(mInflightFramesLock);
+ if (!iffLocked) {
+ dprintf(fd,
+ "!! ExternalCameraDeviceSession mInflightFramesLock may be deadlocked !!\n");
+ }
+ inflightFrames = mInflightFrames;
+ if (iffLocked) {
+ mInflightFramesLock.unlock();
+ }
+ }
+
+ dprintf(fd, "External camera %s V4L2 FD %d, cropping type %s, %s\n", mCameraId.c_str(),
+ mV4l2Fd.get(), (mCroppingType == VERTICAL) ? "vertical" : "horizontal",
+ streaming ? "streaming" : "not streaming");
+
+ if (streaming) {
+ // TODO: dump fps later
+ dprintf(fd, "Current V4L2 format %c%c%c%c %dx%d @ %ffps\n", streamingFmt.fourcc & 0xFF,
+ (streamingFmt.fourcc >> 8) & 0xFF, (streamingFmt.fourcc >> 16) & 0xFF,
+ (streamingFmt.fourcc >> 24) & 0xFF, streamingFmt.width, streamingFmt.height,
+ mV4l2StreamingFps);
+
+ size_t numDequeuedV4l2Buffers = 0;
+ {
+ std::lock_guard<std::mutex> lk(mV4l2BufferLock);
+ numDequeuedV4l2Buffers = mNumDequeuedV4l2Buffers;
+ }
+ dprintf(fd, "V4L2 buffer queue size %zu, dequeued %zu\n", v4L2BufferCount,
+ numDequeuedV4l2Buffers);
+ }
+
+ dprintf(fd, "In-flight frames (not sorted):");
+ for (const auto& frameNumber : inflightFrames) {
+ dprintf(fd, "%d, ", frameNumber);
+ }
+ dprintf(fd, "\n");
+ mOutputThread->dump(fd);
+ dprintf(fd, "\n");
+
+ if (intfLocked) {
+ mInterfaceLock.unlock();
+ }
+
+ return STATUS_OK;
+}
+
+// Start ExternalCameraDeviceSession::BufferRequestThread functions
+ExternalCameraDeviceSession::BufferRequestThread::BufferRequestThread(
+ std::weak_ptr<OutputThreadInterface> parent,
+ std::shared_ptr<ICameraDeviceCallback> callbacks)
+ : mParent(parent), mCallbacks(callbacks) {}
+
+int ExternalCameraDeviceSession::BufferRequestThread::requestBufferStart(
+ const std::vector<HalStreamBuffer>& bufReqs) {
+ if (bufReqs.empty()) {
+ ALOGE("%s: bufReqs is empty!", __FUNCTION__);
+ return -1;
+ }
+
+ {
+ std::lock_guard<std::mutex> lk(mLock);
+ if (mRequestingBuffer) {
+ ALOGE("%s: BufferRequestThread does not support more than one concurrent request!",
+ __FUNCTION__);
+ return -1;
+ }
+
+ mBufferReqs = bufReqs;
+ mRequestingBuffer = true;
+ }
+ mRequestCond.notify_one();
+ return 0;
+}
+
+int ExternalCameraDeviceSession::BufferRequestThread::waitForBufferRequestDone(
+ std::vector<HalStreamBuffer>* outBufReqs) {
+ std::unique_lock<std::mutex> lk(mLock);
+ if (!mRequestingBuffer) {
+ ALOGE("%s: no pending buffer request!", __FUNCTION__);
+ return -1;
+ }
+
+ if (mPendingReturnBufferReqs.empty()) {
+ std::chrono::milliseconds timeout = std::chrono::milliseconds(kReqProcTimeoutMs);
+ auto st = mRequestDoneCond.wait_for(lk, timeout);
+ if (st == std::cv_status::timeout) {
+ ALOGE("%s: wait for buffer request finish timeout!", __FUNCTION__);
+ return -1;
+ }
+ }
+ mRequestingBuffer = false;
+ *outBufReqs = std::move(mPendingReturnBufferReqs);
+ mPendingReturnBufferReqs.clear();
+ return 0;
+}
+
+void ExternalCameraDeviceSession::BufferRequestThread::waitForNextRequest() {
+ ATRACE_CALL();
+ std::unique_lock<std::mutex> lk(mLock);
+ int waitTimes = 0;
+ while (mBufferReqs.empty()) {
+ if (exitPending()) {
+ return;
+ }
+ auto timeout = std::chrono::milliseconds(kReqWaitTimeoutMs);
+ auto st = mRequestCond.wait_for(lk, timeout);
+ if (st == std::cv_status::timeout) {
+ waitTimes++;
+ if (waitTimes == kReqWaitTimesWarn) {
+ // BufferRequestThread just wait forever for new buffer request
+ // But it will print some periodic warning indicating it's waiting
+ ALOGV("%s: still waiting for new buffer request", __FUNCTION__);
+ waitTimes = 0;
+ }
+ }
+ }
+
+ // Fill in BufferRequest
+ mHalBufferReqs.resize(mBufferReqs.size());
+ for (size_t i = 0; i < mHalBufferReqs.size(); i++) {
+ mHalBufferReqs[i].streamId = mBufferReqs[i].streamId;
+ mHalBufferReqs[i].numBuffersRequested = 1;
+ }
+}
+
+bool ExternalCameraDeviceSession::BufferRequestThread::threadLoop() {
+ waitForNextRequest();
+ if (exitPending()) {
+ return false;
+ }
+
+ ATRACE_BEGIN("AIDL requestStreamBuffers");
+ BufferRequestStatus status;
+ std::vector<StreamBufferRet> bufRets;
+ ScopedAStatus ret = mCallbacks->requestStreamBuffers(mHalBufferReqs, &bufRets, &status);
+ if (!ret.isOk()) {
+ ALOGE("%s: Transaction error: %d:%d", __FUNCTION__, ret.getExceptionCode(),
+ ret.getServiceSpecificError());
+ return false;
+ }
+
+ std::unique_lock<std::mutex> lk(mLock);
+ if (status == BufferRequestStatus::OK || status == BufferRequestStatus::FAILED_PARTIAL) {
+ if (bufRets.size() != mHalBufferReqs.size()) {
+ ALOGE("%s: expect %zu buffer requests returned, only got %zu", __FUNCTION__,
+ mHalBufferReqs.size(), bufRets.size());
+ return false;
+ }
+
+ auto parent = mParent.lock();
+ if (parent == nullptr) {
+ ALOGE("%s: session has been disconnected!", __FUNCTION__);
+ return false;
+ }
+
+ std::vector<int> importedFences;
+ importedFences.resize(bufRets.size());
+ for (size_t i = 0; i < bufRets.size(); i++) {
+ int streamId = bufRets[i].streamId;
+ switch (bufRets[i].val.getTag()) {
+ case StreamBuffersVal::Tag::error:
+ continue;
+ case StreamBuffersVal::Tag::buffers: {
+ const std::vector<StreamBuffer>& hBufs =
+ bufRets[i].val.get<StreamBuffersVal::Tag::buffers>();
+ if (hBufs.size() != 1) {
+ ALOGE("%s: expect 1 buffer returned, got %zu!", __FUNCTION__, hBufs.size());
+ return false;
+ }
+ const StreamBuffer& hBuf = hBufs[0];
+
+ mBufferReqs[i].bufferId = hBuf.bufferId;
+ // TODO: create a batch import API so we don't need to lock/unlock mCbsLock
+ // repeatedly?
+ lk.unlock();
+ Status s =
+ parent->importBuffer(streamId, hBuf.bufferId, makeFromAidl(hBuf.buffer),
+ /*out*/ &mBufferReqs[i].bufPtr);
+ lk.lock();
+
+ if (s != Status::OK) {
+ ALOGE("%s: stream %d import buffer failed!", __FUNCTION__, streamId);
+ cleanupInflightFences(importedFences, i - 1);
+ return false;
+ }
+ if (!sHandleImporter.importFence(makeFromAidl(hBuf.acquireFence),
+ mBufferReqs[i].acquireFence)) {
+ ALOGE("%s: stream %d import fence failed!", __FUNCTION__, streamId);
+ cleanupInflightFences(importedFences, i - 1);
+ return false;
+ }
+ importedFences[i] = mBufferReqs[i].acquireFence;
+ } break;
+ default:
+ ALOGE("%s: Unknown StreamBuffersVal!", __FUNCTION__);
+ return false;
+ }
+ }
+ } else {
+ ALOGE("%s: requestStreamBuffers call failed!", __FUNCTION__);
+ }
+
+ mPendingReturnBufferReqs = std::move(mBufferReqs);
+ mBufferReqs.clear();
+
+ lk.unlock();
+ mRequestDoneCond.notify_one();
+ return true;
+}
+
+// End ExternalCameraDeviceSession::BufferRequestThread functions
+
+// Start ExternalCameraDeviceSession::OutputThread functions
+
+ExternalCameraDeviceSession::OutputThread::OutputThread(
+ std::weak_ptr<OutputThreadInterface> parent, CroppingType ct,
+ const common::V1_0::helper::CameraMetadata& chars,
+ std::shared_ptr<BufferRequestThread> bufReqThread)
+ : mParent(parent),
+ mCroppingType(ct),
+ mCameraCharacteristics(chars),
+ mBufferRequestThread(bufReqThread) {}
+
+ExternalCameraDeviceSession::OutputThread::~OutputThread() {}
+
+Status ExternalCameraDeviceSession::OutputThread::allocateIntermediateBuffers(
+ const Size& v4lSize, const Size& thumbSize, const std::vector<Stream>& streams,
+ uint32_t blobBufferSize) {
+ std::lock_guard<std::mutex> lk(mBufferLock);
+ if (!mScaledYu12Frames.empty()) {
+ ALOGE("%s: intermediate buffer pool has %zu inflight buffers! (expect 0)", __FUNCTION__,
+ mScaledYu12Frames.size());
+ return Status::INTERNAL_ERROR;
+ }
+
+ // Allocating intermediate YU12 frame
+ if (mYu12Frame == nullptr || mYu12Frame->mWidth != v4lSize.width ||
+ mYu12Frame->mHeight != v4lSize.height) {
+ mYu12Frame.reset();
+ mYu12Frame = std::make_shared<AllocatedFrame>(v4lSize.width, v4lSize.height);
+ int ret = mYu12Frame->allocate(&mYu12FrameLayout);
+ if (ret != 0) {
+ ALOGE("%s: allocating YU12 frame failed!", __FUNCTION__);
+ return Status::INTERNAL_ERROR;
+ }
+ }
+
+ // Allocating intermediate YU12 thumbnail frame
+ if (mYu12ThumbFrame == nullptr || mYu12ThumbFrame->mWidth != thumbSize.width ||
+ mYu12ThumbFrame->mHeight != thumbSize.height) {
+ mYu12ThumbFrame.reset();
+ mYu12ThumbFrame = std::make_shared<AllocatedFrame>(thumbSize.width, thumbSize.height);
+ int ret = mYu12ThumbFrame->allocate(&mYu12ThumbFrameLayout);
+ if (ret != 0) {
+ ALOGE("%s: allocating YU12 thumb frame failed!", __FUNCTION__);
+ return Status::INTERNAL_ERROR;
+ }
+ }
+
+ // Allocating scaled buffers
+ for (const auto& stream : streams) {
+ Size sz = {stream.width, stream.height};
+ if (sz == v4lSize) {
+ continue; // Don't need an intermediate buffer same size as v4lBuffer
+ }
+ if (mIntermediateBuffers.count(sz) == 0) {
+ // Create new intermediate buffer
+ std::shared_ptr<AllocatedFrame> buf =
+ std::make_shared<AllocatedFrame>(stream.width, stream.height);
+ int ret = buf->allocate();
+ if (ret != 0) {
+ ALOGE("%s: allocating intermediate YU12 frame %dx%d failed!", __FUNCTION__,
+ stream.width, stream.height);
+ return Status::INTERNAL_ERROR;
+ }
+ mIntermediateBuffers[sz] = buf;
+ }
+ }
+
+ // Remove unconfigured buffers
+ auto it = mIntermediateBuffers.begin();
+ while (it != mIntermediateBuffers.end()) {
+ bool configured = false;
+ auto sz = it->first;
+ for (const auto& stream : streams) {
+ if (stream.width == sz.width && stream.height == sz.height) {
+ configured = true;
+ break;
+ }
+ }
+ if (configured) {
+ it++;
+ } else {
+ it = mIntermediateBuffers.erase(it);
+ }
+ }
+
+ // Allocate mute test pattern frame
+ mMuteTestPatternFrame.resize(mYu12Frame->mWidth * mYu12Frame->mHeight * 3);
+
+ mBlobBufferSize = blobBufferSize;
+ return Status::OK;
+}
+
+Status ExternalCameraDeviceSession::OutputThread::submitRequest(
+ const std::shared_ptr<HalRequest>& req) {
+ std::unique_lock<std::mutex> lk(mRequestListLock);
+ mRequestList.push_back(req);
+ lk.unlock();
+ mRequestCond.notify_one();
+ return Status::OK;
+}
+
+void ExternalCameraDeviceSession::OutputThread::flush() {
+ ATRACE_CALL();
+ auto parent = mParent.lock();
+ if (parent == nullptr) {
+ ALOGE("%s: session has been disconnected!", __FUNCTION__);
+ return;
+ }
+
+ std::unique_lock<std::mutex> lk(mRequestListLock);
+ std::list<std::shared_ptr<HalRequest>> reqs = std::move(mRequestList);
+ mRequestList.clear();
+ if (mProcessingRequest) {
+ auto timeout = std::chrono::seconds(kFlushWaitTimeoutSec);
+ auto st = mRequestDoneCond.wait_for(lk, timeout);
+ if (st == std::cv_status::timeout) {
+ ALOGE("%s: wait for inflight request finish timeout!", __FUNCTION__);
+ }
+ }
+
+ ALOGV("%s: flushing inflight requests", __FUNCTION__);
+ lk.unlock();
+ for (const auto& req : reqs) {
+ parent->processCaptureRequestError(req);
+ }
+}
+
+void ExternalCameraDeviceSession::OutputThread::dump(int fd) {
+ std::lock_guard<std::mutex> lk(mRequestListLock);
+ if (mProcessingRequest) {
+ dprintf(fd, "OutputThread processing frame %d\n", mProcessingFrameNumber);
+ } else {
+ dprintf(fd, "OutputThread not processing any frames\n");
+ }
+ dprintf(fd, "OutputThread request list contains frame: ");
+ for (const auto& req : mRequestList) {
+ dprintf(fd, "%d, ", req->frameNumber);
+ }
+ dprintf(fd, "\n");
+}
+
+void ExternalCameraDeviceSession::OutputThread::setExifMakeModel(const std::string& make,
+ const std::string& model) {
+ mExifMake = make;
+ mExifModel = model;
+}
+
+std::list<std::shared_ptr<HalRequest>>
+ExternalCameraDeviceSession::OutputThread::switchToOffline() {
+ ATRACE_CALL();
+ auto parent = mParent.lock();
+ if (parent == nullptr) {
+ ALOGE("%s: session has been disconnected!", __FUNCTION__);
+ return {};
+ }
+
+ std::unique_lock<std::mutex> lk(mRequestListLock);
+ std::list<std::shared_ptr<HalRequest>> reqs = std::move(mRequestList);
+ mRequestList.clear();
+ if (mProcessingRequest) {
+ auto timeout = std::chrono::seconds(kFlushWaitTimeoutSec);
+ auto st = mRequestDoneCond.wait_for(lk, timeout);
+ if (st == std::cv_status::timeout) {
+ ALOGE("%s: wait for inflight request finish timeout!", __FUNCTION__);
+ }
+ }
+ lk.unlock();
+ clearIntermediateBuffers();
+ ALOGV("%s: returning %zu request for offline processing", __FUNCTION__, reqs.size());
+ return reqs;
+}
+
+int ExternalCameraDeviceSession::OutputThread::requestBufferStart(
+ const std::vector<HalStreamBuffer>& bufs) {
+ if (mBufferRequestThread == nullptr) {
+ return 0;
+ }
+ return mBufferRequestThread->requestBufferStart(bufs);
+}
+
+int ExternalCameraDeviceSession::OutputThread::waitForBufferRequestDone(
+ std::vector<HalStreamBuffer>* outBufs) {
+ if (mBufferRequestThread == nullptr) {
+ return 0;
+ }
+ return mBufferRequestThread->waitForBufferRequestDone(outBufs);
+}
+
+void ExternalCameraDeviceSession::OutputThread::waitForNextRequest(
+ std::shared_ptr<HalRequest>* out) {
+ ATRACE_CALL();
+ if (out == nullptr) {
+ ALOGE("%s: out is null", __FUNCTION__);
+ return;
+ }
+
+ std::unique_lock<std::mutex> lk(mRequestListLock);
+ int waitTimes = 0;
+ while (mRequestList.empty()) {
+ if (exitPending()) {
+ return;
+ }
+ auto timeout = std::chrono::milliseconds(kReqWaitTimeoutMs);
+ auto st = mRequestCond.wait_for(lk, timeout);
+ if (st == std::cv_status::timeout) {
+ waitTimes++;
+ if (waitTimes == kReqWaitTimesMax) {
+ // no new request, return
+ return;
+ }
+ }
+ }
+ *out = mRequestList.front();
+ mRequestList.pop_front();
+ mProcessingRequest = true;
+ mProcessingFrameNumber = (*out)->frameNumber;
+}
+
+void ExternalCameraDeviceSession::OutputThread::signalRequestDone() {
+ std::unique_lock<std::mutex> lk(mRequestListLock);
+ mProcessingRequest = false;
+ mProcessingFrameNumber = 0;
+ lk.unlock();
+ mRequestDoneCond.notify_one();
+}
+
+int ExternalCameraDeviceSession::OutputThread::cropAndScaleLocked(
+ std::shared_ptr<AllocatedFrame>& in, const Size& outSz, YCbCrLayout* out) {
+ Size inSz = {in->mWidth, in->mHeight};
+
+ int ret;
+ if (inSz == outSz) {
+ ret = in->getLayout(out);
+ if (ret != 0) {
+ ALOGE("%s: failed to get input image layout", __FUNCTION__);
+ return ret;
+ }
+ return ret;
+ }
+
+ // Cropping to output aspect ratio
+ IMapper::Rect inputCrop;
+ ret = getCropRect(mCroppingType, inSz, outSz, &inputCrop);
+ if (ret != 0) {
+ ALOGE("%s: failed to compute crop rect for output size %dx%d", __FUNCTION__, outSz.width,
+ outSz.height);
+ return ret;
+ }
+
+ YCbCrLayout croppedLayout;
+ ret = in->getCroppedLayout(inputCrop, &croppedLayout);
+ if (ret != 0) {
+ ALOGE("%s: failed to crop input image %dx%d to output size %dx%d", __FUNCTION__, inSz.width,
+ inSz.height, outSz.width, outSz.height);
+ return ret;
+ }
+
+ if ((mCroppingType == VERTICAL && inSz.width == outSz.width) ||
+ (mCroppingType == HORIZONTAL && inSz.height == outSz.height)) {
+ // No scale is needed
+ *out = croppedLayout;
+ return 0;
+ }
+
+ auto it = mScaledYu12Frames.find(outSz);
+ std::shared_ptr<AllocatedFrame> scaledYu12Buf;
+ if (it != mScaledYu12Frames.end()) {
+ scaledYu12Buf = it->second;
+ } else {
+ it = mIntermediateBuffers.find(outSz);
+ if (it == mIntermediateBuffers.end()) {
+ ALOGE("%s: failed to find intermediate buffer size %dx%d", __FUNCTION__, outSz.width,
+ outSz.height);
+ return -1;
+ }
+ scaledYu12Buf = it->second;
+ }
+ // Scale
+ YCbCrLayout outLayout;
+ ret = scaledYu12Buf->getLayout(&outLayout);
+ if (ret != 0) {
+ ALOGE("%s: failed to get output buffer layout", __FUNCTION__);
+ return ret;
+ }
+
+ ret = libyuv::I420Scale(
+ static_cast<uint8_t*>(croppedLayout.y), croppedLayout.yStride,
+ static_cast<uint8_t*>(croppedLayout.cb), croppedLayout.cStride,
+ static_cast<uint8_t*>(croppedLayout.cr), croppedLayout.cStride, inputCrop.width,
+ inputCrop.height, static_cast<uint8_t*>(outLayout.y), outLayout.yStride,
+ static_cast<uint8_t*>(outLayout.cb), outLayout.cStride,
+ static_cast<uint8_t*>(outLayout.cr), outLayout.cStride, outSz.width, outSz.height,
+ // TODO: b/72261744 see if we can use better filter without losing too much perf
+ libyuv::FilterMode::kFilterNone);
+
+ if (ret != 0) {
+ ALOGE("%s: failed to scale buffer from %dx%d to %dx%d. Ret %d", __FUNCTION__,
+ inputCrop.width, inputCrop.height, outSz.width, outSz.height, ret);
+ return ret;
+ }
+
+ *out = outLayout;
+ mScaledYu12Frames.insert({outSz, scaledYu12Buf});
+ return 0;
+}
+
+int ExternalCameraDeviceSession::OutputThread::cropAndScaleThumbLocked(
+ std::shared_ptr<AllocatedFrame>& in, const Size& outSz, YCbCrLayout* out) {
+ Size inSz{in->mWidth, in->mHeight};
+
+ if ((outSz.width * outSz.height) > (mYu12ThumbFrame->mWidth * mYu12ThumbFrame->mHeight)) {
+ ALOGE("%s: Requested thumbnail size too big (%d,%d) > (%d,%d)", __FUNCTION__, outSz.width,
+ outSz.height, mYu12ThumbFrame->mWidth, mYu12ThumbFrame->mHeight);
+ return -1;
+ }
+
+ int ret;
+
+ /* This will crop-and-zoom the input YUV frame to the thumbnail size
+ * Based on the following logic:
+ * 1) Square pixels come in, square pixels come out, therefore single
+ * scale factor is computed to either make input bigger or smaller
+ * depending on if we are upscaling or downscaling
+ * 2) That single scale factor would either make height too tall or width
+ * too wide so we need to crop the input either horizontally or vertically
+ * but not both
+ */
+
+ /* Convert the input and output dimensions into floats for ease of math */
+ float fWin = static_cast<float>(inSz.width);
+ float fHin = static_cast<float>(inSz.height);
+ float fWout = static_cast<float>(outSz.width);
+ float fHout = static_cast<float>(outSz.height);
+
+ /* Compute the one scale factor from (1) above, it will be the smaller of
+ * the two possibilities. */
+ float scaleFactor = std::min(fHin / fHout, fWin / fWout);
+
+ /* Since we are crop-and-zooming (as opposed to letter/pillar boxing) we can
+ * simply multiply the output by our scaleFactor to get the cropped input
+ * size. Note that at least one of {fWcrop, fHcrop} is going to wind up
+ * being {fWin, fHin} respectively because fHout or fWout cancels out the
+ * scaleFactor calculation above.
+ *
+ * Specifically:
+ * if ( fHin / fHout ) < ( fWin / fWout ) we crop the sides off
+ * input, in which case
+ * scaleFactor = fHin / fHout
+ * fWcrop = fHin / fHout * fWout
+ * fHcrop = fHin
+ *
+ * Note that fWcrop <= fWin ( because ( fHin / fHout ) * fWout < fWin, which
+ * is just the inequality above with both sides multiplied by fWout
+ *
+ * on the other hand if ( fWin / fWout ) < ( fHin / fHout) we crop the top
+ * and the bottom off of input, and
+ * scaleFactor = fWin / fWout
+ * fWcrop = fWin
+ * fHCrop = fWin / fWout * fHout
+ */
+ float fWcrop = scaleFactor * fWout;
+ float fHcrop = scaleFactor * fHout;
+
+ /* Convert to integer and truncate to an even number */
+ Size cropSz = {.width = 2 * static_cast<int32_t>(fWcrop / 2.0f),
+ .height = 2 * static_cast<int32_t>(fHcrop / 2.0f)};
+
+ /* Convert to a centered rectange with even top/left */
+ IMapper::Rect inputCrop{.left = 2 * static_cast<int32_t>((inSz.width - cropSz.width) / 4),
+ .top = 2 * static_cast<int32_t>((inSz.height - cropSz.height) / 4),
+ .width = static_cast<int32_t>(cropSz.width),
+ .height = static_cast<int32_t>(cropSz.height)};
+
+ if ((inputCrop.top < 0) || (inputCrop.top >= static_cast<int32_t>(inSz.height)) ||
+ (inputCrop.left < 0) || (inputCrop.left >= static_cast<int32_t>(inSz.width)) ||
+ (inputCrop.width <= 0) ||
+ (inputCrop.width + inputCrop.left > static_cast<int32_t>(inSz.width)) ||
+ (inputCrop.height <= 0) ||
+ (inputCrop.height + inputCrop.top > static_cast<int32_t>(inSz.height))) {
+ ALOGE("%s: came up with really wrong crop rectangle", __FUNCTION__);
+ ALOGE("%s: input layout %dx%d to for output size %dx%d", __FUNCTION__, inSz.width,
+ inSz.height, outSz.width, outSz.height);
+ ALOGE("%s: computed input crop +%d,+%d %dx%d", __FUNCTION__, inputCrop.left, inputCrop.top,
+ inputCrop.width, inputCrop.height);
+ return -1;
+ }
+
+ YCbCrLayout inputLayout;
+ ret = in->getCroppedLayout(inputCrop, &inputLayout);
+ if (ret != 0) {
+ ALOGE("%s: failed to crop input layout %dx%d to for output size %dx%d", __FUNCTION__,
+ inSz.width, inSz.height, outSz.width, outSz.height);
+ ALOGE("%s: computed input crop +%d,+%d %dx%d", __FUNCTION__, inputCrop.left, inputCrop.top,
+ inputCrop.width, inputCrop.height);
+ return ret;
+ }
+ ALOGV("%s: crop input layout %dx%d to for output size %dx%d", __FUNCTION__, inSz.width,
+ inSz.height, outSz.width, outSz.height);
+ ALOGV("%s: computed input crop +%d,+%d %dx%d", __FUNCTION__, inputCrop.left, inputCrop.top,
+ inputCrop.width, inputCrop.height);
+
+ // Scale
+ YCbCrLayout outFullLayout;
+
+ ret = mYu12ThumbFrame->getLayout(&outFullLayout);
+ if (ret != 0) {
+ ALOGE("%s: failed to get output buffer layout", __FUNCTION__);
+ return ret;
+ }
+
+ ret = libyuv::I420Scale(static_cast<uint8_t*>(inputLayout.y), inputLayout.yStride,
+ static_cast<uint8_t*>(inputLayout.cb), inputLayout.cStride,
+ static_cast<uint8_t*>(inputLayout.cr), inputLayout.cStride,
+ inputCrop.width, inputCrop.height,
+ static_cast<uint8_t*>(outFullLayout.y), outFullLayout.yStride,
+ static_cast<uint8_t*>(outFullLayout.cb), outFullLayout.cStride,
+ static_cast<uint8_t*>(outFullLayout.cr), outFullLayout.cStride,
+ outSz.width, outSz.height, libyuv::FilterMode::kFilterNone);
+
+ if (ret != 0) {
+ ALOGE("%s: failed to scale buffer from %dx%d to %dx%d. Ret %d", __FUNCTION__,
+ inputCrop.width, inputCrop.height, outSz.width, outSz.height, ret);
+ return ret;
+ }
+
+ *out = outFullLayout;
+ return 0;
+}
+
+int ExternalCameraDeviceSession::OutputThread::createJpegLocked(
+ HalStreamBuffer& halBuf, const common::V1_0::helper::CameraMetadata& setting) {
+ ATRACE_CALL();
+ int ret;
+ auto lfail = [&](auto... args) {
+ ALOGE(args...);
+
+ return 1;
+ };
+ auto parent = mParent.lock();
+ if (parent == nullptr) {
+ ALOGE("%s: session has been disconnected!", __FUNCTION__);
+ return 1;
+ }
+
+ ALOGV("%s: HAL buffer sid: %d bid: %" PRIu64 " w: %u h: %u", __FUNCTION__, halBuf.streamId,
+ static_cast<uint64_t>(halBuf.bufferId), halBuf.width, halBuf.height);
+ ALOGV("%s: HAL buffer fmt: %x usage: %" PRIx64 " ptr: %p", __FUNCTION__, halBuf.format,
+ static_cast<uint64_t>(halBuf.usage), halBuf.bufPtr);
+ ALOGV("%s: YV12 buffer %d x %d", __FUNCTION__, mYu12Frame->mWidth, mYu12Frame->mHeight);
+
+ int jpegQuality, thumbQuality;
+ Size thumbSize;
+ bool outputThumbnail = true;
+
+ if (setting.exists(ANDROID_JPEG_QUALITY)) {
+ camera_metadata_ro_entry entry = setting.find(ANDROID_JPEG_QUALITY);
+ jpegQuality = entry.data.u8[0];
+ } else {
+ return lfail("%s: ANDROID_JPEG_QUALITY not set", __FUNCTION__);
+ }
+
+ if (setting.exists(ANDROID_JPEG_THUMBNAIL_QUALITY)) {
+ camera_metadata_ro_entry entry = setting.find(ANDROID_JPEG_THUMBNAIL_QUALITY);
+ thumbQuality = entry.data.u8[0];
+ } else {
+ return lfail("%s: ANDROID_JPEG_THUMBNAIL_QUALITY not set", __FUNCTION__);
+ }
+
+ if (setting.exists(ANDROID_JPEG_THUMBNAIL_SIZE)) {
+ camera_metadata_ro_entry entry = setting.find(ANDROID_JPEG_THUMBNAIL_SIZE);
+ thumbSize = Size{.width = entry.data.i32[0], .height = entry.data.i32[1]};
+ if (thumbSize.width == 0 && thumbSize.height == 0) {
+ outputThumbnail = false;
+ }
+ } else {
+ return lfail("%s: ANDROID_JPEG_THUMBNAIL_SIZE not set", __FUNCTION__);
+ }
+
+ /* Cropped and scaled YU12 buffer for main and thumbnail */
+ YCbCrLayout yu12Main;
+ Size jpegSize{halBuf.width, halBuf.height};
+
+ /* Compute temporary buffer sizes accounting for the following:
+ * thumbnail can't exceed APP1 size of 64K
+ * main image needs to hold APP1, headers, and at most a poorly
+ * compressed image */
+ const ssize_t maxThumbCodeSize = 64 * 1024;
+ const ssize_t maxJpegCodeSize =
+ mBlobBufferSize == 0 ? parent->getJpegBufferSize(jpegSize.width, jpegSize.height)
+ : mBlobBufferSize;
+
+ /* Check that getJpegBufferSize did not return an error */
+ if (maxJpegCodeSize < 0) {
+ return lfail("%s: getJpegBufferSize returned %zd", __FUNCTION__, maxJpegCodeSize);
+ }
+
+ /* Hold actual thumbnail and main image code sizes */
+ size_t thumbCodeSize = 0, jpegCodeSize = 0;
+ /* Temporary thumbnail code buffer */
+ std::vector<uint8_t> thumbCode(outputThumbnail ? maxThumbCodeSize : 0);
+
+ YCbCrLayout yu12Thumb;
+ if (outputThumbnail) {
+ ret = cropAndScaleThumbLocked(mYu12Frame, thumbSize, &yu12Thumb);
+
+ if (ret != 0) {
+ return lfail("%s: crop and scale thumbnail failed!", __FUNCTION__);
+ }
+ }
+
+ /* Scale and crop main jpeg */
+ ret = cropAndScaleLocked(mYu12Frame, jpegSize, &yu12Main);
+
+ if (ret != 0) {
+ return lfail("%s: crop and scale main failed!", __FUNCTION__);
+ }
+
+ /* Encode the thumbnail image */
+ if (outputThumbnail) {
+ ret = encodeJpegYU12(thumbSize, yu12Thumb, thumbQuality, 0, 0, &thumbCode[0],
+ maxThumbCodeSize, thumbCodeSize);
+
+ if (ret != 0) {
+ return lfail("%s: thumbnail encodeJpegYU12 failed with %d", __FUNCTION__, ret);
+ }
+ }
+
+ /* Combine camera characteristics with request settings to form EXIF
+ * metadata */
+ common::V1_0::helper::CameraMetadata meta(mCameraCharacteristics);
+ meta.append(setting);
+
+ /* Generate EXIF object */
+ std::unique_ptr<ExifUtils> utils(ExifUtils::create());
+ /* Make sure it's initialized */
+ utils->initialize();
+
+ utils->setFromMetadata(meta, jpegSize.width, jpegSize.height);
+ utils->setMake(mExifMake);
+ utils->setModel(mExifModel);
+
+ ret = utils->generateApp1(outputThumbnail ? &thumbCode[0] : nullptr, thumbCodeSize);
+
+ if (!ret) {
+ return lfail("%s: generating APP1 failed", __FUNCTION__);
+ }
+
+ /* Get internal buffer */
+ size_t exifDataSize = utils->getApp1Length();
+ const uint8_t* exifData = utils->getApp1Buffer();
+
+ /* Lock the HAL jpeg code buffer */
+ void* bufPtr = sHandleImporter.lock(*(halBuf.bufPtr), static_cast<uint64_t>(halBuf.usage),
+ maxJpegCodeSize);
+
+ if (!bufPtr) {
+ return lfail("%s: could not lock %zu bytes", __FUNCTION__, maxJpegCodeSize);
+ }
+
+ /* Encode the main jpeg image */
+ ret = encodeJpegYU12(jpegSize, yu12Main, jpegQuality, exifData, exifDataSize, bufPtr,
+ maxJpegCodeSize, jpegCodeSize);
+
+ /* TODO: Not sure this belongs here, maybe better to pass jpegCodeSize out
+ * and do this when returning buffer to parent */
+ CameraBlob blob{CameraBlobId::JPEG, static_cast<int32_t>(jpegCodeSize)};
+ void* blobDst = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(bufPtr) + maxJpegCodeSize -
+ sizeof(CameraBlob));
+ memcpy(blobDst, &blob, sizeof(CameraBlob));
+
+ /* Unlock the HAL jpeg code buffer */
+ int relFence = sHandleImporter.unlock(*(halBuf.bufPtr));
+ if (relFence >= 0) {
+ halBuf.acquireFence = relFence;
+ }
+
+ /* Check if our JPEG actually succeeded */
+ if (ret != 0) {
+ return lfail("%s: encodeJpegYU12 failed with %d", __FUNCTION__, ret);
+ }
+
+ ALOGV("%s: encoded JPEG (ret:%d) with Q:%d max size: %zu", __FUNCTION__, ret, jpegQuality,
+ maxJpegCodeSize);
+
+ return 0;
+}
+
+void ExternalCameraDeviceSession::OutputThread::clearIntermediateBuffers() {
+ std::lock_guard<std::mutex> lk(mBufferLock);
+ mYu12Frame.reset();
+ mYu12ThumbFrame.reset();
+ mIntermediateBuffers.clear();
+ mMuteTestPatternFrame.clear();
+ mBlobBufferSize = 0;
+}
+
+bool ExternalCameraDeviceSession::OutputThread::threadLoop() {
+ std::shared_ptr<HalRequest> req;
+ auto parent = mParent.lock();
+ if (parent == nullptr) {
+ ALOGE("%s: session has been disconnected!", __FUNCTION__);
+ return false;
+ }
+
+ // TODO: maybe we need to setup a sensor thread to dq/enq v4l frames
+ // regularly to prevent v4l buffer queue filled with stale buffers
+ // when app doesn't program a preview request
+ waitForNextRequest(&req);
+ if (req == nullptr) {
+ // No new request, wait again
+ return true;
+ }
+
+ auto onDeviceError = [&](auto... args) {
+ ALOGE(args...);
+ parent->notifyError(req->frameNumber, /*stream*/ -1, ErrorCode::ERROR_DEVICE);
+ signalRequestDone();
+ return false;
+ };
+
+ if (req->frameIn->mFourcc != V4L2_PIX_FMT_MJPEG && req->frameIn->mFourcc != V4L2_PIX_FMT_Z16) {
+ return onDeviceError("%s: do not support V4L2 format %c%c%c%c", __FUNCTION__,
+ req->frameIn->mFourcc & 0xFF, (req->frameIn->mFourcc >> 8) & 0xFF,
+ (req->frameIn->mFourcc >> 16) & 0xFF,
+ (req->frameIn->mFourcc >> 24) & 0xFF);
+ }
+
+ int res = requestBufferStart(req->buffers);
+ if (res != 0) {
+ ALOGE("%s: send BufferRequest failed! res %d", __FUNCTION__, res);
+ return onDeviceError("%s: failed to send buffer request!", __FUNCTION__);
+ }
+
+ std::unique_lock<std::mutex> lk(mBufferLock);
+ // Convert input V4L2 frame to YU12 of the same size
+ // TODO: see if we can save some computation by converting to YV12 here
+ uint8_t* inData;
+ size_t inDataSize;
+ if (req->frameIn->getData(&inData, &inDataSize) != 0) {
+ lk.unlock();
+ return onDeviceError("%s: V4L2 buffer map failed", __FUNCTION__);
+ }
+
+ // Process camera mute state
+ auto testPatternMode = req->setting.find(ANDROID_SENSOR_TEST_PATTERN_MODE);
+ if (testPatternMode.count == 1) {
+ if (mCameraMuted != (testPatternMode.data.u8[0] != ANDROID_SENSOR_TEST_PATTERN_MODE_OFF)) {
+ mCameraMuted = !mCameraMuted;
+ // Get solid color for test pattern, if any was set
+ if (testPatternMode.data.u8[0] == ANDROID_SENSOR_TEST_PATTERN_MODE_SOLID_COLOR) {
+ auto entry = req->setting.find(ANDROID_SENSOR_TEST_PATTERN_DATA);
+ if (entry.count == 4) {
+ // Update the mute frame if the pattern color has changed
+ if (memcmp(entry.data.i32, mTestPatternData, sizeof(mTestPatternData)) != 0) {
+ memcpy(mTestPatternData, entry.data.i32, sizeof(mTestPatternData));
+ // Fill the mute frame with the solid color, use only 8 MSB of RGGB as RGB
+ for (int i = 0; i < mMuteTestPatternFrame.size(); i += 3) {
+ mMuteTestPatternFrame[i] = entry.data.i32[0] >> 24;
+ mMuteTestPatternFrame[i + 1] = entry.data.i32[1] >> 24;
+ mMuteTestPatternFrame[i + 2] = entry.data.i32[3] >> 24;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // TODO: in some special case maybe we can decode jpg directly to gralloc output?
+ if (req->frameIn->mFourcc == V4L2_PIX_FMT_MJPEG) {
+ ATRACE_BEGIN("MJPGtoI420");
+ res = 0;
+ if (mCameraMuted) {
+ res = libyuv::ConvertToI420(
+ mMuteTestPatternFrame.data(), mMuteTestPatternFrame.size(),
+ static_cast<uint8_t*>(mYu12FrameLayout.y), mYu12FrameLayout.yStride,
+ static_cast<uint8_t*>(mYu12FrameLayout.cb), mYu12FrameLayout.cStride,
+ static_cast<uint8_t*>(mYu12FrameLayout.cr), mYu12FrameLayout.cStride, 0, 0,
+ mYu12Frame->mWidth, mYu12Frame->mHeight, mYu12Frame->mWidth,
+ mYu12Frame->mHeight, libyuv::kRotate0, libyuv::FOURCC_RAW);
+ } else {
+ res = libyuv::MJPGToI420(
+ inData, inDataSize, static_cast<uint8_t*>(mYu12FrameLayout.y),
+ mYu12FrameLayout.yStride, static_cast<uint8_t*>(mYu12FrameLayout.cb),
+ mYu12FrameLayout.cStride, static_cast<uint8_t*>(mYu12FrameLayout.cr),
+ mYu12FrameLayout.cStride, mYu12Frame->mWidth, mYu12Frame->mHeight,
+ mYu12Frame->mWidth, mYu12Frame->mHeight);
+ }
+ ATRACE_END();
+
+ if (res != 0) {
+ // For some webcam, the first few V4L2 frames might be malformed...
+ ALOGE("%s: Convert V4L2 frame to YU12 failed! res %d", __FUNCTION__, res);
+ lk.unlock();
+ Status st = parent->processCaptureRequestError(req);
+ if (st != Status::OK) {
+ return onDeviceError("%s: failed to process capture request error!", __FUNCTION__);
+ }
+ signalRequestDone();
+ return true;
+ }
+ }
+
+ ATRACE_BEGIN("Wait for BufferRequest done");
+ res = waitForBufferRequestDone(&req->buffers);
+ ATRACE_END();
+
+ if (res != 0) {
+ ALOGE("%s: wait for BufferRequest done failed! res %d", __FUNCTION__, res);
+ lk.unlock();
+ return onDeviceError("%s: failed to process buffer request error!", __FUNCTION__);
+ }
+
+ ALOGV("%s processing new request", __FUNCTION__);
+ const int kSyncWaitTimeoutMs = 500;
+ for (auto& halBuf : req->buffers) {
+ if (*(halBuf.bufPtr) == nullptr) {
+ ALOGW("%s: buffer for stream %d missing", __FUNCTION__, halBuf.streamId);
+ halBuf.fenceTimeout = true;
+ } else if (halBuf.acquireFence >= 0) {
+ int ret = sync_wait(halBuf.acquireFence, kSyncWaitTimeoutMs);
+ if (ret) {
+ halBuf.fenceTimeout = true;
+ } else {
+ ::close(halBuf.acquireFence);
+ halBuf.acquireFence = -1;
+ }
+ }
+
+ if (halBuf.fenceTimeout) {
+ continue;
+ }
+
+ // Gralloc lockYCbCr the buffer
+ switch (halBuf.format) {
+ case PixelFormat::BLOB: {
+ int ret = createJpegLocked(halBuf, req->setting);
+
+ if (ret != 0) {
+ lk.unlock();
+ return onDeviceError("%s: createJpegLocked failed with %d", __FUNCTION__, ret);
+ }
+ } break;
+ case PixelFormat::Y16: {
+ void* outLayout = sHandleImporter.lock(
+ *(halBuf.bufPtr), static_cast<uint64_t>(halBuf.usage), inDataSize);
+
+ std::memcpy(outLayout, inData, inDataSize);
+
+ int relFence = sHandleImporter.unlock(*(halBuf.bufPtr));
+ if (relFence >= 0) {
+ halBuf.acquireFence = relFence;
+ }
+ } break;
+ case PixelFormat::YCBCR_420_888:
+ case PixelFormat::YV12: {
+ IMapper::Rect outRect{0, 0, static_cast<int32_t>(halBuf.width),
+ static_cast<int32_t>(halBuf.height)};
+ YCbCrLayout outLayout = sHandleImporter.lockYCbCr(
+ *(halBuf.bufPtr), static_cast<uint64_t>(halBuf.usage), outRect);
+ ALOGV("%s: outLayout y %p cb %p cr %p y_str %d c_str %d c_step %d", __FUNCTION__,
+ outLayout.y, outLayout.cb, outLayout.cr, outLayout.yStride, outLayout.cStride,
+ outLayout.chromaStep);
+
+ // Convert to output buffer size/format
+ uint32_t outputFourcc = getFourCcFromLayout(outLayout);
+ ALOGV("%s: converting to format %c%c%c%c", __FUNCTION__, outputFourcc & 0xFF,
+ (outputFourcc >> 8) & 0xFF, (outputFourcc >> 16) & 0xFF,
+ (outputFourcc >> 24) & 0xFF);
+
+ YCbCrLayout cropAndScaled;
+ ATRACE_BEGIN("cropAndScaleLocked");
+ int ret = cropAndScaleLocked(mYu12Frame, Size{halBuf.width, halBuf.height},
+ &cropAndScaled);
+ ATRACE_END();
+ if (ret != 0) {
+ lk.unlock();
+ return onDeviceError("%s: crop and scale failed!", __FUNCTION__);
+ }
+
+ Size sz{halBuf.width, halBuf.height};
+ ATRACE_BEGIN("formatConvert");
+ ret = formatConvert(cropAndScaled, outLayout, sz, outputFourcc);
+ ATRACE_END();
+ if (ret != 0) {
+ lk.unlock();
+ return onDeviceError("%s: format conversion failed!", __FUNCTION__);
+ }
+ int relFence = sHandleImporter.unlock(*(halBuf.bufPtr));
+ if (relFence >= 0) {
+ halBuf.acquireFence = relFence;
+ }
+ } break;
+ default:
+ lk.unlock();
+ return onDeviceError("%s: unknown output format %x", __FUNCTION__, halBuf.format);
+ }
+ } // for each buffer
+ mScaledYu12Frames.clear();
+
+ // Don't hold the lock while calling back to parent
+ lk.unlock();
+ Status st = parent->processCaptureResult(req);
+ if (st != Status::OK) {
+ return onDeviceError("%s: failed to process capture result!", __FUNCTION__);
+ }
+ signalRequestDone();
+ return true;
+}
+
+// End ExternalCameraDeviceSession::OutputThread functions
+
+} // namespace implementation
+} // namespace device
+} // namespace camera
+} // namespace hardware
+} // namespace android
diff --git a/camera/device/default/ExternalCameraDeviceSession.h b/camera/device/default/ExternalCameraDeviceSession.h
new file mode 100644
index 0000000..5d42092
--- /dev/null
+++ b/camera/device/default/ExternalCameraDeviceSession.h
@@ -0,0 +1,399 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HARDWARE_INTERFACES_CAMERA_DEVICE_DEFAULT_EXTERNALCAMERADEVICESESSION_H_
+#define HARDWARE_INTERFACES_CAMERA_DEVICE_DEFAULT_EXTERNALCAMERADEVICESESSION_H_
+
+#include <ExternalCameraUtils.h>
+#include <SimpleThread.h>
+#include <aidl/android/hardware/camera/common/Status.h>
+#include <aidl/android/hardware/camera/device/BnCameraDeviceSession.h>
+#include <aidl/android/hardware/camera/device/BufferRequest.h>
+#include <aidl/android/hardware/camera/device/Stream.h>
+#include <android-base/unique_fd.h>
+#include <fmq/AidlMessageQueue.h>
+#include <utils/Thread.h>
+#include <deque>
+#include <list>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace implementation {
+
+using ::aidl::android::hardware::camera::common::Status;
+using ::aidl::android::hardware::camera::device::BnCameraDeviceSession;
+using ::aidl::android::hardware::camera::device::BufferCache;
+using ::aidl::android::hardware::camera::device::BufferRequest;
+using ::aidl::android::hardware::camera::device::CameraMetadata;
+using ::aidl::android::hardware::camera::device::CameraOfflineSessionInfo;
+using ::aidl::android::hardware::camera::device::CaptureRequest;
+using ::aidl::android::hardware::camera::device::HalStream;
+using ::aidl::android::hardware::camera::device::ICameraDeviceCallback;
+using ::aidl::android::hardware::camera::device::ICameraOfflineSession;
+using ::aidl::android::hardware::camera::device::RequestTemplate;
+using ::aidl::android::hardware::camera::device::Stream;
+using ::aidl::android::hardware::camera::device::StreamConfiguration;
+using ::aidl::android::hardware::common::fmq::MQDescriptor;
+using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using ::android::AidlMessageQueue;
+using ::android::base::unique_fd;
+using ::android::hardware::camera::common::helper::SimpleThread;
+using ::android::hardware::camera::external::common::ExternalCameraConfig;
+using ::android::hardware::camera::external::common::SizeHasher;
+using ::ndk::ScopedAStatus;
+
+class ExternalCameraDeviceSession : public BnCameraDeviceSession, public OutputThreadInterface {
+ public:
+ ExternalCameraDeviceSession(const std::shared_ptr<ICameraDeviceCallback>&,
+ const ExternalCameraConfig& cfg,
+ const std::vector<SupportedV4L2Format>& sortedFormats,
+ const CroppingType& croppingType,
+ const common::V1_0::helper::CameraMetadata& chars,
+ const std::string& cameraId, unique_fd v4l2Fd);
+ ~ExternalCameraDeviceSession() override;
+
+ // Caller must use this method to check if CameraDeviceSession ctor failed
+ bool isInitFailed();
+ bool isClosed();
+
+ ScopedAStatus close() override;
+
+ ScopedAStatus configureStreams(const StreamConfiguration& in_requestedConfiguration,
+ std::vector<HalStream>* _aidl_return) override;
+ ScopedAStatus constructDefaultRequestSettings(RequestTemplate in_type,
+ CameraMetadata* _aidl_return) override;
+ ScopedAStatus flush() override;
+ ScopedAStatus getCaptureRequestMetadataQueue(
+ MQDescriptor<int8_t, SynchronizedReadWrite>* _aidl_return) override;
+ ScopedAStatus getCaptureResultMetadataQueue(
+ MQDescriptor<int8_t, SynchronizedReadWrite>* _aidl_return) override;
+ ScopedAStatus isReconfigurationRequired(const CameraMetadata& in_oldSessionParams,
+ const CameraMetadata& in_newSessionParams,
+ bool* _aidl_return) override;
+ ScopedAStatus processCaptureRequest(const std::vector<CaptureRequest>& in_requests,
+ const std::vector<BufferCache>& in_cachesToRemove,
+ int32_t* _aidl_return) override;
+ ScopedAStatus signalStreamFlush(const std::vector<int32_t>& in_streamIds,
+ int32_t in_streamConfigCounter) override;
+ ScopedAStatus switchToOffline(const std::vector<int32_t>& in_streamsToKeep,
+ CameraOfflineSessionInfo* out_offlineSessionInfo,
+ std::shared_ptr<ICameraOfflineSession>* _aidl_return) override;
+ ScopedAStatus repeatingRequestEnd(int32_t in_frameNumber,
+ const std::vector<int32_t>& in_streamIds) override;
+
+ Status importBuffer(int32_t streamId, uint64_t bufId, buffer_handle_t buf,
+ buffer_handle_t** outBufPtr) override;
+
+ void notifyError(int32_t frameNumber, int32_t streamId, ErrorCode ec) override;
+
+ Status processCaptureRequestError(const std::shared_ptr<HalRequest>& ptr,
+ std::vector<NotifyMsg>* msgs,
+ std::vector<CaptureResult>* results) override;
+
+ Status processCaptureResult(std::shared_ptr<HalRequest>& ptr) override;
+ ssize_t getJpegBufferSize(int32_t width, int32_t height) const override;
+
+ // Called by CameraDevice to dump active device states
+ binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
+
+ static Status isStreamCombinationSupported(
+ const StreamConfiguration& config,
+ const std::vector<SupportedV4L2Format>& supportedFormats,
+ const ExternalCameraConfig& devCfg);
+
+ static const int kMaxProcessedStream = 2;
+ static const int kMaxStallStream = 1;
+ static const uint32_t kMaxBytesPerPixel = 2;
+
+ class BufferRequestThread : public SimpleThread {
+ public:
+ BufferRequestThread(std::weak_ptr<OutputThreadInterface> parent,
+ std::shared_ptr<ICameraDeviceCallback> callbacks);
+
+ int requestBufferStart(const std::vector<HalStreamBuffer>&);
+ int waitForBufferRequestDone(
+ /*out*/ std::vector<HalStreamBuffer>*);
+
+ bool threadLoop() override;
+
+ private:
+ void waitForNextRequest();
+
+ const std::weak_ptr<OutputThreadInterface> mParent;
+ const std::shared_ptr<ICameraDeviceCallback> mCallbacks;
+
+ std::mutex mLock;
+ bool mRequestingBuffer = false;
+
+ std::vector<HalStreamBuffer> mBufferReqs;
+ std::vector<HalStreamBuffer> mPendingReturnBufferReqs;
+ // mHalBufferReqs is not under mLock protection during the HIDL transaction
+ std::vector<BufferRequest> mHalBufferReqs;
+
+ // request buffers takes much less time in steady state, but can take much longer
+ // when requesting 1st buffer from a stream.
+ // TODO: consider a separate timeout for new vs. steady state?
+ // TODO: or make sure framework is warming up the pipeline during configure new stream?
+ static const int kReqProcTimeoutMs = 66;
+
+ static const int kReqWaitTimeoutMs = 33;
+ static const int kReqWaitTimesWarn = 90; // 33ms * 90 ~= 3 sec
+ std::condition_variable mRequestCond; // signaled when a new buffer request incoming
+ std::condition_variable mRequestDoneCond; // signaled when a request is done
+ };
+
+ class OutputThread : public SimpleThread {
+ public:
+ OutputThread(std::weak_ptr<OutputThreadInterface> parent, CroppingType,
+ const common::V1_0::helper::CameraMetadata&,
+ std::shared_ptr<BufferRequestThread> bufReqThread);
+ ~OutputThread();
+
+ Status allocateIntermediateBuffers(const Size& v4lSize, const Size& thumbSize,
+ const std::vector<Stream>& streams,
+ uint32_t blobBufferSize);
+ Status submitRequest(const std::shared_ptr<HalRequest>&);
+ void flush();
+ void dump(int fd);
+ bool threadLoop() override;
+
+ void setExifMakeModel(const std::string& make, const std::string& model);
+
+ // The remaining request list is returned for offline processing
+ std::list<std::shared_ptr<HalRequest>> switchToOffline();
+
+ protected:
+ static const int kFlushWaitTimeoutSec = 3; // 3 sec
+ static const int kReqWaitTimeoutMs = 33; // 33ms
+ static const int kReqWaitTimesMax = 90; // 33ms * 90 ~= 3 sec
+
+ // Methods to request output buffer in parallel
+ int requestBufferStart(const std::vector<HalStreamBuffer>&);
+ int waitForBufferRequestDone(
+ /*out*/ std::vector<HalStreamBuffer>*);
+
+ void waitForNextRequest(std::shared_ptr<HalRequest>* out);
+ void signalRequestDone();
+
+ int cropAndScaleLocked(std::shared_ptr<AllocatedFrame>& in, const Size& outSize,
+ YCbCrLayout* out);
+
+ int cropAndScaleThumbLocked(std::shared_ptr<AllocatedFrame>& in, const Size& outSize,
+ YCbCrLayout* out);
+
+ int createJpegLocked(HalStreamBuffer& halBuf,
+ const common::V1_0::helper::CameraMetadata& settings);
+
+ void clearIntermediateBuffers();
+
+ const std::weak_ptr<OutputThreadInterface> mParent;
+ const CroppingType mCroppingType;
+ const common::V1_0::helper::CameraMetadata mCameraCharacteristics;
+
+ mutable std::mutex mRequestListLock; // Protect access to mRequestList,
+ // mProcessingRequest and mProcessingFrameNumber
+ std::condition_variable mRequestCond; // signaled when a new request is submitted
+ std::condition_variable mRequestDoneCond; // signaled when a request is done processing
+ std::list<std::shared_ptr<HalRequest>> mRequestList;
+ bool mProcessingRequest = false;
+ uint32_t mProcessingFrameNumber = 0;
+
+ // V4L2 frameIn
+ // (MJPG decode)-> mYu12Frame
+ // (Scale)-> mScaledYu12Frames
+ // (Format convert) -> output gralloc frames
+ mutable std::mutex mBufferLock; // Protect access to intermediate buffers
+ std::shared_ptr<AllocatedFrame> mYu12Frame;
+ std::shared_ptr<AllocatedFrame> mYu12ThumbFrame;
+ std::unordered_map<Size, std::shared_ptr<AllocatedFrame>, SizeHasher> mIntermediateBuffers;
+ std::unordered_map<Size, std::shared_ptr<AllocatedFrame>, SizeHasher> mScaledYu12Frames;
+ YCbCrLayout mYu12FrameLayout;
+ YCbCrLayout mYu12ThumbFrameLayout;
+ std::vector<uint8_t> mMuteTestPatternFrame;
+ uint32_t mTestPatternData[4] = {0, 0, 0, 0};
+ bool mCameraMuted = false;
+ uint32_t mBlobBufferSize = 0; // 0 -> HAL derive buffer size, else: use given size
+
+ std::string mExifMake;
+ std::string mExifModel;
+
+ const std::shared_ptr<BufferRequestThread> mBufferRequestThread;
+ };
+
+ private:
+ bool initialize();
+ // To init/close different version of output thread
+ void initOutputThread();
+ void closeOutputThread();
+ void closeOutputThreadImpl();
+
+ void close(bool callerIsDtor);
+ Status initStatus() const;
+ status_t initDefaultRequests();
+
+ status_t fillCaptureResult(common::V1_0::helper::CameraMetadata& md, nsecs_t timestamp);
+ int configureV4l2StreamLocked(const SupportedV4L2Format& fmt, double fps = 0.0);
+ int v4l2StreamOffLocked();
+
+ int setV4l2FpsLocked(double fps);
+
+ std::unique_ptr<V4L2Frame> dequeueV4l2FrameLocked(
+ /*out*/ nsecs_t* shutterTs); // Called with mLock held
+
+ void enqueueV4l2Frame(const std::shared_ptr<V4L2Frame>&);
+
+ // Check if input Stream is one of supported stream setting on this device
+ static bool isSupported(const Stream& stream,
+ const std::vector<SupportedV4L2Format>& supportedFormats,
+ const ExternalCameraConfig& cfg);
+
+ // Validate and import request's output buffers and acquire fence
+ Status importRequestLocked(const CaptureRequest& request,
+ std::vector<buffer_handle_t*>& allBufPtrs,
+ std::vector<int>& allFences);
+
+ Status importRequestLockedImpl(const CaptureRequest& request,
+ std::vector<buffer_handle_t*>& allBufPtrs,
+ std::vector<int>& allFences);
+
+ Status importBufferLocked(int32_t streamId, uint64_t bufId, buffer_handle_t buf,
+ /*out*/ buffer_handle_t** outBufPtr);
+ static void cleanupInflightFences(std::vector<int>& allFences, size_t numFences);
+ void cleanupBuffersLocked(int id);
+
+ void updateBufferCaches(const std::vector<BufferCache>& cachesToRemove);
+
+ Status processOneCaptureRequest(const CaptureRequest& request);
+ void notifyShutter(int32_t frameNumber, nsecs_t shutterTs);
+
+ void invokeProcessCaptureResultCallback(std::vector<CaptureResult>& results, bool tryWriteFmq);
+ Size getMaxJpegResolution() const;
+
+ Size getMaxThumbResolution() const;
+
+ int waitForV4L2BufferReturnLocked(std::unique_lock<std::mutex>& lk);
+
+ // Main body of switchToOffline. This method does not invoke any callbacks
+ // but instead returns the necessary callbacks in output arguments so callers
+ // can callback later without holding any locks
+ Status switchToOffline(const std::vector<int32_t>& offlineStreams,
+ /*out*/ std::vector<NotifyMsg>* msgs,
+ /*out*/ std::vector<CaptureResult>* results,
+ /*out*/ CameraOfflineSessionInfo* info,
+ /*out*/ std::shared_ptr<ICameraOfflineSession>* session);
+
+ bool supportOfflineLocked(int32_t streamId);
+
+ // Whether a request can be completely dropped when switching to offline
+ bool canDropRequest(const std::vector<int32_t>& offlineStreams,
+ std::shared_ptr<HalRequest> halReq);
+
+ void fillOfflineSessionInfo(const std::vector<int32_t>& offlineStreams,
+ std::deque<std::shared_ptr<HalRequest>>& offlineReqs,
+ const std::map<int, CirculatingBuffers>& circulatingBuffers,
+ /*out*/ CameraOfflineSessionInfo* info);
+
+ // Protect (most of) HIDL interface methods from synchronized-entering
+ mutable Mutex mInterfaceLock;
+
+ mutable Mutex mLock; // Protect all private members except otherwise noted
+ const std::shared_ptr<ICameraDeviceCallback> mCallback;
+ const ExternalCameraConfig& mCfg;
+ const common::V1_0::helper::CameraMetadata mCameraCharacteristics;
+ const std::vector<SupportedV4L2Format> mSupportedFormats;
+ const CroppingType mCroppingType;
+ const std::string mCameraId;
+
+ // Not protected by mLock, this is almost a const.
+ // Setup in constructor, reset in close() after OutputThread is joined
+ unique_fd mV4l2Fd;
+
+ // device is closed either
+ // - closed by user
+ // - init failed
+ // - camera disconnected
+ bool mClosed = false;
+ bool mInitialized = false;
+ bool mInitFail = false;
+ bool mFirstRequest = false;
+ common::V1_0::helper::CameraMetadata mLatestReqSetting;
+
+ bool mV4l2Streaming = false;
+ SupportedV4L2Format mV4l2StreamingFmt;
+ double mV4l2StreamingFps = 0.0;
+ size_t mV4L2BufferCount = 0;
+
+ static const int kBufferWaitTimeoutSec = 3; // TODO: handle long exposure (or not allowing)
+ std::mutex mV4l2BufferLock; // protect the buffer count and condition below
+ std::condition_variable mV4L2BufferReturned;
+ size_t mNumDequeuedV4l2Buffers = 0;
+ uint32_t mMaxV4L2BufferSize = 0;
+
+ // Not protected by mLock (but might be used when mLock is locked)
+ std::shared_ptr<OutputThread> mOutputThread;
+
+ // Stream ID -> Stream cache
+ std::unordered_map<int, Stream> mStreamMap;
+
+ std::mutex mInflightFramesLock; // protect mInflightFrames
+ std::unordered_set<uint32_t> mInflightFrames;
+
+ // Stream ID -> circulating buffers map
+ std::map<int, CirculatingBuffers> mCirculatingBuffers;
+ // Protect mCirculatingBuffers, must not lock mLock after acquiring this lock
+ mutable Mutex mCbsLock;
+
+ std::mutex mAfTriggerLock; // protect mAfTrigger
+ bool mAfTrigger = false;
+
+ uint32_t mBlobBufferSize = 0;
+
+ static HandleImporter sHandleImporter;
+
+ bool mSupportBufMgr;
+ std::shared_ptr<BufferRequestThread> mBufferRequestThread;
+
+ /* Beginning of members not changed after initialize() */
+ using RequestMetadataQueue = AidlMessageQueue<int8_t, SynchronizedReadWrite>;
+ std::unique_ptr<RequestMetadataQueue> mRequestMetadataQueue;
+ using ResultMetadataQueue = AidlMessageQueue<int8_t, SynchronizedReadWrite>;
+ std::shared_ptr<ResultMetadataQueue> mResultMetadataQueue;
+
+ // Protect against invokeProcessCaptureResultCallback()
+ Mutex mProcessCaptureResultLock;
+
+ // tracks last seen stream config counter
+ int32_t mLastStreamConfigCounter = -1;
+
+ std::unordered_map<RequestTemplate, CameraMetadata> mDefaultRequests;
+
+ const Size mMaxThumbResolution;
+ const Size mMaxJpegResolution;
+
+ std::string mExifMake;
+ std::string mExifModel;
+ /* End of members not changed after initialize() */
+};
+
+} // namespace implementation
+} // namespace device
+} // namespace camera
+} // namespace hardware
+} // namespace android
+
+#endif // HARDWARE_INTERFACES_CAMERA_DEVICE_DEFAULT_EXTERNALCAMERADEVICESESSION_H_
diff --git a/camera/device/default/ExternalCameraOfflineSession.cpp b/camera/device/default/ExternalCameraOfflineSession.cpp
new file mode 100644
index 0000000..4c7f732
--- /dev/null
+++ b/camera/device/default/ExternalCameraOfflineSession.cpp
@@ -0,0 +1,547 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "ExtCamOfflnSsn"
+#include <android/log.h>
+
+#include "ExternalCameraOfflineSession.h"
+
+#include <aidl/android/hardware/camera/device/BufferStatus.h>
+#include <aidl/android/hardware/camera/device/ErrorMsg.h>
+#include <aidl/android/hardware/camera/device/ShutterMsg.h>
+#include <aidl/android/hardware/camera/device/StreamBuffer.h>
+#include <aidlcommonsupport/NativeHandle.h>
+#include <convert.h>
+#include <linux/videodev2.h>
+#include <sync/sync.h>
+#include <utils/Trace.h>
+
+#define HAVE_JPEG // required for libyuv.h to export MJPEG decode APIs
+#include <libyuv.h>
+
+namespace {
+
+// Size of request/result metadata fast message queue. Change to 0 to always use hwbinder buffer.
+constexpr size_t kMetadataMsgQueueSize = 1 << 18 /* 256kB */;
+
+} // anonymous namespace
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace implementation {
+
+using ::aidl::android::hardware::camera::device::BufferStatus;
+using ::aidl::android::hardware::camera::device::ErrorMsg;
+using ::aidl::android::hardware::camera::device::ShutterMsg;
+using ::aidl::android::hardware::camera::device::StreamBuffer;
+
+// Static instance
+HandleImporter ExternalCameraOfflineSession::sHandleImporter;
+
+ExternalCameraOfflineSession::ExternalCameraOfflineSession(
+ const CroppingType& croppingType, const common::V1_0::helper::CameraMetadata& chars,
+ const std::string& cameraId, const std::string& exifMake, const std::string& exifModel,
+ uint32_t blobBufferSize, bool afTrigger, const std::vector<Stream>& offlineStreams,
+ std::deque<std::shared_ptr<HalRequest>>& offlineReqs,
+ const std::map<int, CirculatingBuffers>& circulatingBuffers)
+ : mCroppingType(croppingType),
+ mChars(chars),
+ mCameraId(cameraId),
+ mExifMake(exifMake),
+ mExifModel(exifModel),
+ mBlobBufferSize(blobBufferSize),
+ mAfTrigger(afTrigger),
+ mOfflineStreams(offlineStreams),
+ mOfflineReqs(offlineReqs),
+ mCirculatingBuffers(circulatingBuffers) {}
+
+ExternalCameraOfflineSession::~ExternalCameraOfflineSession() {
+ close();
+}
+
+bool ExternalCameraOfflineSession::initialize() {
+ mResultMetadataQueue =
+ std::make_shared<ResultMetadataQueue>(kMetadataMsgQueueSize, false /* non blocking */);
+ if (!mResultMetadataQueue->isValid()) {
+ ALOGE("%s: invalid result fmq", __FUNCTION__);
+ return true;
+ }
+ return false;
+}
+
+Status ExternalCameraOfflineSession::importBuffer(int32_t streamId, uint64_t bufId,
+ buffer_handle_t buf,
+ buffer_handle_t** outBufPtr) {
+ Mutex::Autolock _l(mCbsLock);
+ return importBufferImpl(mCirculatingBuffers, sHandleImporter, streamId, bufId, buf, outBufPtr);
+}
+
+Status ExternalCameraOfflineSession::processCaptureResult(std::shared_ptr<HalRequest>& req) {
+ ATRACE_CALL();
+ // Fill output buffers
+ std::vector<CaptureResult> results;
+ results.resize(1);
+ CaptureResult& result = results[0];
+ result.frameNumber = req->frameNumber;
+ result.partialResult = 1;
+ result.inputBuffer.streamId = -1;
+ result.outputBuffers.resize(req->buffers.size());
+ for (size_t i = 0; i < req->buffers.size(); i++) {
+ StreamBuffer& outputBuffer = result.outputBuffers[i];
+ outputBuffer.streamId = req->buffers[i].streamId;
+ outputBuffer.bufferId = req->buffers[i].bufferId;
+ if (req->buffers[i].fenceTimeout) {
+ outputBuffer.status = BufferStatus::ERROR;
+ if (req->buffers[i].acquireFence >= 0) {
+ native_handle_t* handle = native_handle_create(/*numFds*/ 1, /*numInts*/ 0);
+ handle->data[0] = req->buffers[i].acquireFence;
+ result.outputBuffers[i].releaseFence = android::makeToAidl(handle);
+ }
+ notifyError(req->frameNumber, req->buffers[i].streamId, ErrorCode::ERROR_BUFFER);
+ } else {
+ result.outputBuffers[i].status = BufferStatus::OK;
+ // TODO: refactor
+ if (req->buffers[i].acquireFence >= 0) {
+ native_handle_t* handle = native_handle_create(/*numFds*/ 1, /*numInts*/ 0);
+ handle->data[0] = req->buffers[i].acquireFence;
+ outputBuffer.releaseFence = android::makeToAidl(handle);
+ }
+ }
+ }
+
+ // Fill capture result metadata
+ fillCaptureResult(req->setting, req->shutterTs);
+ const camera_metadata_t* rawResult = req->setting.getAndLock();
+ convertToAidl(rawResult, &result.result);
+ req->setting.unlock(rawResult);
+
+ // Callback into framework
+ invokeProcessCaptureResultCallback(results, /* tryWriteFmq */ true);
+ freeReleaseFences(results);
+ return Status::OK;
+}
+
+#define UPDATE(md, tag, data, size) \
+ do { \
+ if ((md).update((tag), (data), (size))) { \
+ ALOGE("Update " #tag " failed!"); \
+ return BAD_VALUE; \
+ } \
+ } while (0)
+
+status_t ExternalCameraOfflineSession::fillCaptureResult(common::V1_0::helper::CameraMetadata md,
+ nsecs_t timestamp) {
+ bool afTrigger = false;
+ {
+ std::lock_guard<std::mutex> lk(mAfTriggerLock);
+ afTrigger = mAfTrigger;
+ if (md.exists(ANDROID_CONTROL_AF_TRIGGER)) {
+ camera_metadata_entry entry = md.find(ANDROID_CONTROL_AF_TRIGGER);
+ if (entry.data.u8[0] == ANDROID_CONTROL_AF_TRIGGER_START) {
+ mAfTrigger = afTrigger = true;
+ } else if (entry.data.u8[0] == ANDROID_CONTROL_AF_TRIGGER_CANCEL) {
+ mAfTrigger = afTrigger = false;
+ }
+ }
+ }
+
+ // For USB camera, the USB camera handles everything and we don't have control
+ // over AF. We only simply fake the AF metadata based on the request
+ // received here.
+ uint8_t afState;
+ if (afTrigger) {
+ afState = ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED;
+ } else {
+ afState = ANDROID_CONTROL_AF_STATE_INACTIVE;
+ }
+ UPDATE(md, ANDROID_CONTROL_AF_STATE, &afState, 1);
+
+ camera_metadata_ro_entry activeArraySize = mChars.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
+
+ return fillCaptureResultCommon(md, timestamp, activeArraySize);
+}
+void ExternalCameraOfflineSession::invokeProcessCaptureResultCallback(
+ std::vector<CaptureResult>& results, bool tryWriteFmq) {
+ if (mProcessCaptureResultLock.tryLock() != OK) {
+ const nsecs_t NS_TO_SECOND = 1E9;
+ ALOGV("%s: previous call is not finished! waiting 1s...", __FUNCTION__);
+ if (mProcessCaptureResultLock.timedLock(/* 1s */ NS_TO_SECOND) != OK) {
+ ALOGE("%s: cannot acquire lock in 1s, cannot proceed", __FUNCTION__);
+ return;
+ }
+ }
+ if (tryWriteFmq && mResultMetadataQueue->availableToWrite() > 0) {
+ for (CaptureResult& result : results) {
+ if (!result.result.metadata.empty()) {
+ if (mResultMetadataQueue->write(
+ reinterpret_cast<int8_t*>(result.result.metadata.data()),
+ result.result.metadata.size())) {
+ result.fmqResultSize = result.result.metadata.size();
+ result.result.metadata.clear();
+ } else {
+ ALOGW("%s: couldn't utilize fmq, fall back to hwbinder", __FUNCTION__);
+ result.fmqResultSize = 0;
+ }
+ } else {
+ result.fmqResultSize = 0;
+ }
+ }
+ }
+ auto status = mCallback->processCaptureResult(results);
+ if (!status.isOk()) {
+ ALOGE("%s: processCaptureResult ERROR : %d:%d", __FUNCTION__, status.getExceptionCode(),
+ status.getServiceSpecificError());
+ }
+
+ mProcessCaptureResultLock.unlock();
+}
+
+Status ExternalCameraOfflineSession::processCaptureRequestError(
+ const std::shared_ptr<HalRequest>& req, std::vector<NotifyMsg>* outMsgs,
+ std::vector<CaptureResult>* outResults) {
+ ATRACE_CALL();
+
+ if (outMsgs == nullptr) {
+ notifyError(/*frameNum*/ req->frameNumber, /*stream*/ -1, ErrorCode::ERROR_REQUEST);
+ } else {
+ NotifyMsg shutter;
+ shutter.set<NotifyMsg::Tag::shutter>(ShutterMsg{
+ .frameNumber = req->frameNumber,
+ .timestamp = req->shutterTs,
+ });
+
+ NotifyMsg error;
+ error.set<NotifyMsg::Tag::error>(ErrorMsg{.frameNumber = req->frameNumber,
+ .errorStreamId = -1,
+ .errorCode = ErrorCode::ERROR_REQUEST});
+ outMsgs->push_back(shutter);
+ outMsgs->push_back(error);
+ }
+
+ // Fill output buffers
+ CaptureResult result;
+ result.frameNumber = req->frameNumber;
+ result.partialResult = 1;
+ result.inputBuffer.streamId = -1;
+ result.outputBuffers.resize(req->buffers.size());
+ for (size_t i = 0; i < req->buffers.size(); i++) {
+ StreamBuffer& outputBuffer = result.outputBuffers[i];
+ outputBuffer.streamId = req->buffers[i].streamId;
+ outputBuffer.bufferId = req->buffers[i].bufferId;
+ outputBuffer.status = BufferStatus::ERROR;
+ if (req->buffers[i].acquireFence >= 0) {
+ native_handle_t* handle = native_handle_create(/*numFds*/ 1, /*numInts*/ 0);
+ handle->data[0] = req->buffers[i].acquireFence;
+ outputBuffer.releaseFence = makeToAidl(handle);
+ }
+ }
+
+ if (outResults == nullptr) {
+ // Callback into framework
+ std::vector<CaptureResult> results(1);
+ results[0] = std::move(result);
+ invokeProcessCaptureResultCallback(results, /* tryWriteFmq */ true);
+ freeReleaseFences(results);
+ } else {
+ outResults->push_back(std::move(result));
+ }
+ return Status::OK;
+}
+
+ssize_t ExternalCameraOfflineSession::getJpegBufferSize(int32_t, int32_t) const {
+ // Empty implementation here as the jpeg buffer size is passed in by ctor
+ return 0;
+}
+
+void ExternalCameraOfflineSession::notifyError(int32_t frameNumber, int32_t streamId,
+ ErrorCode ec) {
+ NotifyMsg msg;
+ msg.set<NotifyMsg::Tag::error>(
+ ErrorMsg{.frameNumber = frameNumber, .errorStreamId = streamId, .errorCode = ec});
+ mCallback->notify({msg});
+}
+
+ScopedAStatus ExternalCameraOfflineSession::setCallback(
+ const std::shared_ptr<ICameraDeviceCallback>& in_cb) {
+ Mutex::Autolock _il(mInterfaceLock);
+ if (mCallback != nullptr && in_cb != nullptr) {
+ ALOGE("%s: callback must not be set twice!", __FUNCTION__);
+ return fromStatus(Status::OK);
+ }
+ mCallback = in_cb;
+
+ initOutputThread();
+
+ if (mOutputThread == nullptr) {
+ ALOGE("%s: init OutputThread failed!", __FUNCTION__);
+ }
+ return fromStatus(Status::OK);
+}
+void ExternalCameraOfflineSession::initOutputThread() {
+ if (mOutputThread != nullptr) {
+ ALOGE("%s: OutputThread already exist!", __FUNCTION__);
+ return;
+ }
+
+ // Grab a shared_ptr to 'this' from ndk::SharedRefBase::ref()
+ std::shared_ptr<ExternalCameraOfflineSession> thiz = ref<ExternalCameraOfflineSession>();
+
+ mBufferRequestThread = std::make_shared<ExternalCameraDeviceSession::BufferRequestThread>(
+ /*parent=*/thiz, mCallback);
+ mBufferRequestThread->run();
+
+ mOutputThread = std::make_shared<OutputThread>(/*parent=*/thiz, mCroppingType, mChars,
+ mBufferRequestThread, mOfflineReqs);
+
+ mOutputThread->setExifMakeModel(mExifMake, mExifModel);
+
+ Size inputSize = {mOfflineReqs[0]->frameIn->mWidth, mOfflineReqs[0]->frameIn->mHeight};
+ Size maxThumbSize = getMaxThumbnailResolution(mChars);
+ mOutputThread->allocateIntermediateBuffers(inputSize, maxThumbSize, mOfflineStreams,
+ mBlobBufferSize);
+
+ mOutputThread->run();
+}
+
+ScopedAStatus ExternalCameraOfflineSession::getCaptureResultMetadataQueue(
+ MQDescriptor<int8_t, SynchronizedReadWrite>* _aidl_return) {
+ Mutex::Autolock _il(mInterfaceLock);
+ *_aidl_return = mResultMetadataQueue->dupeDesc();
+ return fromStatus(Status::OK);
+}
+
+ScopedAStatus ExternalCameraOfflineSession::close() {
+ Mutex::Autolock _il(mInterfaceLock);
+ {
+ Mutex::Autolock _l(mLock);
+ if (mClosed) {
+ ALOGW("%s: offline session already closed!", __FUNCTION__);
+ return fromStatus(Status::OK);
+ }
+ }
+ if (mBufferRequestThread != nullptr) {
+ mBufferRequestThread->requestExitAndWait();
+ mBufferRequestThread.reset();
+ }
+ if (mOutputThread) {
+ mOutputThread->flush();
+ mOutputThread->requestExitAndWait();
+ mOutputThread.reset();
+ }
+
+ Mutex::Autolock _l(mLock);
+ // free all buffers
+ {
+ Mutex::Autolock _cbl(mCbsLock);
+ for (auto& stream : mOfflineStreams) {
+ cleanupBuffersLocked(stream.id);
+ }
+ }
+ mCallback.reset();
+ mClosed = true;
+ return fromStatus(Status::OK);
+}
+void ExternalCameraOfflineSession::cleanupBuffersLocked(int32_t id) {
+ for (auto& pair : mCirculatingBuffers.at(id)) {
+ sHandleImporter.freeBuffer(pair.second);
+ }
+ mCirculatingBuffers[id].clear();
+ mCirculatingBuffers.erase(id);
+}
+
+bool ExternalCameraOfflineSession::OutputThread::threadLoop() {
+ auto parent = mParent.lock();
+ if (parent == nullptr) {
+ ALOGE("%s: session has been disconnected!", __FUNCTION__);
+ return false;
+ }
+
+ if (mOfflineReqs.empty()) {
+ ALOGI("%s: all offline requests are processed. Stopping.", __FUNCTION__);
+ return false;
+ }
+
+ std::shared_ptr<HalRequest> req = mOfflineReqs.front();
+ mOfflineReqs.pop_front();
+
+ auto onDeviceError = [&](auto... args) {
+ ALOGE(args...);
+ parent->notifyError(req->frameNumber, /*stream*/ -1, ErrorCode::ERROR_DEVICE);
+ signalRequestDone();
+ return false;
+ };
+
+ if (req->frameIn->mFourcc != V4L2_PIX_FMT_MJPEG && req->frameIn->mFourcc != V4L2_PIX_FMT_Z16) {
+ return onDeviceError("%s: do not support V4L2 format %c%c%c%c", __FUNCTION__,
+ req->frameIn->mFourcc & 0xFF, (req->frameIn->mFourcc >> 8) & 0xFF,
+ (req->frameIn->mFourcc >> 16) & 0xFF,
+ (req->frameIn->mFourcc >> 24) & 0xFF);
+ }
+
+ int res = requestBufferStart(req->buffers);
+ if (res != 0) {
+ ALOGE("%s: send BufferRequest failed! res %d", __FUNCTION__, res);
+ return onDeviceError("%s: failed to send buffer request!", __FUNCTION__);
+ }
+
+ std::unique_lock<std::mutex> lk(mBufferLock);
+ // Convert input V4L2 frame to YU12 of the same size
+ // TODO: see if we can save some computation by converting to YV12 here
+ uint8_t* inData;
+ size_t inDataSize;
+ if (req->frameIn->getData(&inData, &inDataSize) != 0) {
+ lk.unlock();
+ return onDeviceError("%s: V4L2 buffer map failed", __FUNCTION__);
+ }
+
+ // TODO: in some special case maybe we can decode jpg directly to gralloc output?
+ if (req->frameIn->mFourcc == V4L2_PIX_FMT_MJPEG) {
+ ATRACE_BEGIN("MJPGtoI420");
+ int convRes = libyuv::MJPGToI420(
+ inData, inDataSize, static_cast<uint8_t*>(mYu12FrameLayout.y),
+ mYu12FrameLayout.yStride, static_cast<uint8_t*>(mYu12FrameLayout.cb),
+ mYu12FrameLayout.cStride, static_cast<uint8_t*>(mYu12FrameLayout.cr),
+ mYu12FrameLayout.cStride, mYu12Frame->mWidth, mYu12Frame->mHeight,
+ mYu12Frame->mWidth, mYu12Frame->mHeight);
+ ATRACE_END();
+
+ if (convRes != 0) {
+ // For some webcam, the first few V4L2 frames might be malformed...
+ ALOGE("%s: Convert V4L2 frame to YU12 failed! res %d", __FUNCTION__, convRes);
+ lk.unlock();
+ Status st = parent->processCaptureRequestError(req);
+ if (st != Status::OK) {
+ return onDeviceError("%s: failed to process capture request error!", __FUNCTION__);
+ }
+ signalRequestDone();
+ return true;
+ }
+ }
+
+ ATRACE_BEGIN("Wait for BufferRequest done");
+ res = waitForBufferRequestDone(&req->buffers);
+ ATRACE_END();
+
+ if (res != 0) {
+ ALOGE("%s: wait for BufferRequest done failed! res %d", __FUNCTION__, res);
+ lk.unlock();
+ return onDeviceError("%s: failed to process buffer request error!", __FUNCTION__);
+ }
+
+ ALOGV("%s processing new request", __FUNCTION__);
+ const int kSyncWaitTimeoutMs = 500;
+ for (auto& halBuf : req->buffers) {
+ if (*(halBuf.bufPtr) == nullptr) {
+ ALOGW("%s: buffer for stream %d missing", __FUNCTION__, halBuf.streamId);
+ halBuf.fenceTimeout = true;
+ } else if (halBuf.acquireFence >= 0) {
+ int ret = sync_wait(halBuf.acquireFence, kSyncWaitTimeoutMs);
+ if (ret) {
+ halBuf.fenceTimeout = true;
+ } else {
+ ::close(halBuf.acquireFence);
+ halBuf.acquireFence = -1;
+ }
+ }
+
+ if (halBuf.fenceTimeout) {
+ continue;
+ }
+
+ // Gralloc lockYCbCr the buffer
+ switch (halBuf.format) {
+ case PixelFormat::BLOB: {
+ int ret = createJpegLocked(halBuf, req->setting);
+
+ if (ret != 0) {
+ lk.unlock();
+ return onDeviceError("%s: createJpegLocked failed with %d", __FUNCTION__, ret);
+ }
+ } break;
+ case PixelFormat::Y16: {
+ void* outLayout = sHandleImporter.lock(
+ *(halBuf.bufPtr), static_cast<uint64_t>(halBuf.usage), inDataSize);
+
+ std::memcpy(outLayout, inData, inDataSize);
+
+ int relFence = sHandleImporter.unlock(*(halBuf.bufPtr));
+ if (relFence >= 0) {
+ halBuf.acquireFence = relFence;
+ }
+ } break;
+ case PixelFormat::YCBCR_420_888:
+ case PixelFormat::YV12: {
+ IMapper::Rect outRect{0, 0, static_cast<int32_t>(halBuf.width),
+ static_cast<int32_t>(halBuf.height)};
+ YCbCrLayout outLayout = sHandleImporter.lockYCbCr(
+ *(halBuf.bufPtr), static_cast<uint64_t>(halBuf.usage), outRect);
+ ALOGV("%s: outLayout y %p cb %p cr %p y_str %d c_str %d c_step %d", __FUNCTION__,
+ outLayout.y, outLayout.cb, outLayout.cr, outLayout.yStride, outLayout.cStride,
+ outLayout.chromaStep);
+
+ // Convert to output buffer size/format
+ uint32_t outputFourcc = getFourCcFromLayout(outLayout);
+ ALOGV("%s: converting to format %c%c%c%c", __FUNCTION__, outputFourcc & 0xFF,
+ (outputFourcc >> 8) & 0xFF, (outputFourcc >> 16) & 0xFF,
+ (outputFourcc >> 24) & 0xFF);
+
+ YCbCrLayout cropAndScaled;
+ ATRACE_BEGIN("cropAndScaleLocked");
+ int ret = cropAndScaleLocked(mYu12Frame, Size{halBuf.width, halBuf.height},
+ &cropAndScaled);
+ ATRACE_END();
+ if (ret != 0) {
+ lk.unlock();
+ return onDeviceError("%s: crop and scale failed!", __FUNCTION__);
+ }
+
+ Size sz{halBuf.width, halBuf.height};
+ ATRACE_BEGIN("formatConvert");
+ ret = formatConvert(cropAndScaled, outLayout, sz, outputFourcc);
+ ATRACE_END();
+ if (ret != 0) {
+ lk.unlock();
+ return onDeviceError("%s: format coversion failed!", __FUNCTION__);
+ }
+ int relFence = sHandleImporter.unlock(*(halBuf.bufPtr));
+ if (relFence >= 0) {
+ halBuf.acquireFence = relFence;
+ }
+ } break;
+ default:
+ lk.unlock();
+ return onDeviceError("%s: unknown output format %x", __FUNCTION__, halBuf.format);
+ }
+ } // for each buffer
+ mScaledYu12Frames.clear();
+
+ // Don't hold the lock while calling back to parent
+ lk.unlock();
+ Status st = parent->processCaptureResult(req);
+ if (st != Status::OK) {
+ return onDeviceError("%s: failed to process capture result!", __FUNCTION__);
+ }
+ signalRequestDone();
+ return true;
+}
+
+} // namespace implementation
+} // namespace device
+} // namespace camera
+} // namespace hardware
+} // namespace android
\ No newline at end of file
diff --git a/camera/device/default/ExternalCameraOfflineSession.h b/camera/device/default/ExternalCameraOfflineSession.h
new file mode 100644
index 0000000..5795c95
--- /dev/null
+++ b/camera/device/default/ExternalCameraOfflineSession.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HARDWARE_INTERFACES_CAMERA_DEVICE_DEFAULT_EXTERNALCAMERAOFFLINESESSION_H_
+#define HARDWARE_INTERFACES_CAMERA_DEVICE_DEFAULT_EXTERNALCAMERAOFFLINESESSION_H_
+
+#include <ExternalCameraDeviceSession.h>
+#include <ExternalCameraUtils.h>
+#include <aidl/android/hardware/camera/common/Status.h>
+#include <aidl/android/hardware/camera/device/BnCameraOfflineSession.h>
+#include <aidl/android/hardware/camera/device/Stream.h>
+#include <fmq/AidlMessageQueue.h>
+#include <utils/RefBase.h>
+#include <deque>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace implementation {
+
+using ::aidl::android::hardware::camera::common::Status;
+using ::aidl::android::hardware::camera::device::BnCameraOfflineSession;
+using ::aidl::android::hardware::camera::device::ICameraDeviceCallback;
+using ::aidl::android::hardware::camera::device::Stream;
+using ::aidl::android::hardware::common::fmq::MQDescriptor;
+using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+
+class ExternalCameraOfflineSession : public BnCameraOfflineSession,
+ public virtual RefBase,
+ public virtual OutputThreadInterface {
+ public:
+ ExternalCameraOfflineSession(const CroppingType& croppingType,
+ const common::V1_0::helper::CameraMetadata& chars,
+ const std::string& cameraId, const std::string& exifMake,
+ const std::string& exifModel, uint32_t blobBufferSize,
+ bool afTrigger, const std::vector<Stream>& offlineStreams,
+ std::deque<std::shared_ptr<HalRequest>>& offlineReqs,
+ const std::map<int, CirculatingBuffers>& circulatingBuffers);
+
+ ~ExternalCameraOfflineSession() override;
+
+ bool initialize();
+
+ // Methods from OutputThreadInterface
+ Status importBuffer(int32_t streamId, uint64_t bufId, buffer_handle_t buf,
+ /*out*/ buffer_handle_t** outBufPtr) override;
+
+ Status processCaptureResult(std::shared_ptr<HalRequest>&) override;
+
+ Status processCaptureRequestError(const std::shared_ptr<HalRequest>&,
+ /*out*/ std::vector<NotifyMsg>* msgs,
+ /*out*/ std::vector<CaptureResult>* results) override;
+
+ ssize_t getJpegBufferSize(int32_t width, int32_t height) const override;
+
+ void notifyError(int32_t frameNumber, int32_t streamId, ErrorCode ec) override;
+ // End of OutputThreadInterface methods
+
+ ScopedAStatus setCallback(const std::shared_ptr<ICameraDeviceCallback>& in_cb) override;
+ ScopedAStatus getCaptureResultMetadataQueue(
+ MQDescriptor<int8_t, SynchronizedReadWrite>* _aidl_return) override;
+ ScopedAStatus close() override;
+
+ private:
+ class OutputThread : public ExternalCameraDeviceSession::OutputThread {
+ public:
+ OutputThread(std::weak_ptr<OutputThreadInterface> parent, CroppingType ct,
+ const common::V1_0::helper::CameraMetadata& chars,
+ std::shared_ptr<ExternalCameraDeviceSession::BufferRequestThread> bufReqThread,
+ std::deque<std::shared_ptr<HalRequest>>& offlineReqs)
+ : ExternalCameraDeviceSession::OutputThread(std::move(parent), ct, chars,
+ std::move(bufReqThread)),
+ mOfflineReqs(offlineReqs) {}
+
+ bool threadLoop() override;
+
+ protected:
+ std::deque<std::shared_ptr<HalRequest>> mOfflineReqs;
+ }; // OutputThread
+
+ status_t fillCaptureResult(common::V1_0::helper::CameraMetadata md, nsecs_t timestamp);
+ void invokeProcessCaptureResultCallback(std::vector<CaptureResult>& results, bool tryWriteFmq);
+ void initOutputThread();
+ void cleanupBuffersLocked(int32_t id);
+
+ // Protect (most of) HIDL interface methods from synchronized-entering
+ mutable Mutex mInterfaceLock;
+
+ mutable Mutex mLock; // Protect all data members except otherwise noted
+
+ bool mClosed = false;
+ const CroppingType mCroppingType;
+ const common::V1_0::helper::CameraMetadata mChars;
+ const std::string mCameraId;
+ const std::string mExifMake;
+ const std::string mExifModel;
+ const uint32_t mBlobBufferSize;
+
+ std::mutex mAfTriggerLock; // protect mAfTrigger
+ bool mAfTrigger;
+
+ const std::vector<Stream> mOfflineStreams;
+ std::deque<std::shared_ptr<HalRequest>> mOfflineReqs;
+
+ // Protect mCirculatingBuffers, must not lock mLock after acquiring this lock
+ mutable Mutex mCbsLock;
+ std::map<int, CirculatingBuffers> mCirculatingBuffers;
+
+ static HandleImporter sHandleImporter;
+
+ using ResultMetadataQueue = AidlMessageQueue<int8_t, SynchronizedReadWrite>;
+ std::shared_ptr<ResultMetadataQueue> mResultMetadataQueue;
+
+ // Protect against invokeProcessCaptureResultCallback()
+ Mutex mProcessCaptureResultLock;
+
+ std::shared_ptr<ICameraDeviceCallback> mCallback;
+
+ std::shared_ptr<ExternalCameraDeviceSession::BufferRequestThread> mBufferRequestThread;
+ std::shared_ptr<OutputThread> mOutputThread;
+};
+
+} // namespace implementation
+} // namespace device
+} // namespace camera
+} // namespace hardware
+} // namespace android
+
+#endif // HARDWARE_INTERFACES_CAMERA_DEVICE_DEFAULT_EXTERNALCAMERAOFFLINESESSION_H_
diff --git a/camera/device/default/ExternalCameraUtils.cpp b/camera/device/default/ExternalCameraUtils.cpp
new file mode 100644
index 0000000..cfb95f2
--- /dev/null
+++ b/camera/device/default/ExternalCameraUtils.cpp
@@ -0,0 +1,860 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "ExtCamUtils"
+// #define LOG_NDEBUG 0
+
+#include "ExternalCameraUtils.h"
+
+#include <aidlcommonsupport/NativeHandle.h>
+#include <jpeglib.h>
+#include <linux/videodev2.h>
+#include <log/log.h>
+#include <algorithm>
+#include <cinttypes>
+#include <cmath>
+
+#define HAVE_JPEG // required for libyuv.h to export MJPEG decode APIs
+#include <libyuv.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+
+namespace external {
+namespace common {
+
+namespace {
+const int kDefaultCameraIdOffset = 100;
+const int kDefaultJpegBufSize = 5 << 20; // 5MB
+const int kDefaultNumVideoBuffer = 4;
+const int kDefaultNumStillBuffer = 2;
+const int kDefaultOrientation = 0; // suitable for natural landscape displays like tablet/TV
+ // For phone devices 270 is better
+} // anonymous namespace
+
+const char* ExternalCameraConfig::kDefaultCfgPath = "/vendor/etc/external_camera_config.xml";
+
+ExternalCameraConfig ExternalCameraConfig::loadFromCfg(const char* cfgPath) {
+ using namespace tinyxml2;
+ ExternalCameraConfig ret;
+
+ XMLDocument configXml;
+ XMLError err = configXml.LoadFile(cfgPath);
+ if (err != XML_SUCCESS) {
+ ALOGE("%s: Unable to load external camera config file '%s'. Error: %s", __FUNCTION__,
+ cfgPath, XMLDocument::ErrorIDToName(err));
+ return ret;
+ } else {
+ ALOGI("%s: load external camera config succeeded!", __FUNCTION__);
+ }
+
+ XMLElement* extCam = configXml.FirstChildElement("ExternalCamera");
+ if (extCam == nullptr) {
+ ALOGI("%s: no external camera config specified", __FUNCTION__);
+ return ret;
+ }
+
+ XMLElement* providerCfg = extCam->FirstChildElement("Provider");
+ if (providerCfg == nullptr) {
+ ALOGI("%s: no external camera provider config specified", __FUNCTION__);
+ return ret;
+ }
+
+ XMLElement* cameraIdOffset = providerCfg->FirstChildElement("CameraIdOffset");
+ if (cameraIdOffset != nullptr) {
+ ret.cameraIdOffset = std::atoi(cameraIdOffset->GetText());
+ }
+
+ XMLElement* ignore = providerCfg->FirstChildElement("ignore");
+ if (ignore == nullptr) {
+ ALOGI("%s: no internal ignored device specified", __FUNCTION__);
+ return ret;
+ }
+
+ XMLElement* id = ignore->FirstChildElement("id");
+ while (id != nullptr) {
+ const char* text = id->GetText();
+ if (text != nullptr) {
+ ret.mInternalDevices.insert(text);
+ ALOGI("%s: device %s will be ignored by external camera provider", __FUNCTION__, text);
+ }
+ id = id->NextSiblingElement("id");
+ }
+
+ XMLElement* deviceCfg = extCam->FirstChildElement("Device");
+ if (deviceCfg == nullptr) {
+ ALOGI("%s: no external camera device config specified", __FUNCTION__);
+ return ret;
+ }
+
+ XMLElement* jpegBufSz = deviceCfg->FirstChildElement("MaxJpegBufferSize");
+ if (jpegBufSz == nullptr) {
+ ALOGI("%s: no max jpeg buffer size specified", __FUNCTION__);
+ } else {
+ ret.maxJpegBufSize = jpegBufSz->UnsignedAttribute("bytes", /*Default*/ kDefaultJpegBufSize);
+ }
+
+ XMLElement* numVideoBuf = deviceCfg->FirstChildElement("NumVideoBuffers");
+ if (numVideoBuf == nullptr) {
+ ALOGI("%s: no num video buffers specified", __FUNCTION__);
+ } else {
+ ret.numVideoBuffers =
+ numVideoBuf->UnsignedAttribute("count", /*Default*/ kDefaultNumVideoBuffer);
+ }
+
+ XMLElement* numStillBuf = deviceCfg->FirstChildElement("NumStillBuffers");
+ if (numStillBuf == nullptr) {
+ ALOGI("%s: no num still buffers specified", __FUNCTION__);
+ } else {
+ ret.numStillBuffers =
+ numStillBuf->UnsignedAttribute("count", /*Default*/ kDefaultNumStillBuffer);
+ }
+
+ XMLElement* fpsList = deviceCfg->FirstChildElement("FpsList");
+ if (fpsList == nullptr) {
+ ALOGI("%s: no fps list specified", __FUNCTION__);
+ } else {
+ if (!updateFpsList(fpsList, ret.fpsLimits)) {
+ return ret;
+ }
+ }
+
+ XMLElement* depth = deviceCfg->FirstChildElement("Depth16Supported");
+ if (depth == nullptr) {
+ ret.depthEnabled = false;
+ ALOGI("%s: depth output is not enabled", __FUNCTION__);
+ } else {
+ ret.depthEnabled = depth->BoolAttribute("enabled", false);
+ }
+
+ if (ret.depthEnabled) {
+ XMLElement* depthFpsList = deviceCfg->FirstChildElement("DepthFpsList");
+ if (depthFpsList == nullptr) {
+ ALOGW("%s: no depth fps list specified", __FUNCTION__);
+ } else {
+ if (!updateFpsList(depthFpsList, ret.depthFpsLimits)) {
+ return ret;
+ }
+ }
+ }
+
+ XMLElement* minStreamSize = deviceCfg->FirstChildElement("MinimumStreamSize");
+ if (minStreamSize == nullptr) {
+ ALOGI("%s: no minimum stream size specified", __FUNCTION__);
+ } else {
+ ret.minStreamSize = {
+ static_cast<int32_t>(minStreamSize->UnsignedAttribute("width", /*Default*/ 0)),
+ static_cast<int32_t>(minStreamSize->UnsignedAttribute("height", /*Default*/ 0))};
+ }
+
+ XMLElement* orientation = deviceCfg->FirstChildElement("Orientation");
+ if (orientation == nullptr) {
+ ALOGI("%s: no sensor orientation specified", __FUNCTION__);
+ } else {
+ ret.orientation = orientation->IntAttribute("degree", /*Default*/ kDefaultOrientation);
+ }
+
+ ALOGI("%s: external camera cfg loaded: maxJpgBufSize %d,"
+ " num video buffers %d, num still buffers %d, orientation %d",
+ __FUNCTION__, ret.maxJpegBufSize, ret.numVideoBuffers, ret.numStillBuffers,
+ ret.orientation);
+ for (const auto& limit : ret.fpsLimits) {
+ ALOGI("%s: fpsLimitList: %dx%d@%f", __FUNCTION__, limit.size.width, limit.size.height,
+ limit.fpsUpperBound);
+ }
+ for (const auto& limit : ret.depthFpsLimits) {
+ ALOGI("%s: depthFpsLimitList: %dx%d@%f", __FUNCTION__, limit.size.width, limit.size.height,
+ limit.fpsUpperBound);
+ }
+ ALOGI("%s: minStreamSize: %dx%d", __FUNCTION__, ret.minStreamSize.width,
+ ret.minStreamSize.height);
+ return ret;
+}
+
+bool ExternalCameraConfig::updateFpsList(tinyxml2::XMLElement* fpsList,
+ std::vector<FpsLimitation>& fpsLimits) {
+ using namespace tinyxml2;
+ std::vector<FpsLimitation> limits;
+ XMLElement* row = fpsList->FirstChildElement("Limit");
+ while (row != nullptr) {
+ FpsLimitation prevLimit{{0, 0}, 1000.0};
+ FpsLimitation limit = {
+ {/* width */ static_cast<int32_t>(row->UnsignedAttribute("width", /*Default*/ 0)),
+ /* height */ static_cast<int32_t>(
+ row->UnsignedAttribute("height", /*Default*/ 0))},
+ /* fpsUpperBound */ row->DoubleAttribute("fpsBound", /*Default*/ 1000.0)};
+ if (limit.size.width <= prevLimit.size.width ||
+ limit.size.height <= prevLimit.size.height ||
+ limit.fpsUpperBound >= prevLimit.fpsUpperBound) {
+ ALOGE("%s: FPS limit list must have increasing size and decreasing fps!"
+ " Prev %dx%d@%f, Current %dx%d@%f",
+ __FUNCTION__, prevLimit.size.width, prevLimit.size.height,
+ prevLimit.fpsUpperBound, limit.size.width, limit.size.height,
+ limit.fpsUpperBound);
+ return false;
+ }
+ limits.push_back(limit);
+ row = row->NextSiblingElement("Limit");
+ }
+ fpsLimits = limits;
+ return true;
+}
+
+ExternalCameraConfig::ExternalCameraConfig()
+ : cameraIdOffset(kDefaultCameraIdOffset),
+ maxJpegBufSize(kDefaultJpegBufSize),
+ numVideoBuffers(kDefaultNumVideoBuffer),
+ numStillBuffers(kDefaultNumStillBuffer),
+ depthEnabled(false),
+ orientation(kDefaultOrientation) {
+ fpsLimits.push_back({/* size */ {/* width */ 640, /* height */ 480}, /* fpsUpperBound */ 30.0});
+ fpsLimits.push_back({/* size */ {/* width */ 1280, /* height */ 720}, /* fpsUpperBound */ 7.5});
+ fpsLimits.push_back(
+ {/* size */ {/* width */ 1920, /* height */ 1080}, /* fpsUpperBound */ 5.0});
+ minStreamSize = {0, 0};
+}
+
+} // namespace common
+} // namespace external
+
+namespace device {
+namespace implementation {
+
+double SupportedV4L2Format::FrameRate::getFramesPerSecond() const {
+ return static_cast<double>(durationDenominator) / durationNumerator;
+}
+
+Frame::Frame(uint32_t width, uint32_t height, uint32_t fourcc)
+ : mWidth(width), mHeight(height), mFourcc(fourcc) {}
+Frame::~Frame() {}
+
+V4L2Frame::V4L2Frame(uint32_t w, uint32_t h, uint32_t fourcc, int bufIdx, int fd, uint32_t dataSize,
+ uint64_t offset)
+ : Frame(w, h, fourcc), mBufferIndex(bufIdx), mFd(fd), mDataSize(dataSize), mOffset(offset) {}
+
+V4L2Frame::~V4L2Frame() {
+ unmap();
+}
+
+int V4L2Frame::getData(uint8_t** outData, size_t* dataSize) {
+ return map(outData, dataSize);
+}
+
+int V4L2Frame::map(uint8_t** data, size_t* dataSize) {
+ if (data == nullptr || dataSize == nullptr) {
+ ALOGI("%s: V4L2 buffer map bad argument: data %p, dataSize %p", __FUNCTION__, data,
+ dataSize);
+ return -EINVAL;
+ }
+
+ std::lock_guard<std::mutex> lk(mLock);
+ if (!mMapped) {
+ void* addr = mmap(nullptr, mDataSize, PROT_READ, MAP_SHARED, mFd, mOffset);
+ if (addr == MAP_FAILED) {
+ ALOGE("%s: V4L2 buffer map failed: %s", __FUNCTION__, strerror(errno));
+ return -EINVAL;
+ }
+ mData = static_cast<uint8_t*>(addr);
+ mMapped = true;
+ }
+ *data = mData;
+ *dataSize = mDataSize;
+ ALOGV("%s: V4L map FD %d, data %p size %zu", __FUNCTION__, mFd, mData, mDataSize);
+ return 0;
+}
+
+int V4L2Frame::unmap() {
+ std::lock_guard<std::mutex> lk(mLock);
+ if (mMapped) {
+ ALOGV("%s: V4L unmap data %p size %zu", __FUNCTION__, mData, mDataSize);
+ if (munmap(mData, mDataSize) != 0) {
+ ALOGE("%s: V4L2 buffer unmap failed: %s", __FUNCTION__, strerror(errno));
+ return -EINVAL;
+ }
+ mMapped = false;
+ }
+ return 0;
+}
+
+AllocatedFrame::AllocatedFrame(uint32_t w, uint32_t h) : Frame(w, h, V4L2_PIX_FMT_YUV420) {}
+AllocatedFrame::~AllocatedFrame() {}
+
+int AllocatedFrame::getData(uint8_t** outData, size_t* dataSize) {
+ YCbCrLayout layout;
+ int ret = allocate(&layout);
+ if (ret != 0) {
+ return ret;
+ }
+ *outData = mData.data();
+ *dataSize = mBufferSize;
+ return 0;
+}
+
+int AllocatedFrame::allocate(YCbCrLayout* out) {
+ std::lock_guard<std::mutex> lk(mLock);
+ if ((mWidth % 2) || (mHeight % 2)) {
+ ALOGE("%s: bad dimension %dx%d (not multiple of 2)", __FUNCTION__, mWidth, mHeight);
+ return -EINVAL;
+ }
+
+ // This frame might be sent to jpeglib to be encoded. Since AllocatedFrame only contains YUV420,
+ // jpeglib expects height and width of Y component to be an integral multiple of 2*DCTSIZE,
+ // and heights and widths of Cb and Cr components to be an integral multiple of DCTSIZE. If the
+ // image size does not meet this requirement, libjpeg expects its input to be padded to meet the
+ // constraints. This padding is removed from the final encoded image so the content in the
+ // padding doesn't matter. What matters is that the memory is accessible to jpeglib at the time
+ // of encoding.
+ // For example, if the image size is 1500x844 and DCTSIZE is 8, jpeglib expects a YUV 420
+ // frame with components of following sizes:
+ // Y: 1504x848 because 1504 and 848 are the next smallest multiples of 2*8
+ // Cb/Cr: 752x424 which are the next smallest multiples of 8
+
+ // jpeglib takes an array of row pointers which makes vertical padding trivial when setting up
+ // the pointers. Padding horizontally is a bit more complicated. AllocatedFrame holds the data
+ // in a flattened buffer, which means memory accesses past a row will flow into the next logical
+ // row. For any row of a component, we can consider the first few bytes of the next row as
+ // padding for the current one. This is true for Y and Cb components and all but last row of the
+ // Cr component. Reading past the last row of Cr component will lead to undefined behavior as
+ // libjpeg attempts to read memory past the allocated buffer. To prevent undefined behavior,
+ // the buffer allocated here is padded such that libjpeg never accesses unallocated memory when
+ // reading the last row. Effectively, we only need to ensure that the last row of Cr component
+ // has width that is an integral multiple of DCTSIZE.
+
+ size_t dataSize = mWidth * mHeight * 3 / 2; // YUV420
+
+ size_t cbWidth = mWidth / 2;
+ size_t requiredCbWidth = DCTSIZE * ((cbWidth + DCTSIZE - 1) / DCTSIZE);
+ size_t padding = requiredCbWidth - cbWidth;
+ size_t finalSize = dataSize + padding;
+
+ if (mData.size() != finalSize) {
+ mData.resize(finalSize);
+ mBufferSize = dataSize;
+ }
+
+ if (out != nullptr) {
+ out->y = mData.data();
+ out->yStride = mWidth;
+ uint8_t* cbStart = mData.data() + mWidth * mHeight;
+ uint8_t* crStart = cbStart + mWidth * mHeight / 4;
+ out->cb = cbStart;
+ out->cr = crStart;
+ out->cStride = mWidth / 2;
+ out->chromaStep = 1;
+ }
+ return 0;
+}
+
+int AllocatedFrame::getLayout(YCbCrLayout* out) {
+ IMapper::Rect noCrop = {0, 0, static_cast<int32_t>(mWidth), static_cast<int32_t>(mHeight)};
+ return getCroppedLayout(noCrop, out);
+}
+
+int AllocatedFrame::getCroppedLayout(const IMapper::Rect& rect, YCbCrLayout* out) {
+ if (out == nullptr) {
+ ALOGE("%s: null out", __FUNCTION__);
+ return -1;
+ }
+
+ std::lock_guard<std::mutex> lk(mLock);
+ if ((rect.left + rect.width) > static_cast<int>(mWidth) ||
+ (rect.top + rect.height) > static_cast<int>(mHeight) || (rect.left % 2) || (rect.top % 2) ||
+ (rect.width % 2) || (rect.height % 2)) {
+ ALOGE("%s: bad rect left %d top %d w %d h %d", __FUNCTION__, rect.left, rect.top,
+ rect.width, rect.height);
+ return -1;
+ }
+
+ out->y = mData.data() + mWidth * rect.top + rect.left;
+ out->yStride = mWidth;
+ uint8_t* cbStart = mData.data() + mWidth * mHeight;
+ uint8_t* crStart = cbStart + mWidth * mHeight / 4;
+ out->cb = cbStart + mWidth * rect.top / 4 + rect.left / 2;
+ out->cr = crStart + mWidth * rect.top / 4 + rect.left / 2;
+ out->cStride = mWidth / 2;
+ out->chromaStep = 1;
+ return 0;
+}
+
+bool isAspectRatioClose(float ar1, float ar2) {
+ constexpr float kAspectRatioMatchThres = 0.025f; // This threshold is good enough to
+ // distinguish 4:3/16:9/20:9 1.33/1.78/2
+ return std::abs(ar1 - ar2) < kAspectRatioMatchThres;
+}
+
+aidl::android::hardware::camera::common::Status importBufferImpl(
+ /*inout*/ std::map<int, CirculatingBuffers>& circulatingBuffers,
+ /*inout*/ HandleImporter& handleImporter, int32_t streamId, uint64_t bufId,
+ buffer_handle_t buf,
+ /*out*/ buffer_handle_t** outBufPtr) {
+ using ::aidl::android::hardware::camera::common::Status;
+ if (buf == nullptr && bufId == BUFFER_ID_NO_BUFFER) {
+ ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId);
+ return Status::ILLEGAL_ARGUMENT;
+ }
+
+ CirculatingBuffers& cbs = circulatingBuffers[streamId];
+ if (cbs.count(bufId) == 0) {
+ if (buf == nullptr) {
+ ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId);
+ return Status::ILLEGAL_ARGUMENT;
+ }
+ // Register a newly seen buffer
+ buffer_handle_t importedBuf = buf;
+ handleImporter.importBuffer(importedBuf);
+ if (importedBuf == nullptr) {
+ ALOGE("%s: output buffer for stream %d is invalid!", __FUNCTION__, streamId);
+ return Status::INTERNAL_ERROR;
+ } else {
+ cbs[bufId] = importedBuf;
+ }
+ }
+ *outBufPtr = &cbs[bufId];
+ return Status::OK;
+}
+
+uint32_t getFourCcFromLayout(const YCbCrLayout& layout) {
+ intptr_t cb = reinterpret_cast<intptr_t>(layout.cb);
+ intptr_t cr = reinterpret_cast<intptr_t>(layout.cr);
+ if (std::abs(cb - cr) == 1 && layout.chromaStep == 2) {
+ // Interleaved format
+ if (layout.cb > layout.cr) {
+ return V4L2_PIX_FMT_NV21;
+ } else {
+ return V4L2_PIX_FMT_NV12;
+ }
+ } else if (layout.chromaStep == 1) {
+ // Planar format
+ if (layout.cb > layout.cr) {
+ return V4L2_PIX_FMT_YVU420; // YV12
+ } else {
+ return V4L2_PIX_FMT_YUV420; // YU12
+ }
+ } else {
+ return FLEX_YUV_GENERIC;
+ }
+}
+
+int getCropRect(CroppingType ct, const Size& inSize, const Size& outSize, IMapper::Rect* out) {
+ if (out == nullptr) {
+ ALOGE("%s: out is null", __FUNCTION__);
+ return -1;
+ }
+
+ uint32_t inW = inSize.width;
+ uint32_t inH = inSize.height;
+ uint32_t outW = outSize.width;
+ uint32_t outH = outSize.height;
+
+ // Handle special case where aspect ratio is close to input but scaled
+ // dimension is slightly larger than input
+ float arIn = ASPECT_RATIO(inSize);
+ float arOut = ASPECT_RATIO(outSize);
+ if (isAspectRatioClose(arIn, arOut)) {
+ out->left = 0;
+ out->top = 0;
+ out->width = static_cast<int32_t>(inW);
+ out->height = static_cast<int32_t>(inH);
+ return 0;
+ }
+
+ if (ct == VERTICAL) {
+ uint64_t scaledOutH = static_cast<uint64_t>(outH) * inW / outW;
+ if (scaledOutH > inH) {
+ ALOGE("%s: Output size %dx%d cannot be vertically cropped from input size %dx%d",
+ __FUNCTION__, outW, outH, inW, inH);
+ return -1;
+ }
+ scaledOutH = scaledOutH & ~0x1; // make it multiple of 2
+
+ out->left = 0;
+ out->top = static_cast<int32_t>((inH - scaledOutH) / 2) & ~0x1;
+ out->width = static_cast<int32_t>(inW);
+ out->height = static_cast<int32_t>(scaledOutH);
+ ALOGV("%s: crop %dx%d to %dx%d: top %d, scaledH %d", __FUNCTION__, inW, inH, outW, outH,
+ out->top, static_cast<int32_t>(scaledOutH));
+ } else {
+ uint64_t scaledOutW = static_cast<uint64_t>(outW) * inH / outH;
+ if (scaledOutW > inW) {
+ ALOGE("%s: Output size %dx%d cannot be horizontally cropped from input size %dx%d",
+ __FUNCTION__, outW, outH, inW, inH);
+ return -1;
+ }
+ scaledOutW = scaledOutW & ~0x1; // make it multiple of 2
+
+ out->left = static_cast<int32_t>((inW - scaledOutW) / 2) & ~0x1;
+ out->top = 0;
+ out->width = static_cast<int32_t>(scaledOutW);
+ out->height = static_cast<int32_t>(inH);
+ ALOGV("%s: crop %dx%d to %dx%d: top %d, scaledW %d", __FUNCTION__, inW, inH, outW, outH,
+ out->top, static_cast<int32_t>(scaledOutW));
+ }
+
+ return 0;
+}
+
+int formatConvert(const YCbCrLayout& in, const YCbCrLayout& out, Size sz, uint32_t format) {
+ int ret = 0;
+ switch (format) {
+ case V4L2_PIX_FMT_NV21:
+ ret = libyuv::I420ToNV21(
+ static_cast<uint8_t*>(in.y), static_cast<int32_t>(in.yStride),
+ static_cast<uint8_t*>(in.cb), static_cast<int32_t>(in.cStride),
+ static_cast<uint8_t*>(in.cr), static_cast<int32_t>(in.cStride),
+ static_cast<uint8_t*>(out.y), static_cast<int32_t>(out.yStride),
+ static_cast<uint8_t*>(out.cr), static_cast<int32_t>(out.cStride),
+ static_cast<int32_t>(sz.width), static_cast<int32_t>(sz.height));
+ if (ret != 0) {
+ ALOGE("%s: convert to NV21 buffer failed! ret %d", __FUNCTION__, ret);
+ return ret;
+ }
+ break;
+ case V4L2_PIX_FMT_NV12:
+ ret = libyuv::I420ToNV12(
+ static_cast<uint8_t*>(in.y), static_cast<int32_t>(in.yStride),
+ static_cast<uint8_t*>(in.cb), static_cast<int32_t>(in.cStride),
+ static_cast<uint8_t*>(in.cr), static_cast<int32_t>(in.cStride),
+ static_cast<uint8_t*>(out.y), static_cast<int32_t>(out.yStride),
+ static_cast<uint8_t*>(out.cb), static_cast<int32_t>(out.cStride),
+ static_cast<int32_t>(sz.width), static_cast<int32_t>(sz.height));
+ if (ret != 0) {
+ ALOGE("%s: convert to NV12 buffer failed! ret %d", __FUNCTION__, ret);
+ return ret;
+ }
+ break;
+ case V4L2_PIX_FMT_YVU420: // YV12
+ case V4L2_PIX_FMT_YUV420: // YU12
+ // TODO: maybe we can speed up here by somehow save this copy?
+ ret = libyuv::I420Copy(static_cast<uint8_t*>(in.y), static_cast<int32_t>(in.yStride),
+ static_cast<uint8_t*>(in.cb), static_cast<int32_t>(in.cStride),
+ static_cast<uint8_t*>(in.cr), static_cast<int32_t>(in.cStride),
+ static_cast<uint8_t*>(out.y), static_cast<int32_t>(out.yStride),
+ static_cast<uint8_t*>(out.cb), static_cast<int32_t>(out.cStride),
+ static_cast<uint8_t*>(out.cr), static_cast<int32_t>(out.cStride),
+ static_cast<int32_t>(sz.width), static_cast<int32_t>(sz.height));
+ if (ret != 0) {
+ ALOGE("%s: copy to YV12 or YU12 buffer failed! ret %d", __FUNCTION__, ret);
+ return ret;
+ }
+ break;
+ case FLEX_YUV_GENERIC:
+ // TODO: b/72261744 write to arbitrary flexible YUV layout. Slow.
+ ALOGE("%s: unsupported flexible yuv layout"
+ " y %p cb %p cr %p y_str %d c_str %d c_step %d",
+ __FUNCTION__, out.y, out.cb, out.cr, out.yStride, out.cStride, out.chromaStep);
+ return -1;
+ default:
+ ALOGE("%s: unknown YUV format 0x%x!", __FUNCTION__, format);
+ return -1;
+ }
+ return 0;
+}
+
+int encodeJpegYU12(const Size& inSz, const YCbCrLayout& inLayout, int jpegQuality,
+ const void* app1Buffer, size_t app1Size, void* out, size_t maxOutSize,
+ size_t& actualCodeSize) {
+ /* libjpeg is a C library so we use C-style "inheritance" by
+ * putting libjpeg's jpeg_destination_mgr first in our custom
+ * struct. This allows us to cast jpeg_destination_mgr* to
+ * CustomJpegDestMgr* when we get it passed to us in a callback */
+ struct CustomJpegDestMgr {
+ struct jpeg_destination_mgr mgr;
+ JOCTET* mBuffer;
+ size_t mBufferSize;
+ size_t mEncodedSize;
+ bool mSuccess;
+ } dmgr;
+
+ jpeg_compress_struct cinfo = {};
+ jpeg_error_mgr jerr;
+
+ /* Initialize error handling with standard callbacks, but
+ * then override output_message (to print to ALOG) and
+ * error_exit to set a flag and print a message instead
+ * of killing the whole process */
+ cinfo.err = jpeg_std_error(&jerr);
+
+ cinfo.err->output_message = [](j_common_ptr cinfo) {
+ char buffer[JMSG_LENGTH_MAX];
+
+ /* Create the message */
+ (*cinfo->err->format_message)(cinfo, buffer);
+ ALOGE("libjpeg error: %s", buffer);
+ };
+ cinfo.err->error_exit = [](j_common_ptr cinfo) {
+ (*cinfo->err->output_message)(cinfo);
+ if (cinfo->client_data) {
+ auto& dmgr = *reinterpret_cast<CustomJpegDestMgr*>(cinfo->client_data);
+ dmgr.mSuccess = false;
+ }
+ };
+
+ /* Now that we initialized some callbacks, let's create our compressor */
+ jpeg_create_compress(&cinfo);
+
+ /* Initialize our destination manager */
+ dmgr.mBuffer = static_cast<JOCTET*>(out);
+ dmgr.mBufferSize = maxOutSize;
+ dmgr.mEncodedSize = 0;
+ dmgr.mSuccess = true;
+ cinfo.client_data = static_cast<void*>(&dmgr);
+
+ /* These lambdas become C-style function pointers and as per C++11 spec
+ * may not capture anything */
+ dmgr.mgr.init_destination = [](j_compress_ptr cinfo) {
+ auto& dmgr = reinterpret_cast<CustomJpegDestMgr&>(*cinfo->dest);
+ dmgr.mgr.next_output_byte = dmgr.mBuffer;
+ dmgr.mgr.free_in_buffer = dmgr.mBufferSize;
+ ALOGV("%s:%d jpeg start: %p [%zu]", __FUNCTION__, __LINE__, dmgr.mBuffer, dmgr.mBufferSize);
+ };
+
+ dmgr.mgr.empty_output_buffer = [](j_compress_ptr cinfo __unused) {
+ ALOGV("%s:%d Out of buffer", __FUNCTION__, __LINE__);
+ return 0;
+ };
+
+ dmgr.mgr.term_destination = [](j_compress_ptr cinfo) {
+ auto& dmgr = reinterpret_cast<CustomJpegDestMgr&>(*cinfo->dest);
+ dmgr.mEncodedSize = dmgr.mBufferSize - dmgr.mgr.free_in_buffer;
+ ALOGV("%s:%d Done with jpeg: %zu", __FUNCTION__, __LINE__, dmgr.mEncodedSize);
+ };
+ cinfo.dest = reinterpret_cast<struct jpeg_destination_mgr*>(&dmgr);
+
+ /* We are going to be using JPEG in raw data mode, so we are passing
+ * straight subsampled planar YCbCr and it will not touch our pixel
+ * data or do any scaling or anything */
+ cinfo.image_width = inSz.width;
+ cinfo.image_height = inSz.height;
+ cinfo.input_components = 3;
+ cinfo.in_color_space = JCS_YCbCr;
+
+ /* Initialize defaults and then override what we want */
+ jpeg_set_defaults(&cinfo);
+
+ jpeg_set_quality(&cinfo, jpegQuality, 1);
+ jpeg_set_colorspace(&cinfo, JCS_YCbCr);
+ cinfo.raw_data_in = 1;
+ cinfo.dct_method = JDCT_IFAST;
+
+ /* Configure sampling factors. The sampling factor is JPEG subsampling 420
+ * because the source format is YUV420. Note that libjpeg sampling factors
+ * are... a little weird. Sampling of Y=2,U=1,V=1 means there is 1 U and
+ * 1 V value for each 2 Y values */
+ cinfo.comp_info[0].h_samp_factor = 2;
+ cinfo.comp_info[0].v_samp_factor = 2;
+ cinfo.comp_info[1].h_samp_factor = 1;
+ cinfo.comp_info[1].v_samp_factor = 1;
+ cinfo.comp_info[2].h_samp_factor = 1;
+ cinfo.comp_info[2].v_samp_factor = 1;
+
+ /* Start the compressor */
+ jpeg_start_compress(&cinfo, TRUE);
+
+ /* Let's not hardcode YUV420 in 6 places... 5 was enough */
+ int maxVSampFactor = cinfo.max_v_samp_factor;
+ int cVSubSampling = cinfo.comp_info[0].v_samp_factor / cinfo.comp_info[1].v_samp_factor;
+
+ /* Compute our macroblock height, so we can pad our input to be vertically
+ * macroblock aligned. No need to for horizontal alignment since AllocatedFrame already
+ * pads horizontally */
+
+ size_t mcuV = DCTSIZE * maxVSampFactor;
+ size_t paddedHeight = mcuV * ((inSz.height + mcuV - 1) / mcuV);
+
+ /* libjpeg uses arrays of row pointers, which makes it really easy to pad
+ * data vertically (unfortunately doesn't help horizontally) */
+ std::vector<JSAMPROW> yLines(paddedHeight);
+ std::vector<JSAMPROW> cbLines(paddedHeight / cVSubSampling);
+ std::vector<JSAMPROW> crLines(paddedHeight / cVSubSampling);
+
+ uint8_t* py = static_cast<uint8_t*>(inLayout.y);
+ uint8_t* pcb = static_cast<uint8_t*>(inLayout.cb);
+ uint8_t* pcr = static_cast<uint8_t*>(inLayout.cr);
+
+ for (int32_t i = 0; i < paddedHeight; i++) {
+ /* Once we are in the padding territory we still point to the last line
+ * effectively replicating it several times ~ CLAMP_TO_EDGE */
+ int li = std::min(i, inSz.height - 1);
+ yLines[i] = static_cast<JSAMPROW>(py + li * inLayout.yStride);
+ if (i < paddedHeight / cVSubSampling) {
+ li = std::min(i, (inSz.height - 1) / cVSubSampling);
+ cbLines[i] = static_cast<JSAMPROW>(pcb + li * inLayout.cStride);
+ crLines[i] = static_cast<JSAMPROW>(pcr + li * inLayout.cStride);
+ }
+ }
+
+ /* If APP1 data was passed in, use it */
+ if (app1Buffer && app1Size) {
+ jpeg_write_marker(&cinfo, JPEG_APP0 + 1, static_cast<const JOCTET*>(app1Buffer), app1Size);
+ }
+
+ /* While we still have padded height left to go, keep giving it one
+ * macroblock at a time. */
+ while (cinfo.next_scanline < cinfo.image_height) {
+ const uint32_t batchSize = DCTSIZE * maxVSampFactor;
+ const uint32_t nl = cinfo.next_scanline;
+ JSAMPARRAY planes[3]{&yLines[nl], &cbLines[nl / cVSubSampling],
+ &crLines[nl / cVSubSampling]};
+
+ uint32_t done = jpeg_write_raw_data(&cinfo, planes, batchSize);
+
+ if (done != batchSize) {
+ ALOGE("%s: compressed %u lines, expected %u (total %u/%u)", __FUNCTION__, done,
+ batchSize, cinfo.next_scanline, cinfo.image_height);
+ return -1;
+ }
+ }
+
+ /* This will flush everything */
+ jpeg_finish_compress(&cinfo);
+
+ /* Grab the actual code size and set it */
+ actualCodeSize = dmgr.mEncodedSize;
+
+ return 0;
+}
+
+Size getMaxThumbnailResolution(const common::V1_0::helper::CameraMetadata& chars) {
+ Size thumbSize{0, 0};
+ camera_metadata_ro_entry entry = chars.find(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES);
+ for (uint32_t i = 0; i < entry.count; i += 2) {
+ Size sz{.width = entry.data.i32[i], .height = entry.data.i32[i + 1]};
+ if (sz.width * sz.height > thumbSize.width * thumbSize.height) {
+ thumbSize = sz;
+ }
+ }
+
+ if (thumbSize.width * thumbSize.height == 0) {
+ ALOGW("%s: non-zero thumbnail size not available", __FUNCTION__);
+ }
+
+ return thumbSize;
+}
+
+void freeReleaseFences(std::vector<CaptureResult>& results) {
+ for (auto& result : results) {
+ native_handle_t* inputReleaseFence =
+ ::android::makeFromAidl(result.inputBuffer.releaseFence);
+ if (inputReleaseFence != nullptr) {
+ native_handle_close(inputReleaseFence);
+ native_handle_delete(inputReleaseFence);
+ }
+ for (auto& buf : result.outputBuffers) {
+ native_handle_t* outReleaseFence = ::android::makeFromAidl(buf.releaseFence);
+ if (outReleaseFence != nullptr) {
+ native_handle_close(outReleaseFence);
+ native_handle_delete(outReleaseFence);
+ }
+ }
+ }
+}
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#define UPDATE(md, tag, data, size) \
+ do { \
+ if ((md).update((tag), (data), (size))) { \
+ ALOGE("Update " #tag " failed!"); \
+ return BAD_VALUE; \
+ } \
+ } while (0)
+
+status_t fillCaptureResultCommon(CameraMetadata& md, nsecs_t timestamp,
+ camera_metadata_ro_entry& activeArraySize) {
+ if (activeArraySize.count < 4) {
+ ALOGE("%s: cannot find active array size!", __FUNCTION__);
+ return -EINVAL;
+ }
+ // android.control
+ // For USB camera, we don't know the AE state. Set the state to converged to
+ // indicate the frame should be good to use. Then apps don't have to wait the
+ // AE state.
+ const uint8_t aeState = ANDROID_CONTROL_AE_STATE_CONVERGED;
+ UPDATE(md, ANDROID_CONTROL_AE_STATE, &aeState, 1);
+
+ const uint8_t ae_lock = ANDROID_CONTROL_AE_LOCK_OFF;
+ UPDATE(md, ANDROID_CONTROL_AE_LOCK, &ae_lock, 1);
+
+ // Set AWB state to converged to indicate the frame should be good to use.
+ const uint8_t awbState = ANDROID_CONTROL_AWB_STATE_CONVERGED;
+ UPDATE(md, ANDROID_CONTROL_AWB_STATE, &awbState, 1);
+
+ const uint8_t awbLock = ANDROID_CONTROL_AWB_LOCK_OFF;
+ UPDATE(md, ANDROID_CONTROL_AWB_LOCK, &awbLock, 1);
+
+ const uint8_t flashState = ANDROID_FLASH_STATE_UNAVAILABLE;
+ UPDATE(md, ANDROID_FLASH_STATE, &flashState, 1);
+
+ // This means pipeline latency of X frame intervals. The maximum number is 4.
+ const uint8_t requestPipelineMaxDepth = 4;
+ UPDATE(md, ANDROID_REQUEST_PIPELINE_DEPTH, &requestPipelineMaxDepth, 1);
+
+ // android.scaler
+ const int32_t crop_region[] = {
+ activeArraySize.data.i32[0],
+ activeArraySize.data.i32[1],
+ activeArraySize.data.i32[2],
+ activeArraySize.data.i32[3],
+ };
+ UPDATE(md, ANDROID_SCALER_CROP_REGION, crop_region, ARRAY_SIZE(crop_region));
+
+ // android.sensor
+ UPDATE(md, ANDROID_SENSOR_TIMESTAMP, ×tamp, 1);
+
+ // android.statistics
+ const uint8_t lensShadingMapMode = ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF;
+ UPDATE(md, ANDROID_STATISTICS_LENS_SHADING_MAP_MODE, &lensShadingMapMode, 1);
+
+ const uint8_t sceneFlicker = ANDROID_STATISTICS_SCENE_FLICKER_NONE;
+ UPDATE(md, ANDROID_STATISTICS_SCENE_FLICKER, &sceneFlicker, 1);
+
+ return OK;
+}
+
+#undef ARRAY_SIZE
+#undef UPDATE
+
+AllocatedV4L2Frame::AllocatedV4L2Frame(std::shared_ptr<V4L2Frame> frameIn)
+ : Frame(frameIn->mWidth, frameIn->mHeight, frameIn->mFourcc) {
+ uint8_t* dataIn;
+ size_t dataSize;
+ if (frameIn->getData(&dataIn, &dataSize) != 0) {
+ ALOGE("%s: map input V4L2 frame failed!", __FUNCTION__);
+ return;
+ }
+
+ mData.resize(dataSize);
+ std::memcpy(mData.data(), dataIn, dataSize);
+}
+
+AllocatedV4L2Frame::~AllocatedV4L2Frame() {}
+
+int AllocatedV4L2Frame::getData(uint8_t** outData, size_t* dataSize) {
+ if (outData == nullptr || dataSize == nullptr) {
+ ALOGE("%s: outData(%p)/dataSize(%p) must not be null", __FUNCTION__, outData, dataSize);
+ return -1;
+ }
+
+ *outData = mData.data();
+ *dataSize = mData.size();
+ return 0;
+}
+
+} // namespace implementation
+} // namespace device
+} // namespace camera
+} // namespace hardware
+} // namespace android
\ No newline at end of file
diff --git a/camera/device/default/ExternalCameraUtils.h b/camera/device/default/ExternalCameraUtils.h
new file mode 100644
index 0000000..b37933c
--- /dev/null
+++ b/camera/device/default/ExternalCameraUtils.h
@@ -0,0 +1,300 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HARDWARE_INTERFACES_CAMERA_DEVICE_DEFAULT_EXTERNALCAMERAUTILS_H_
+#define HARDWARE_INTERFACES_CAMERA_DEVICE_DEFAULT_EXTERNALCAMERAUTILS_H_
+
+#include <CameraMetadata.h>
+#include <HandleImporter.h>
+#include <aidl/android/hardware/camera/common/Status.h>
+#include <aidl/android/hardware/camera/device/CaptureResult.h>
+#include <aidl/android/hardware/camera/device/ErrorCode.h>
+#include <aidl/android/hardware/camera/device/NotifyMsg.h>
+#include <aidl/android/hardware/graphics/common/BufferUsage.h>
+#include <aidl/android/hardware/graphics/common/PixelFormat.h>
+#include <tinyxml2.h>
+#include <unordered_map>
+#include <unordered_set>
+
+using ::aidl::android::hardware::camera::common::Status;
+using ::aidl::android::hardware::camera::device::CaptureResult;
+using ::aidl::android::hardware::camera::device::ErrorCode;
+using ::aidl::android::hardware::camera::device::NotifyMsg;
+using ::aidl::android::hardware::graphics::common::BufferUsage;
+using ::aidl::android::hardware::graphics::common::PixelFormat;
+using ::android::hardware::camera::common::V1_0::helper::CameraMetadata;
+using ::android::hardware::camera::common::V1_0::helper::HandleImporter;
+
+namespace android {
+namespace hardware {
+namespace camera {
+
+namespace external {
+namespace common {
+
+struct Size {
+ int32_t width;
+ int32_t height;
+
+ bool operator==(const Size& other) const {
+ return (width == other.width && height == other.height);
+ }
+};
+
+struct SizeHasher {
+ size_t operator()(const Size& sz) const {
+ size_t result = 1;
+ result = 31 * result + sz.width;
+ result = 31 * result + sz.height;
+ return result;
+ }
+};
+
+struct ExternalCameraConfig {
+ static const char* kDefaultCfgPath;
+ static ExternalCameraConfig loadFromCfg(const char* cfgPath = kDefaultCfgPath);
+
+ // CameraId base offset for numerical representation
+ uint32_t cameraIdOffset;
+
+ // List of internal V4L2 video nodes external camera HAL must ignore.
+ std::unordered_set<std::string> mInternalDevices;
+
+ // Maximal size of a JPEG buffer, in bytes
+ int32_t maxJpegBufSize;
+
+ // Maximum Size that can sustain 30fps streaming
+ Size maxVideoSize;
+
+ // Size of v4l2 buffer queue when streaming <= kMaxVideoSize
+ uint32_t numVideoBuffers;
+
+ // Size of v4l2 buffer queue when streaming > kMaxVideoSize
+ uint32_t numStillBuffers;
+
+ // Indication that the device connected supports depth output
+ bool depthEnabled;
+
+ struct FpsLimitation {
+ Size size;
+ double fpsUpperBound;
+ };
+ std::vector<FpsLimitation> fpsLimits;
+ std::vector<FpsLimitation> depthFpsLimits;
+
+ // Minimum output stream size
+ Size minStreamSize;
+
+ // The value of android.sensor.orientation
+ int32_t orientation;
+
+ private:
+ ExternalCameraConfig();
+ static bool updateFpsList(tinyxml2::XMLElement* fpsList, std::vector<FpsLimitation>& fpsLimits);
+};
+
+} // namespace common
+} // namespace external
+
+namespace device {
+namespace implementation {
+
+struct SupportedV4L2Format {
+ int32_t width;
+ int32_t height;
+ uint32_t fourcc;
+ // All supported frame rate for this w/h/fourcc combination
+ struct FrameRate {
+ // Duration (in seconds) of a single frame.
+ // Numerator and denominator of the frame duration are stored separately.
+ // For ex. a frame lasting 1/30 of a second will be stored as {1, 30}
+ uint32_t durationNumerator; // frame duration numerator. Ex: 1
+ uint32_t durationDenominator; // frame duration denominator. Ex: 30
+ double getFramesPerSecond() const; // FPS as double. Ex: 30.0
+ };
+ std::vector<FrameRate> frameRates;
+};
+
+// A Base class with basic information about a frame
+struct Frame : public std::enable_shared_from_this<Frame> {
+ public:
+ Frame(uint32_t width, uint32_t height, uint32_t fourcc);
+ virtual ~Frame();
+ const int32_t mWidth;
+ const int32_t mHeight;
+ const uint32_t mFourcc;
+
+ // getData might involve map/allocation
+ virtual int getData(uint8_t** outData, size_t* dataSize) = 0;
+};
+
+// A class provide access to a dequeued V4L2 frame buffer (mostly in MJPG format)
+// Also contains necessary information to enqueue the buffer back to V4L2 buffer queue
+class V4L2Frame : public Frame {
+ public:
+ V4L2Frame(uint32_t w, uint32_t h, uint32_t fourcc, int bufIdx, int fd, uint32_t dataSize,
+ uint64_t offset);
+ virtual ~V4L2Frame();
+
+ virtual int getData(uint8_t** outData, size_t* dataSize) override;
+
+ const int mBufferIndex; // for later enqueue
+ int map(uint8_t** data, size_t* dataSize);
+ int unmap();
+
+ private:
+ std::mutex mLock;
+ const int mFd; // used for mmap but doesn't claim ownership
+ const size_t mDataSize;
+ const uint64_t mOffset; // used for mmap
+ uint8_t* mData = nullptr;
+ bool mMapped = false;
+};
+
+// A RAII class representing a CPU allocated YUV frame used as intermediate buffers
+// when generating output images.
+class AllocatedFrame : public Frame {
+ public:
+ AllocatedFrame(uint32_t w, uint32_t h); // only support V4L2_PIX_FMT_YUV420 for now
+ ~AllocatedFrame() override;
+
+ virtual int getData(uint8_t** outData, size_t* dataSize) override;
+
+ int allocate(YCbCrLayout* out = nullptr);
+ int getLayout(YCbCrLayout* out);
+ int getCroppedLayout(const IMapper::Rect&, YCbCrLayout* out); // return non-zero for bad input
+ private:
+ std::mutex mLock;
+ std::vector<uint8_t> mData;
+ size_t mBufferSize; // size of mData before padding. Actual size of mData might be slightly
+ // bigger to horizontally pad the frame for jpeglib.
+};
+
+enum CroppingType { HORIZONTAL = 0, VERTICAL = 1 };
+
+// Aspect ratio is defined as width/height here and ExternalCameraDevice
+// will guarantee all supported sizes has width >= height (so aspect ratio >= 1.0)
+#define ASPECT_RATIO(sz) (static_cast<float>((sz).width) / (sz).height)
+const float kMaxAspectRatio = std::numeric_limits<float>::max();
+const float kMinAspectRatio = 1.f;
+
+bool isAspectRatioClose(float ar1, float ar2);
+
+struct HalStreamBuffer {
+ int32_t streamId;
+ int64_t bufferId;
+ int32_t width;
+ int32_t height;
+ ::aidl::android::hardware::graphics::common::PixelFormat format;
+ ::aidl::android::hardware::graphics::common::BufferUsage usage;
+ buffer_handle_t* bufPtr;
+ int acquireFence;
+ bool fenceTimeout;
+};
+
+struct HalRequest {
+ int32_t frameNumber;
+ common::V1_0::helper::CameraMetadata setting;
+ std::shared_ptr<Frame> frameIn;
+ nsecs_t shutterTs;
+ std::vector<HalStreamBuffer> buffers;
+};
+
+static const uint64_t BUFFER_ID_NO_BUFFER = 0;
+
+// buffers currently circulating between HAL and camera service
+// key: bufferId sent via HIDL interface
+// value: imported buffer_handle_t
+// Buffer will be imported during processCaptureRequest (or requestStreamBuffer
+// in the case of HAL buffer manager is enabled) and will be freed
+// when the stream is deleted or camera device session is closed
+typedef std::unordered_map<uint64_t, buffer_handle_t> CirculatingBuffers;
+
+aidl::android::hardware::camera::common::Status importBufferImpl(
+ /*inout*/ std::map<int, CirculatingBuffers>& circulatingBuffers,
+ /*inout*/ HandleImporter& handleImporter, int32_t streamId, uint64_t bufId,
+ buffer_handle_t buf,
+ /*out*/ buffer_handle_t** outBufPtr);
+
+static const uint32_t FLEX_YUV_GENERIC =
+ static_cast<uint32_t>('F') | static_cast<uint32_t>('L') << 8 |
+ static_cast<uint32_t>('E') << 16 | static_cast<uint32_t>('X') << 24;
+
+// returns FLEX_YUV_GENERIC for formats other than YV12/YU12/NV12/NV21
+uint32_t getFourCcFromLayout(const YCbCrLayout&);
+
+using ::android::hardware::camera::external::common::Size;
+int getCropRect(CroppingType ct, const Size& inSize, const Size& outSize, IMapper::Rect* out);
+
+int formatConvert(const YCbCrLayout& in, const YCbCrLayout& out, Size sz, uint32_t format);
+
+int encodeJpegYU12(const Size& inSz, const YCbCrLayout& inLayout, int jpegQuality,
+ const void* app1Buffer, size_t app1Size, void* out, size_t maxOutSize,
+ size_t& actualCodeSize);
+
+Size getMaxThumbnailResolution(const common::V1_0::helper::CameraMetadata&);
+
+void freeReleaseFences(std::vector<CaptureResult>&);
+
+status_t fillCaptureResultCommon(common::V1_0::helper::CameraMetadata& md, nsecs_t timestamp,
+ camera_metadata_ro_entry& activeArraySize);
+
+// Interface for OutputThread calling back to parent
+struct OutputThreadInterface {
+ virtual ~OutputThreadInterface() {}
+ virtual aidl::android::hardware::camera::common::Status importBuffer(
+ int32_t streamId, uint64_t bufId, buffer_handle_t buf,
+ /*out*/ buffer_handle_t** outBufPtr) = 0;
+
+ virtual void notifyError(int32_t frameNumber, int32_t streamId, ErrorCode ec) = 0;
+
+ // Callbacks are fired within the method if msgs/results are nullptr.
+ // Otherwise the callbacks will be returned and caller is responsible to
+ // fire the callback later
+ virtual aidl::android::hardware::camera::common::Status processCaptureRequestError(
+ const std::shared_ptr<HalRequest>&,
+ /*out*/ std::vector<NotifyMsg>* msgs,
+ /*out*/ std::vector<CaptureResult>* results) = 0;
+
+ virtual aidl::android::hardware::camera::common::Status processCaptureRequestError(
+ const std::shared_ptr<HalRequest>& reqs) final {
+ return processCaptureRequestError(reqs, nullptr, nullptr);
+ }
+
+ virtual aidl::android::hardware::camera::common::Status processCaptureResult(
+ std::shared_ptr<HalRequest>&) = 0;
+
+ virtual ssize_t getJpegBufferSize(int32_t width, int32_t height) const = 0;
+};
+
+// A CPU copy of a mapped V4L2Frame. Will map the input V4L2 frame.
+class AllocatedV4L2Frame : public Frame {
+ public:
+ AllocatedV4L2Frame(std::shared_ptr<V4L2Frame> frameIn);
+ ~AllocatedV4L2Frame() override;
+ virtual int getData(uint8_t** outData, size_t* dataSize) override;
+
+ private:
+ std::vector<uint8_t> mData;
+};
+
+} // namespace implementation
+} // namespace device
+} // namespace camera
+} // namespace hardware
+} // namespace android
+
+#endif // HARDWARE_INTERFACES_CAMERA_DEVICE_DEFAULT_EXTERNALCAMERAUTILS_H_
diff --git a/camera/common/1.0/default/OWNERS b/camera/device/default/OWNERS
similarity index 100%
copy from camera/common/1.0/default/OWNERS
copy to camera/device/default/OWNERS
diff --git a/camera/device/default/convert.cpp b/camera/device/default/convert.cpp
new file mode 100644
index 0000000..8134dd5
--- /dev/null
+++ b/camera/device/default/convert.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.camera.device@3.4-convert-impl"
+#include <log/log.h>
+
+#include "convert.h"
+
+#include <aidl/android/hardware/graphics/common/BufferUsage.h>
+#include <aidl/android/hardware/graphics/common/PixelFormat.h>
+#include <hardware/camera_common.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace implementation {
+
+using ::aidl::android::hardware::camera::device::ErrorCode;
+using ::aidl::android::hardware::camera::device::ErrorMsg;
+using ::aidl::android::hardware::camera::device::ShutterMsg;
+using ::aidl::android::hardware::graphics::common::BufferUsage;
+using ::aidl::android::hardware::graphics::common::PixelFormat;
+
+void convertToAidl(const camera_metadata_t* src, CameraMetadata* dest) {
+ if (src == nullptr) {
+ return;
+ }
+
+ size_t size = get_camera_metadata_size(src);
+ auto* src_start = (uint8_t*)src;
+ uint8_t* src_end = src_start + size;
+ dest->metadata.assign(src_start, src_end);
+}
+
+bool convertFromAidl(const CameraMetadata& src, const camera_metadata_t** dst) {
+ const std::vector<uint8_t>& metadata = src.metadata;
+ if (metadata.empty()) {
+ // Special case for null metadata
+ *dst = nullptr;
+ return true;
+ }
+
+ const uint8_t* data = metadata.data();
+ // check that the size of CameraMetadata match underlying camera_metadata_t
+ if (get_camera_metadata_size((camera_metadata_t*)data) != metadata.size()) {
+ ALOGE("%s: input CameraMetadata is corrupt!", __FUNCTION__);
+ return false;
+ }
+ *dst = (camera_metadata_t*)data;
+ return true;
+}
+
+} // namespace implementation
+} // namespace device
+} // namespace camera
+} // namespace hardware
+} // namespace android
diff --git a/camera/device/default/convert.h b/camera/device/default/convert.h
new file mode 100644
index 0000000..5a508fc
--- /dev/null
+++ b/camera/device/default/convert.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HARDWARE_INTERFACES_CAMERA_DEVICE_DEFAULT_CONVERT_H_
+#define HARDWARE_INTERFACES_CAMERA_DEVICE_DEFAULT_CONVERT_H_
+
+#include <aidl/android/hardware/camera/common/Status.h>
+#include <aidl/android/hardware/camera/device/BufferStatus.h>
+#include <aidl/android/hardware/camera/device/CameraMetadata.h>
+#include <aidl/android/hardware/camera/device/HalStream.h>
+#include <aidl/android/hardware/camera/device/NotifyMsg.h>
+#include <aidl/android/hardware/camera/device/Stream.h>
+#include <hardware/camera3.h>
+#include <system/camera_metadata.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace implementation {
+
+using ::aidl::android::hardware::camera::common::Status;
+using ::aidl::android::hardware::camera::device::BufferStatus;
+using ::aidl::android::hardware::camera::device::CameraMetadata;
+using ::aidl::android::hardware::camera::device::HalStream;
+using ::aidl::android::hardware::camera::device::NotifyMsg;
+using ::aidl::android::hardware::camera::device::Stream;
+
+void convertToAidl(const camera_metadata_t* src, CameraMetadata* dest);
+
+bool convertFromAidl(const CameraMetadata& src, const camera_metadata_t** dst);
+
+inline ndk::ScopedAStatus fromStatus(Status status) {
+ return status == Status::OK
+ ? ndk::ScopedAStatus::ok()
+ : ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(status));
+}
+
+} // namespace implementation
+} // namespace device
+} // namespace camera
+} // namespace hardware
+} // namespace android
+
+#endif // HARDWARE_INTERFACES_CAMERA_DEVICE_DEFAULT_CONVERT_H_
diff --git a/camera/metadata/aidl/Android.bp b/camera/metadata/aidl/Android.bp
index 301a943..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: {
@@ -19,6 +20,9 @@
java: {
enabled: false,
},
+ rust: {
+ enabled: true,
+ }
},
versions_with_info: [
{
diff --git a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataSection.aidl b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataSection.aidl
index 8bed156..d99f16e 100644
--- a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataSection.aidl
+++ b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataSection.aidl
@@ -70,5 +70,7 @@
ANDROID_HEIC_INFO = 29,
ANDROID_AUTOMOTIVE = 30,
ANDROID_AUTOMOTIVE_LENS = 31,
+ ANDROID_EXTENSION = 32,
+ ANDROID_JPEGR = 33,
VENDOR_SECTION = 32768,
}
diff --git a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataSectionStart.aidl b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataSectionStart.aidl
index 1725347..0bcd846 100644
--- a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataSectionStart.aidl
+++ b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataSectionStart.aidl
@@ -70,5 +70,7 @@
ANDROID_HEIC_INFO_START = 1900544,
ANDROID_AUTOMOTIVE_START = 1966080,
ANDROID_AUTOMOTIVE_LENS_START = 2031616,
+ ANDROID_EXTENSION_START = 2097152,
+ ANDROID_JPEGR_START = 2162688,
VENDOR_SECTION_START = -2147483648,
}
diff --git a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataTag.aidl b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataTag.aidl
index ecbfc93..b836dbe 100644
--- a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataTag.aidl
+++ b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataTag.aidl
@@ -335,4 +335,10 @@
ANDROID_HEIC_INFO_MAX_JPEG_APP_SEGMENTS_COUNT = 1900545,
ANDROID_AUTOMOTIVE_LOCATION = 1966080,
ANDROID_AUTOMOTIVE_LENS_FACING = 2031616,
+ ANDROID_JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS = 2162688,
+ ANDROID_JPEGR_AVAILABLE_JPEG_R_MIN_FRAME_DURATIONS = 2162689,
+ ANDROID_JPEGR_AVAILABLE_JPEG_R_STALL_DURATIONS = 2162690,
+ ANDROID_JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION = 2162691,
+ ANDROID_JPEGR_AVAILABLE_JPEG_R_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION = 2162692,
+ ANDROID_JPEGR_AVAILABLE_JPEG_R_STALL_DURATIONS_MAXIMUM_RESOLUTION = 2162693,
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/JpegrAvailableJpegRStreamConfigurations.aidl
similarity index 75%
copy from audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
copy to camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/JpegrAvailableJpegRStreamConfigurations.aidl
index 8ad4848..cd005b5 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
+++ b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/JpegrAvailableJpegRStreamConfigurations.aidl
@@ -12,6 +12,10 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
+ *//*
+ * Autogenerated from camera metadata definitions in
+ * /system/media/camera/docs/metadata_definitions.xml
+ * *** DO NOT EDIT BY HAND ***
*/
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
@@ -31,27 +35,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;
-@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.camera.metadata;
+@Backing(type="int") @VintfStability
+enum JpegrAvailableJpegRStreamConfigurations {
+ ANDROID_JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS_OUTPUT = 0,
+ ANDROID_JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS_INPUT = 1,
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/JpegrAvailableJpegRStreamConfigurationsMaximumResolution.aidl
similarity index 75%
copy from audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
copy to camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/JpegrAvailableJpegRStreamConfigurationsMaximumResolution.aidl
index 8ad4848..68028db 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
+++ b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/JpegrAvailableJpegRStreamConfigurationsMaximumResolution.aidl
@@ -12,6 +12,10 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
+ *//*
+ * Autogenerated from camera metadata definitions in
+ * /system/media/camera/docs/metadata_definitions.xml
+ * *** DO NOT EDIT BY HAND ***
*/
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
@@ -31,27 +35,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;
-@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.camera.metadata;
+@Backing(type="int") @VintfStability
+enum JpegrAvailableJpegRStreamConfigurationsMaximumResolution {
+ ANDROID_JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION_OUTPUT = 0,
+ ANDROID_JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION_INPUT = 1,
}
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataSection.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataSection.aidl
index 99e28b9..73bcc12 100644
--- a/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataSection.aidl
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataSection.aidl
@@ -61,5 +61,7 @@
ANDROID_HEIC_INFO,
ANDROID_AUTOMOTIVE,
ANDROID_AUTOMOTIVE_LENS,
+ ANDROID_EXTENSION,
+ ANDROID_JPEGR,
VENDOR_SECTION = 0x8000,
}
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataSectionStart.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataSectionStart.aidl
index 62c71e9..75e7915 100644
--- a/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataSectionStart.aidl
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataSectionStart.aidl
@@ -63,5 +63,7 @@
ANDROID_HEIC_INFO_START = CameraMetadataSection.ANDROID_HEIC_INFO << 16,
ANDROID_AUTOMOTIVE_START = CameraMetadataSection.ANDROID_AUTOMOTIVE << 16,
ANDROID_AUTOMOTIVE_LENS_START = CameraMetadataSection.ANDROID_AUTOMOTIVE_LENS << 16,
+ ANDROID_EXTENSION_START = CameraMetadataSection.ANDROID_EXTENSION << 16,
+ ANDROID_JPEGR_START = CameraMetadataSection.ANDROID_JPEGR << 16,
VENDOR_SECTION_START = CameraMetadataSection.VENDOR_SECTION << 16,
}
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataTag.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataTag.aidl
index 2e9bde9..83e9230 100644
--- a/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataTag.aidl
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataTag.aidl
@@ -2298,4 +2298,56 @@
* passenger seats.</p>
*/
ANDROID_AUTOMOTIVE_LENS_FACING = CameraMetadataSectionStart.ANDROID_AUTOMOTIVE_LENS_START,
+ /**
+ * android.jpegr.availableJpegRStreamConfigurations [static, enum[], ndk_public]
+ *
+ * <p>The available Jpeg/R stream
+ * configurations that this camera device supports
+ * (i.e. format, width, height, output/input stream).</p>
+ */
+ ANDROID_JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS = CameraMetadataSectionStart.ANDROID_JPEGR_START,
+ /**
+ * android.jpegr.availableJpegRMinFrameDurations [static, int64[], ndk_public]
+ *
+ * <p>This lists the minimum frame duration for each
+ * format/size combination for Jpeg/R output formats.</p>
+ */
+ ANDROID_JPEGR_AVAILABLE_JPEG_R_MIN_FRAME_DURATIONS,
+ /**
+ * android.jpegr.availableJpegRStallDurations [static, int64[], ndk_public]
+ *
+ * <p>This lists the maximum stall duration for each
+ * output format/size combination for Jpeg/R streams.</p>
+ */
+ ANDROID_JPEGR_AVAILABLE_JPEG_R_STALL_DURATIONS,
+ /**
+ * android.jpegr.availableJpegRStreamConfigurationsMaximumResolution [static, enum[], ndk_public]
+ *
+ * <p>The available Jpeg/R stream
+ * configurations that this camera device supports
+ * (i.e. format, width, height, output/input stream).</p>
+ */
+ ANDROID_JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION,
+ /**
+ * android.jpegr.availableJpegRMinFrameDurationsMaximumResolution [static, int64[], ndk_public]
+ *
+ * <p>This lists the minimum frame duration for each
+ * format/size combination for Jpeg/R output formats for CaptureRequests where
+ * ANDROID_SENSOR_PIXEL_MODE is set to
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+ *
+ * @see ANDROID_SENSOR_PIXEL_MODE
+ */
+ ANDROID_JPEGR_AVAILABLE_JPEG_R_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION,
+ /**
+ * android.jpegr.availableJpegRStallDurationsMaximumResolution [static, int64[], ndk_public]
+ *
+ * <p>This lists the maximum stall duration for each
+ * output format/size combination for Jpeg/R streams for CaptureRequests where
+ * ANDROID_SENSOR_PIXEL_MODE is set to
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+ *
+ * @see ANDROID_SENSOR_PIXEL_MODE
+ */
+ ANDROID_JPEGR_AVAILABLE_JPEG_R_STALL_DURATIONS_MAXIMUM_RESOLUTION,
}
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/JpegrAvailableJpegRStreamConfigurations.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/JpegrAvailableJpegRStreamConfigurations.aidl
new file mode 100644
index 0000000..911a062
--- /dev/null
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/JpegrAvailableJpegRStreamConfigurations.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Autogenerated from camera metadata definitions in
+ * /system/media/camera/docs/metadata_definitions.xml
+ * *** DO NOT EDIT BY HAND ***
+ */
+
+package android.hardware.camera.metadata;
+
+/**
+ * android.jpegr.availableJpegRStreamConfigurations enumeration values
+ * @see ANDROID_JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS
+ */
+@VintfStability
+@Backing(type="int")
+enum JpegrAvailableJpegRStreamConfigurations {
+ ANDROID_JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS_OUTPUT,
+ ANDROID_JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS_INPUT,
+}
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/JpegrAvailableJpegRStreamConfigurationsMaximumResolution.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/JpegrAvailableJpegRStreamConfigurationsMaximumResolution.aidl
new file mode 100644
index 0000000..9e78662
--- /dev/null
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/JpegrAvailableJpegRStreamConfigurationsMaximumResolution.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Autogenerated from camera metadata definitions in
+ * /system/media/camera/docs/metadata_definitions.xml
+ * *** DO NOT EDIT BY HAND ***
+ */
+
+package android.hardware.camera.metadata;
+
+/**
+ * android.jpegr.availableJpegRStreamConfigurationsMaximumResolution enumeration values
+ * @see ANDROID_JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION
+ */
+@VintfStability
+@Backing(type="int")
+enum JpegrAvailableJpegRStreamConfigurationsMaximumResolution {
+ ANDROID_JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION_OUTPUT,
+ ANDROID_JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION_INPUT,
+}
diff --git a/camera/provider/aidl/Android.bp b/camera/provider/aidl/Android.bp
index d7e613e..19dede0 100644
--- a/camera/provider/aidl/Android.bp
+++ b/camera/provider/aidl/Android.bp
@@ -26,6 +26,9 @@
cpp: {
enabled: false,
},
+ rust: {
+ enabled: true,
+ },
},
versions_with_info: [
{
diff --git a/camera/provider/default/Android.bp b/camera/provider/default/Android.bp
new file mode 100644
index 0000000..ed45cbe
--- /dev/null
+++ b/camera/provider/default/Android.bp
@@ -0,0 +1,104 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_shared {
+ name: "android.hardware.camera.provider-V1-external-impl",
+ defaults: ["hidl_defaults"],
+ proprietary: true,
+ srcs: [
+ "ExternalCameraProvider.cpp",
+ ],
+ shared_libs: [
+ "android.hardware.camera.common-V1-ndk",
+ "android.hardware.camera.device-V1-ndk",
+ "android.hardware.camera.provider-V1-ndk",
+ "android.hardware.graphics.mapper@2.0",
+ "android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
+ "android.hidl.allocator@1.0",
+ "android.hidl.memory@1.0",
+ "camera.device-external-impl",
+ "libbinder_ndk",
+ "libcamera_metadata",
+ "libcutils",
+ "libfmq",
+ "libhardware",
+ "libhidlbase",
+ "liblog",
+ "libtinyxml2",
+ "libutils",
+ ],
+ static_libs: [
+ "android.hardware.camera.common@1.0-helper",
+ ],
+ export_include_dirs: ["."],
+}
+
+cc_defaults {
+ name: "camera_external_service_defaults",
+ defaults: ["hidl_defaults"],
+ proprietary: true,
+ relative_install_path: "hw",
+ srcs: ["external-service.cpp"],
+ compile_multilib: "first",
+ shared_libs: [
+ "android.hardware.camera.common-V1-ndk",
+ "android.hardware.camera.device-V1-ndk",
+ "android.hardware.camera.provider-V1-ndk",
+ "android.hardware.camera.provider-V1-external-impl",
+ "android.hardware.graphics.mapper@2.0",
+ "android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
+ "android.hidl.allocator@1.0",
+ "android.hidl.memory@1.0",
+ "camera.device-external-impl",
+ "libbinder_ndk",
+ "libcamera_metadata",
+ "libcutils",
+ "libfmq",
+ "libhardware",
+ "libhidlbase",
+ "liblog",
+ "libtinyxml2",
+ "libutils",
+ ],
+ static_libs: [
+ "android.hardware.camera.common@1.0-helper",
+ ],
+}
+
+cc_binary {
+ name: "android.hardware.camera.provider-V1-external-service",
+ defaults: ["camera_external_service_defaults"],
+ init_rc: ["android.hardware.camera.provider-V1-external-service.rc"],
+}
+
+cc_binary {
+ name: "android.hardware.camera.provider-V1-external-service-lazy",
+ overrides: ["android.hardware.camera.provider-V1-external-service"],
+ defaults: ["camera_external_service_defaults"],
+ init_rc: ["android.hardware.camera.provider-V1-external-service-lazy.rc"],
+ cflags: ["-DLAZY_SERVICE"],
+}
diff --git a/camera/provider/default/ExternalCameraProvider.cpp b/camera/provider/default/ExternalCameraProvider.cpp
new file mode 100644
index 0000000..d47ddbf
--- /dev/null
+++ b/camera/provider/default/ExternalCameraProvider.cpp
@@ -0,0 +1,382 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "ExtCamPrvdr"
+// #define LOG_NDEBUG 0
+
+#include "ExternalCameraProvider.h"
+
+#include <ExternalCameraDevice.h>
+#include <aidl/android/hardware/camera/common/Status.h>
+#include <convert.h>
+#include <cutils/properties.h>
+#include <linux/videodev2.h>
+#include <log/log.h>
+#include <sys/inotify.h>
+#include <regex>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace provider {
+namespace implementation {
+
+using ::aidl::android::hardware::camera::common::Status;
+using ::android::hardware::camera::device::implementation::ExternalCameraDevice;
+using ::android::hardware::camera::device::implementation::fromStatus;
+using ::android::hardware::camera::external::common::ExternalCameraConfig;
+
+namespace {
+// "device@<version>/external/<id>"
+const std::regex kDeviceNameRE("device@([0-9]+\\.[0-9]+)/external/(.+)");
+const int kMaxDevicePathLen = 256;
+constexpr char kDevicePath[] = "/dev/";
+constexpr char kPrefix[] = "video";
+constexpr int kPrefixLen = sizeof(kPrefix) - 1;
+constexpr int kDevicePrefixLen = sizeof(kDevicePath) + kPrefixLen + 1;
+
+bool matchDeviceName(int cameraIdOffset, const std::string& deviceName, std::string* deviceVersion,
+ std::string* cameraDevicePath) {
+ std::smatch sm;
+ if (std::regex_match(deviceName, sm, kDeviceNameRE)) {
+ if (deviceVersion != nullptr) {
+ *deviceVersion = sm[1];
+ }
+ if (cameraDevicePath != nullptr) {
+ *cameraDevicePath = "/dev/video" + std::to_string(std::stoi(sm[2]) - cameraIdOffset);
+ }
+ return true;
+ }
+ return false;
+}
+} // namespace
+
+ExternalCameraProvider::ExternalCameraProvider() : mCfg(ExternalCameraConfig::loadFromCfg()) {
+ mHotPlugThread = std::make_shared<HotplugThread>(this);
+ mHotPlugThread->run();
+}
+
+ExternalCameraProvider::~ExternalCameraProvider() {
+ mHotPlugThread->requestExitAndWait();
+}
+
+ndk::ScopedAStatus ExternalCameraProvider::setCallback(
+ const std::shared_ptr<ICameraProviderCallback>& in_callback) {
+ {
+ Mutex::Autolock _l(mLock);
+ mCallback = in_callback;
+ }
+
+ if (mCallback == nullptr) {
+ return fromStatus(Status::OK);
+ }
+
+ for (const auto& pair : mCameraStatusMap) {
+ mCallback->cameraDeviceStatusChange(pair.first, pair.second);
+ }
+ return fromStatus(Status::OK);
+}
+
+ndk::ScopedAStatus ExternalCameraProvider::getVendorTags(
+ std::vector<VendorTagSection>* _aidl_return) {
+ if (_aidl_return == nullptr) {
+ return fromStatus(Status::ILLEGAL_ARGUMENT);
+ }
+ // No vendor tag support for USB camera
+ *_aidl_return = {};
+ return fromStatus(Status::OK);
+}
+
+ndk::ScopedAStatus ExternalCameraProvider::getCameraIdList(std::vector<std::string>* _aidl_return) {
+ if (_aidl_return == nullptr) {
+ return fromStatus(Status::ILLEGAL_ARGUMENT);
+ }
+ // External camera HAL always report 0 camera, and extra cameras
+ // are just reported via cameraDeviceStatusChange callbacks
+ *_aidl_return = {};
+ return fromStatus(Status::OK);
+}
+
+ndk::ScopedAStatus ExternalCameraProvider::getCameraDeviceInterface(
+ const std::string& in_cameraDeviceName, std::shared_ptr<ICameraDevice>* _aidl_return) {
+ if (_aidl_return == nullptr) {
+ return fromStatus(Status::ILLEGAL_ARGUMENT);
+ }
+ std::string cameraDevicePath, deviceVersion;
+ bool match = matchDeviceName(mCfg.cameraIdOffset, in_cameraDeviceName, &deviceVersion,
+ &cameraDevicePath);
+
+ if (!match) {
+ *_aidl_return = nullptr;
+ return fromStatus(Status::ILLEGAL_ARGUMENT);
+ }
+
+ if (mCameraStatusMap.count(in_cameraDeviceName) == 0 ||
+ mCameraStatusMap[in_cameraDeviceName] != CameraDeviceStatus::PRESENT) {
+ *_aidl_return = nullptr;
+ return fromStatus(Status::ILLEGAL_ARGUMENT);
+ }
+
+ ALOGV("Constructing external camera device");
+ std::shared_ptr<ExternalCameraDevice> deviceImpl =
+ ndk::SharedRefBase::make<ExternalCameraDevice>(cameraDevicePath, mCfg);
+ if (deviceImpl == nullptr || deviceImpl->isInitFailed()) {
+ ALOGE("%s: camera device %s init failed!", __FUNCTION__, cameraDevicePath.c_str());
+ *_aidl_return = nullptr;
+ return fromStatus(Status::INTERNAL_ERROR);
+ }
+
+ IF_ALOGV() {
+ int interfaceVersion;
+ deviceImpl->getInterfaceVersion(&interfaceVersion);
+ ALOGV("%s: device interface version: %d", __FUNCTION__, interfaceVersion);
+ }
+
+ *_aidl_return = deviceImpl;
+ return fromStatus(Status::OK);
+}
+
+ndk::ScopedAStatus ExternalCameraProvider::notifyDeviceStateChange(int64_t) {
+ return fromStatus(Status::OK);
+}
+
+ndk::ScopedAStatus ExternalCameraProvider::getConcurrentCameraIds(
+ std::vector<ConcurrentCameraIdCombination>* _aidl_return) {
+ if (_aidl_return == nullptr) {
+ return fromStatus(Status::ILLEGAL_ARGUMENT);
+ }
+ *_aidl_return = {};
+ return fromStatus(Status::OK);
+}
+
+ndk::ScopedAStatus ExternalCameraProvider::isConcurrentStreamCombinationSupported(
+ const std::vector<CameraIdAndStreamCombination>&, bool* _aidl_return) {
+ if (_aidl_return == nullptr) {
+ return fromStatus(Status::ILLEGAL_ARGUMENT);
+ }
+ // No concurrent stream combinations are supported
+ *_aidl_return = false;
+ return fromStatus(Status::OK);
+}
+
+void ExternalCameraProvider::addExternalCamera(const char* devName) {
+ ALOGV("%s: ExtCam: adding %s to External Camera HAL!", __FUNCTION__, devName);
+ Mutex::Autolock _l(mLock);
+ std::string deviceName;
+ std::string cameraId =
+ std::to_string(mCfg.cameraIdOffset + std::atoi(devName + kDevicePrefixLen));
+ deviceName =
+ std::string("device@") + ExternalCameraDevice::kDeviceVersion + "/external/" + cameraId;
+ mCameraStatusMap[deviceName] = CameraDeviceStatus::PRESENT;
+ if (mCallback != nullptr) {
+ mCallback->cameraDeviceStatusChange(deviceName, CameraDeviceStatus::PRESENT);
+ }
+}
+
+void ExternalCameraProvider::deviceAdded(const char* devName) {
+ {
+ base::unique_fd fd(::open(devName, O_RDWR));
+ if (fd.get() < 0) {
+ ALOGE("%s open v4l2 device %s failed:%s", __FUNCTION__, devName, strerror(errno));
+ return;
+ }
+
+ struct v4l2_capability capability;
+ int ret = ioctl(fd.get(), VIDIOC_QUERYCAP, &capability);
+ if (ret < 0) {
+ ALOGE("%s v4l2 QUERYCAP %s failed", __FUNCTION__, devName);
+ return;
+ }
+
+ if (!(capability.device_caps & V4L2_CAP_VIDEO_CAPTURE)) {
+ ALOGW("%s device %s does not support VIDEO_CAPTURE", __FUNCTION__, devName);
+ return;
+ }
+ }
+
+ // See if we can initialize ExternalCameraDevice correctly
+ std::shared_ptr<ExternalCameraDevice> deviceImpl =
+ ndk::SharedRefBase::make<ExternalCameraDevice>(devName, mCfg);
+ if (deviceImpl == nullptr || deviceImpl->isInitFailed()) {
+ ALOGW("%s: Attempt to init camera device %s failed!", __FUNCTION__, devName);
+ return;
+ }
+ deviceImpl.reset();
+ addExternalCamera(devName);
+}
+
+void ExternalCameraProvider::deviceRemoved(const char* devName) {
+ Mutex::Autolock _l(mLock);
+ std::string deviceName;
+ std::string cameraId =
+ std::to_string(mCfg.cameraIdOffset + std::atoi(devName + kDevicePrefixLen));
+
+ deviceName =
+ std::string("device@") + ExternalCameraDevice::kDeviceVersion + "/external/" + cameraId;
+
+ if (mCameraStatusMap.erase(deviceName) == 0) {
+ // Unknown device, do not fire callback
+ ALOGE("%s: cannot find camera device to remove %s", __FUNCTION__, devName);
+ return;
+ }
+
+ if (mCallback != nullptr) {
+ mCallback->cameraDeviceStatusChange(deviceName, CameraDeviceStatus::NOT_PRESENT);
+ }
+}
+
+void ExternalCameraProvider::updateAttachedCameras() {
+ ALOGV("%s start scanning for existing V4L2 devices", __FUNCTION__);
+
+ // Find existing /dev/video* devices
+ DIR* devdir = opendir(kDevicePath);
+ if (devdir == nullptr) {
+ ALOGE("%s: cannot open %s! Exiting threadloop", __FUNCTION__, kDevicePath);
+ return;
+ }
+
+ struct dirent* de;
+ while ((de = readdir(devdir)) != nullptr) {
+ // Find external v4l devices that's existing before we start watching and add them
+ if (!strncmp(kPrefix, de->d_name, kPrefixLen)) {
+ std::string deviceId(de->d_name + kPrefixLen);
+ if (mCfg.mInternalDevices.count(deviceId) == 0) {
+ ALOGV("Non-internal v4l device %s found", de->d_name);
+ char v4l2DevicePath[kMaxDevicePathLen];
+ snprintf(v4l2DevicePath, kMaxDevicePathLen, "%s%s", kDevicePath, de->d_name);
+ deviceAdded(v4l2DevicePath);
+ }
+ }
+ }
+ closedir(devdir);
+}
+
+// Start ExternalCameraProvider::HotplugThread functions
+
+ExternalCameraProvider::HotplugThread::HotplugThread(ExternalCameraProvider* parent)
+ : mParent(parent), mInternalDevices(parent->mCfg.mInternalDevices) {}
+
+ExternalCameraProvider::HotplugThread::~HotplugThread() {
+ // Clean up inotify descriptor if needed.
+ if (mINotifyFD >= 0) {
+ close(mINotifyFD);
+ }
+}
+
+bool ExternalCameraProvider::HotplugThread::initialize() {
+ // Update existing cameras
+ mParent->updateAttachedCameras();
+
+ // Set up non-blocking fd. The threadLoop will be responsible for polling read at the
+ // desired frequency
+ mINotifyFD = inotify_init();
+ if (mINotifyFD < 0) {
+ ALOGE("%s: inotify init failed! Exiting threadloop", __FUNCTION__);
+ return false;
+ }
+
+ // Start watching /dev/ directory for created and deleted files
+ mWd = inotify_add_watch(mINotifyFD, kDevicePath, IN_CREATE | IN_DELETE);
+ if (mWd < 0) {
+ ALOGE("%s: inotify add watch failed! Exiting threadloop", __FUNCTION__);
+ return false;
+ }
+
+ mPollFd = {.fd = mINotifyFD, .events = POLLIN};
+
+ mIsInitialized = true;
+ return true;
+}
+
+bool ExternalCameraProvider::HotplugThread::threadLoop() {
+ // Initialize inotify descriptors if needed.
+ if (!mIsInitialized && !initialize()) {
+ return true;
+ }
+
+ // poll /dev/* and handle timeouts and error
+ int pollRet = poll(&mPollFd, /* fd_count= */ 1, /* timeout= */ 250);
+ if (pollRet == 0) {
+ // no read event in 100ms
+ mPollFd.revents = 0;
+ return true;
+ } else if (pollRet < 0) {
+ ALOGE("%s: error while polling for /dev/*: %d", __FUNCTION__, errno);
+ mPollFd.revents = 0;
+ return true;
+ } else if (mPollFd.revents & POLLERR) {
+ ALOGE("%s: polling /dev/ returned POLLERR", __FUNCTION__);
+ mPollFd.revents = 0;
+ return true;
+ } else if (mPollFd.revents & POLLHUP) {
+ ALOGE("%s: polling /dev/ returned POLLHUP", __FUNCTION__);
+ mPollFd.revents = 0;
+ return true;
+ } else if (mPollFd.revents & POLLNVAL) {
+ ALOGE("%s: polling /dev/ returned POLLNVAL", __FUNCTION__);
+ mPollFd.revents = 0;
+ return true;
+ }
+ // mPollFd.revents must contain POLLIN, so safe to reset it before reading
+ mPollFd.revents = 0;
+
+ uint64_t offset = 0;
+ ssize_t ret = read(mINotifyFD, mEventBuf, sizeof(mEventBuf));
+ if (ret < sizeof(struct inotify_event)) {
+ // invalid event. skip
+ return true;
+ }
+
+ while (offset < ret) {
+ struct inotify_event* event = (struct inotify_event*)&mEventBuf[offset];
+ offset += sizeof(struct inotify_event) + event->len;
+
+ if (event->wd != mWd) {
+ // event for an unrelated descriptor. ignore.
+ continue;
+ }
+
+ ALOGV("%s inotify_event %s", __FUNCTION__, event->name);
+ if (strncmp(kPrefix, event->name, kPrefixLen) != 0) {
+ // event not for /dev/video*. ignore.
+ continue;
+ }
+
+ std::string deviceId = event->name + kPrefixLen;
+ if (mInternalDevices.count(deviceId) != 0) {
+ // update to an internal device. ignore.
+ continue;
+ }
+
+ char v4l2DevicePath[kMaxDevicePathLen];
+ snprintf(v4l2DevicePath, kMaxDevicePathLen, "%s%s", kDevicePath, event->name);
+
+ if (event->mask & IN_CREATE) {
+ mParent->deviceAdded(v4l2DevicePath);
+ } else if (event->mask & IN_DELETE) {
+ mParent->deviceRemoved(v4l2DevicePath);
+ }
+ }
+ return true;
+}
+
+// End ExternalCameraProvider::HotplugThread functions
+
+} // namespace implementation
+} // namespace provider
+} // namespace camera
+} // namespace hardware
+} // namespace android
\ No newline at end of file
diff --git a/camera/provider/default/ExternalCameraProvider.h b/camera/provider/default/ExternalCameraProvider.h
new file mode 100644
index 0000000..347a53c
--- /dev/null
+++ b/camera/provider/default/ExternalCameraProvider.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HARDWARE_INTERFACES_CAMERA_PROVIDER_DEFAULT_EXTERNALCAMERAPROVIDER_H_
+#define HARDWARE_INTERFACES_CAMERA_PROVIDER_DEFAULT_EXTERNALCAMERAPROVIDER_H_
+
+#include <ExternalCameraUtils.h>
+#include <SimpleThread.h>
+#include <aidl/android/hardware/camera/common/CameraDeviceStatus.h>
+#include <aidl/android/hardware/camera/common/VendorTagSection.h>
+#include <aidl/android/hardware/camera/device/ICameraDevice.h>
+#include <aidl/android/hardware/camera/provider/BnCameraProvider.h>
+#include <aidl/android/hardware/camera/provider/CameraIdAndStreamCombination.h>
+#include <aidl/android/hardware/camera/provider/ConcurrentCameraIdCombination.h>
+#include <aidl/android/hardware/camera/provider/ICameraProviderCallback.h>
+#include <poll.h>
+#include <utils/Mutex.h>
+#include <utils/Thread.h>
+#include <thread>
+#include <unordered_map>
+#include <unordered_set>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace provider {
+namespace implementation {
+
+using ::aidl::android::hardware::camera::common::CameraDeviceStatus;
+using ::aidl::android::hardware::camera::common::VendorTagSection;
+using ::aidl::android::hardware::camera::device::ICameraDevice;
+using ::aidl::android::hardware::camera::provider::BnCameraProvider;
+using ::aidl::android::hardware::camera::provider::CameraIdAndStreamCombination;
+using ::aidl::android::hardware::camera::provider::ConcurrentCameraIdCombination;
+using ::aidl::android::hardware::camera::provider::ICameraProviderCallback;
+using ::android::hardware::camera::common::helper::SimpleThread;
+using ::android::hardware::camera::external::common::ExternalCameraConfig;
+
+class ExternalCameraProvider : public BnCameraProvider {
+ public:
+ ExternalCameraProvider();
+ ~ExternalCameraProvider() override;
+ ndk::ScopedAStatus setCallback(
+ const std::shared_ptr<ICameraProviderCallback>& in_callback) override;
+ ndk::ScopedAStatus getVendorTags(std::vector<VendorTagSection>* _aidl_return) override;
+ ndk::ScopedAStatus getCameraIdList(std::vector<std::string>* _aidl_return) override;
+ ndk::ScopedAStatus getCameraDeviceInterface(
+ const std::string& in_cameraDeviceName,
+ std::shared_ptr<ICameraDevice>* _aidl_return) override;
+ ndk::ScopedAStatus notifyDeviceStateChange(int64_t in_deviceState) override;
+ ndk::ScopedAStatus getConcurrentCameraIds(
+ std::vector<ConcurrentCameraIdCombination>* _aidl_return) override;
+ ndk::ScopedAStatus isConcurrentStreamCombinationSupported(
+ const std::vector<CameraIdAndStreamCombination>& in_configs,
+ bool* _aidl_return) override;
+
+ private:
+ void addExternalCamera(const char* devName);
+ void deviceAdded(const char* devName);
+ void deviceRemoved(const char* devName);
+ void updateAttachedCameras();
+
+ // A separate thread to monitor '/dev' directory for '/dev/video*' entries
+ // This thread calls back into ExternalCameraProvider when an actionable change is detected.
+ class HotplugThread : public SimpleThread {
+ public:
+ explicit HotplugThread(ExternalCameraProvider* parent);
+ ~HotplugThread() override;
+
+ protected:
+ bool threadLoop() override;
+
+ private:
+ // Returns true if thread initialization succeeded, and false if thread initialization
+ // failed.
+ bool initialize();
+
+ ExternalCameraProvider* mParent = nullptr;
+ const std::unordered_set<std::string> mInternalDevices;
+
+ bool mIsInitialized = false;
+
+ int mINotifyFD = -1;
+ int mWd = -1;
+
+ // struct to wrap mINotifyFD and poll it with timeout
+ struct pollfd mPollFd = {};
+ char mEventBuf[512] = {0};
+ };
+
+ Mutex mLock;
+ std::shared_ptr<ICameraProviderCallback> mCallback = nullptr;
+ std::unordered_map<std::string, CameraDeviceStatus> mCameraStatusMap; // camera id -> status
+ const ExternalCameraConfig mCfg;
+ std::shared_ptr<HotplugThread> mHotPlugThread;
+};
+
+} // namespace implementation
+} // namespace provider
+} // namespace camera
+} // namespace hardware
+} // namespace android
+
+#endif // HARDWARE_INTERFACES_CAMERA_PROVIDER_DEFAULT_EXTERNALCAMERAPROVIDER_H_
diff --git a/camera/common/1.0/default/OWNERS b/camera/provider/default/OWNERS
similarity index 100%
copy from camera/common/1.0/default/OWNERS
copy to camera/provider/default/OWNERS
diff --git a/camera/provider/default/android.hardware.camera.provider-V1-external-service-lazy.rc b/camera/provider/default/android.hardware.camera.provider-V1-external-service-lazy.rc
new file mode 100644
index 0000000..dcdd88c
--- /dev/null
+++ b/camera/provider/default/android.hardware.camera.provider-V1-external-service-lazy.rc
@@ -0,0 +1,10 @@
+service vendor.camera.provider-ext /vendor/bin/hw/android.hardware.camera.provider-V1-external-service-lazy
+ interface aidl android.hardware.camera.provider.ICameraProvider/external/0
+ class hal
+ oneshot
+ disabled
+ user cameraserver
+ group audio camera input drmrpc usb
+ ioprio rt 4
+ capabilities SYS_NICE
+ task_profiles CameraServiceCapacity MaxPerformance
\ No newline at end of file
diff --git a/camera/provider/default/android.hardware.camera.provider-V1-external-service.rc b/camera/provider/default/android.hardware.camera.provider-V1-external-service.rc
new file mode 100644
index 0000000..302c56f
--- /dev/null
+++ b/camera/provider/default/android.hardware.camera.provider-V1-external-service.rc
@@ -0,0 +1,8 @@
+service vendor.camera.provider-ext /vendor/bin/hw/android.hardware.camera.provider-V1-external-service
+ interface aidl android.hardware.camera.provider.ICameraProvider/external/0
+ class hal
+ user cameraserver
+ group audio camera input drmrpc usb
+ ioprio rt 4
+ capabilities SYS_NICE
+ task_profiles CameraServiceCapacity MaxPerformance
\ No newline at end of file
diff --git a/camera/provider/default/external-service.cpp b/camera/provider/default/external-service.cpp
new file mode 100644
index 0000000..b18f182
--- /dev/null
+++ b/camera/provider/default/external-service.cpp
@@ -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.
+ */
+
+#include <ExternalCameraProvider.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+using ::android::hardware::camera::provider::implementation::ExternalCameraProvider;
+
+namespace {
+// Default recommended RPC thread count for camera provider implementations
+const int HWBINDER_THREAD_COUNT = 6;
+} // namespace
+
+int main() {
+ ALOGI("CameraProvider: external webcam service is starting.");
+
+ ABinderProcess_setThreadPoolMaxThreadCount(HWBINDER_THREAD_COUNT);
+
+ std::shared_ptr<ExternalCameraProvider> defaultProvider =
+ ndk::SharedRefBase::make<ExternalCameraProvider>();
+ const std::string serviceName = std::string(ExternalCameraProvider::descriptor) + "/external/0";
+
+#ifdef LAZY_SERVICE
+ binder_exception_t ret = AServiceManager_registerLazyService(defaultProvider->asBinder().get(),
+ serviceName.c_str());
+ LOG_ALWAYS_FATAL_IF(ret != EX_NONE,
+ "Error while registering lazy ext camera provider service: %d", ret);
+#else
+ binder_exception_t ret =
+ AServiceManager_addService(defaultProvider->asBinder().get(), serviceName.c_str());
+ LOG_ALWAYS_FATAL_IF(ret != EX_NONE, "Error while registering ext camera provider service: %d",
+ ret);
+#endif
+
+ ABinderProcess_joinThreadPool();
+ return EXIT_FAILURE; // should not reach
+}
\ No newline at end of file
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/AidlCasPluginDescriptor.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/AidlCasPluginDescriptor.aidl
index 7b8099f..89d8625 100644
--- a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/AidlCasPluginDescriptor.aidl
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/AidlCasPluginDescriptor.aidl
@@ -32,6 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.cas;
+/* @hide */
@VintfStability
parcelable AidlCasPluginDescriptor {
int caSystemId;
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/DestinationBuffer.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/DestinationBuffer.aidl
index dd355af..b69cc33 100644
--- a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/DestinationBuffer.aidl
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/DestinationBuffer.aidl
@@ -32,6 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.cas;
+/* @hide */
@VintfStability
union DestinationBuffer {
android.hardware.cas.SharedBuffer nonsecureMemory;
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ICas.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ICas.aidl
index e169beb..28c9eb0 100644
--- a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ICas.aidl
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ICas.aidl
@@ -32,6 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.cas;
+/* @hide */
@VintfStability
interface ICas {
void closeSession(in byte[] sessionId);
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ICasListener.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ICasListener.aidl
index ebc13ce..db75062 100644
--- a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ICasListener.aidl
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ICasListener.aidl
@@ -32,6 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.cas;
+/* @hide */
@VintfStability
interface ICasListener {
void onEvent(in int event, in int arg, in byte[] data);
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/IDescrambler.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/IDescrambler.aidl
index 9bf7903..411891b 100644
--- a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/IDescrambler.aidl
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/IDescrambler.aidl
@@ -32,6 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.cas;
+/* @hide */
@VintfStability
interface IDescrambler {
int descramble(in android.hardware.cas.ScramblingControl scramblingControl, in android.hardware.cas.SubSample[] subSamples, in android.hardware.cas.SharedBuffer srcBuffer, in long srcOffset, in android.hardware.cas.DestinationBuffer dstBuffer, in long dstOffset);
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/IMediaCasService.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/IMediaCasService.aidl
index f5c8018..1f945a7 100644
--- a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/IMediaCasService.aidl
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/IMediaCasService.aidl
@@ -32,6 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.cas;
+/* @hide */
@VintfStability
interface IMediaCasService {
android.hardware.cas.IDescrambler createDescrambler(in int CA_system_id);
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ScramblingMode.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ScramblingMode.aidl
index e3923c7..c73f482 100644
--- a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ScramblingMode.aidl
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ScramblingMode.aidl
@@ -44,9 +44,9 @@
DVB_IDSA = 7,
MULTI2 = 8,
AES128 = 9,
- AES_CBC = 10,
- AES_ECB = 11,
- AES_SCTE52 = 12,
- TDES_ECB = 13,
- TDES_SCTE52 = 14,
+ AES_ECB = 10,
+ AES_SCTE52 = 11,
+ TDES_ECB = 12,
+ TDES_SCTE52 = 13,
+ AES_CBC = 14,
}
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SharedBuffer.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SharedBuffer.aidl
index a18aa57..9200b1d 100644
--- a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SharedBuffer.aidl
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SharedBuffer.aidl
@@ -32,6 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.cas;
+/* @hide */
@VintfStability
parcelable SharedBuffer {
android.hardware.common.Ashmem heapBase;
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/Status.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/Status.aidl
index 3d3a8a0..343c810 100644
--- a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/Status.aidl
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/Status.aidl
@@ -32,6 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.cas;
+/* @hide */
@VintfStability
parcelable Status {
const int OK = 0;
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/StatusEvent.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/StatusEvent.aidl
index 178cabc..165c0d4 100644
--- a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/StatusEvent.aidl
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/StatusEvent.aidl
@@ -32,6 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.cas;
+/* @hide */
@Backing(type="byte") @VintfStability
enum StatusEvent {
PLUGIN_PHYSICAL_MODULE_CHANGED = 0,
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SubSample.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SubSample.aidl
index d9ee3b4..5bd1a1e 100644
--- a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SubSample.aidl
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SubSample.aidl
@@ -32,6 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.cas;
+/* @hide */
@VintfStability
parcelable SubSample {
int numBytesOfClearData;
diff --git a/cas/aidl/android/hardware/cas/AidlCasPluginDescriptor.aidl b/cas/aidl/android/hardware/cas/AidlCasPluginDescriptor.aidl
index 55b328a..1dc7ac6 100644
--- a/cas/aidl/android/hardware/cas/AidlCasPluginDescriptor.aidl
+++ b/cas/aidl/android/hardware/cas/AidlCasPluginDescriptor.aidl
@@ -18,6 +18,7 @@
/**
* Describes a CAS plugin with its system ID and name.
+ * @hide
*/
@VintfStability
parcelable AidlCasPluginDescriptor {
diff --git a/cas/aidl/android/hardware/cas/DestinationBuffer.aidl b/cas/aidl/android/hardware/cas/DestinationBuffer.aidl
index 068f29d..74336c2 100644
--- a/cas/aidl/android/hardware/cas/DestinationBuffer.aidl
+++ b/cas/aidl/android/hardware/cas/DestinationBuffer.aidl
@@ -19,6 +19,9 @@
import android.hardware.cas.SharedBuffer;
import android.hardware.common.NativeHandle;
+/**
+ * @hide
+ */
@VintfStability
union DestinationBuffer {
/**
diff --git a/cas/aidl/android/hardware/cas/ICas.aidl b/cas/aidl/android/hardware/cas/ICas.aidl
index 4c938c7..e6494ae 100644
--- a/cas/aidl/android/hardware/cas/ICas.aidl
+++ b/cas/aidl/android/hardware/cas/ICas.aidl
@@ -23,6 +23,7 @@
* ICas is the API to control the CAS. It is used to manage sessions, provision/refresh the cas
* system, and process the EMM/ECM messages. It also allows bi-directional, scheme-specific
* communications between the client and the cas system.
+ * @hide
*/
@VintfStability
interface ICas {
diff --git a/cas/aidl/android/hardware/cas/ICasListener.aidl b/cas/aidl/android/hardware/cas/ICasListener.aidl
index 32d843f..21cd257 100644
--- a/cas/aidl/android/hardware/cas/ICasListener.aidl
+++ b/cas/aidl/android/hardware/cas/ICasListener.aidl
@@ -18,6 +18,9 @@
import android.hardware.cas.StatusEvent;
+/**
+ * @hide
+ */
@VintfStability
interface ICasListener {
/**
diff --git a/cas/aidl/android/hardware/cas/IDescrambler.aidl b/cas/aidl/android/hardware/cas/IDescrambler.aidl
index 33fbe75..0ac995c 100644
--- a/cas/aidl/android/hardware/cas/IDescrambler.aidl
+++ b/cas/aidl/android/hardware/cas/IDescrambler.aidl
@@ -23,6 +23,7 @@
/**
* IDescrambler is the API to control the descrambling operations.
+ * @hide
*/
@VintfStability
interface IDescrambler {
diff --git a/cas/aidl/android/hardware/cas/IMediaCasService.aidl b/cas/aidl/android/hardware/cas/IMediaCasService.aidl
index 8bc31f6..641c4a9 100644
--- a/cas/aidl/android/hardware/cas/IMediaCasService.aidl
+++ b/cas/aidl/android/hardware/cas/IMediaCasService.aidl
@@ -26,6 +26,7 @@
* cas HAL to create cas and descrambler plugin instances. A cas plugin instance
* opens cas sessions which are used to obtain keys for a descrambler session,
* which can in turn be used to descramble protected video content.
+ * @hide
*/
@VintfStability
interface IMediaCasService {
diff --git a/cas/aidl/android/hardware/cas/ScramblingMode.aidl b/cas/aidl/android/hardware/cas/ScramblingMode.aidl
index 9d73eba..2a4858a 100644
--- a/cas/aidl/android/hardware/cas/ScramblingMode.aidl
+++ b/cas/aidl/android/hardware/cas/ScramblingMode.aidl
@@ -70,11 +70,6 @@
AES128,
/**
- * Advanced Encryption System (AES) Cipher Block Chaining (CBC) mode.
- */
- AES_CBC,
-
- /**
* Advanced Encryption System (AES) Electronic Code Book (ECB) mode.
*/
AES_ECB,
@@ -95,4 +90,9 @@
* Engineers (SCTE) 52 mode.
*/
TDES_SCTE52,
+
+ /**
+ * Advanced Encryption System (AES) Cipher Block Chaining (CBC) mode.
+ */
+ AES_CBC,
}
diff --git a/cas/aidl/android/hardware/cas/SharedBuffer.aidl b/cas/aidl/android/hardware/cas/SharedBuffer.aidl
index 8a94ff7..0c89cfe 100644
--- a/cas/aidl/android/hardware/cas/SharedBuffer.aidl
+++ b/cas/aidl/android/hardware/cas/SharedBuffer.aidl
@@ -22,6 +22,7 @@
* SharedBuffer describes a shared buffer which is defined by a heapBase, an
* offset and a size. The offset is relative to the shared memory base for the
* memory region identified by heapBase.
+ * @hide
*/
@VintfStability
parcelable SharedBuffer {
diff --git a/cas/aidl/android/hardware/cas/Status.aidl b/cas/aidl/android/hardware/cas/Status.aidl
index b2be34b..e7ae8ff 100644
--- a/cas/aidl/android/hardware/cas/Status.aidl
+++ b/cas/aidl/android/hardware/cas/Status.aidl
@@ -16,6 +16,9 @@
package android.hardware.cas;
+/**
+ * @hide
+ */
@VintfStability
parcelable Status {
/**
diff --git a/cas/aidl/android/hardware/cas/StatusEvent.aidl b/cas/aidl/android/hardware/cas/StatusEvent.aidl
index 0f62634..1fe732e 100644
--- a/cas/aidl/android/hardware/cas/StatusEvent.aidl
+++ b/cas/aidl/android/hardware/cas/StatusEvent.aidl
@@ -18,6 +18,7 @@
/**
* The Event Type for status change.
+ * @hide
*/
@VintfStability
@Backing(type="byte")
diff --git a/cas/aidl/android/hardware/cas/SubSample.aidl b/cas/aidl/android/hardware/cas/SubSample.aidl
index c1353cb..8e1ff77 100644
--- a/cas/aidl/android/hardware/cas/SubSample.aidl
+++ b/cas/aidl/android/hardware/cas/SubSample.aidl
@@ -19,6 +19,7 @@
/**
* A subsample consists of some number of bytes of clear (unscrambled)
* data followed by a number of bytes of scrambled data.
+ * @hide
*/
@VintfStability
parcelable SubSample {
diff --git a/common/aidl/Android.bp b/common/aidl/Android.bp
index 7f6890c..f3ea8e8 100644
--- a/common/aidl/Android.bp
+++ b/common/aidl/Android.bp
@@ -36,6 +36,9 @@
],
min_sdk_version: "29",
},
+ rust: {
+ enabled: true,
+ }
},
frozen: true,
versions: [
diff --git a/common/fmq/aidl/Android.bp b/common/fmq/aidl/Android.bp
index 95fcc41..0715575 100644
--- a/common/fmq/aidl/Android.bp
+++ b/common/fmq/aidl/Android.bp
@@ -36,6 +36,9 @@
],
min_sdk_version: "29",
},
+ rust: {
+ enabled: true,
+ }
},
frozen: true,
versions: ["1"],
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index f8954a3..b2433e9 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>
@@ -46,6 +53,14 @@
</interface>
</hal>
<hal format="aidl" optional="true">
+ <name>android.hardware.audio.sounddose</name>
+ <version>1</version>
+ <interface>
+ <name>ISoundDoseFactory</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+ <hal format="aidl" optional="true">
<name>android.hardware.authsecret</name>
<version>1</version>
<interface>
@@ -68,6 +83,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>
@@ -206,6 +229,7 @@
</hal>
<hal format="aidl" optional="true">
<name>android.hardware.contexthub</name>
+ <version>2</version>
<interface>
<name>IContextHub</name>
<instance>default</instance>
@@ -276,7 +300,7 @@
</hal>
<hal format="aidl" optional="true">
<name>android.hardware.graphics.composer3</name>
- <version>1</version>
+ <version>2</version>
<interface>
<name>IComposer</name>
<instance>default</instance>
@@ -423,17 +447,9 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.oemlock</name>
- <version>1.0</version>
- <interface>
- <name>IOemLock</name>
- <instance>default</instance>
- </interface>
- </hal>
<hal format="aidl" optional="false">
<name>android.hardware.power</name>
- <version>2-4</version>
+ <version>4</version>
<interface>
<name>IPower</name>
<instance>default</instance>
@@ -505,6 +521,16 @@
</interface>
</hal>
<hal format="aidl" optional="true">
+ <name>android.hardware.radio.sap</name>
+ <version>1</version>
+ <interface>
+ <name>ISap</name>
+ <instance>slot1</instance>
+ <instance>slot2</instance>
+ <instance>slot3</instance>
+ </interface>
+ </hal>
+ <hal format="aidl" optional="true">
<name>android.hardware.radio.voice</name>
<version>2</version>
<interface>
@@ -556,15 +582,6 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.secure_element</name>
- <version>1.0-2</version>
- <interface>
- <name>ISecureElement</name>
- <regex-instance>eSE[1-9][0-9]*</regex-instance>
- <regex-instance>SIM[1-9][0-9]*</regex-instance>
- </interface>
- </hal>
<hal format="aidl" optional="true">
<name>android.hardware.secure_element</name>
<version>1</version>
@@ -593,6 +610,7 @@
</hal>
<hal format="aidl" optional="true">
<name>android.hardware.sensors</name>
+ <version>2</version>
<interface>
<name>ISensors</name>
<instance>default</instance>
@@ -709,7 +727,7 @@
</hal>
<hal format="aidl" optional="true">
<name>android.hardware.weaver</name>
- <version>1</version>
+ <version>2</version>
<interface>
<name>IWeaver</name>
<instance>default</instance>
@@ -723,14 +741,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/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl
index f0676be..272d768 100644
--- a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl
+++ b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl
@@ -45,5 +45,6 @@
void sendMessageToHub(in int contextHubId, in android.hardware.contexthub.ContextHubMessage message);
void onHostEndpointConnected(in android.hardware.contexthub.HostEndpointInfo hostEndpointInfo);
void onHostEndpointDisconnected(char hostEndpointId);
+ long[] getPreloadedNanoappIds();
const int EX_CONTEXT_HUB_UNSPECIFIED = -1;
}
diff --git a/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl b/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl
index 16666ef..9fa67a5 100644
--- a/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl
+++ b/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl
@@ -21,6 +21,7 @@
import android.hardware.contexthub.HostEndpointInfo;
import android.hardware.contexthub.IContextHubCallback;
import android.hardware.contexthub.NanoappBinary;
+import android.hardware.contexthub.NanoappInfo;
import android.hardware.contexthub.Setting;
@VintfStability
@@ -195,6 +196,14 @@
void onHostEndpointDisconnected(char hostEndpointId);
/**
+ * Provides the list of preloaded nanoapp IDs on the system. The output of this API must
+ * not change.
+ *
+ * @return The list of preloaded nanoapp IDs
+ */
+ long[] getPreloadedNanoappIds();
+
+ /**
* Error codes that are used as service specific errors with the AIDL return
* value EX_SERVICE_SPECIFIC.
*/
diff --git a/contexthub/aidl/default/Android.bp b/contexthub/aidl/default/Android.bp
index 269057a..6ee7407 100644
--- a/contexthub/aidl/default/Android.bp
+++ b/contexthub/aidl/default/Android.bp
@@ -29,7 +29,7 @@
shared_libs: [
"libbase",
"libbinder_ndk",
- "android.hardware.contexthub-V1-ndk",
+ "android.hardware.contexthub-V2-ndk",
],
export_include_dirs: ["include"],
srcs: [
@@ -50,7 +50,7 @@
shared_libs: [
"libbase",
"libbinder_ndk",
- "android.hardware.contexthub-V1-ndk",
+ "android.hardware.contexthub-V2-ndk",
],
static_libs: [
"libcontexthubexampleimpl",
diff --git a/contexthub/aidl/default/ContextHub.cpp b/contexthub/aidl/default/ContextHub.cpp
index 35e4650..ac1dc46 100644
--- a/contexthub/aidl/default/ContextHub.cpp
+++ b/contexthub/aidl/default/ContextHub.cpp
@@ -76,6 +76,17 @@
}
}
+ScopedAStatus ContextHub::getPreloadedNanoappIds(std::vector<int64_t>* out_preloadedNanoappIds) {
+ if (out_preloadedNanoappIds == nullptr) {
+ return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+
+ for (uint64_t i = 0; i < 10; ++i) {
+ out_preloadedNanoappIds->push_back(i);
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
ScopedAStatus ContextHub::registerCallback(int32_t in_contextHubId,
const std::shared_ptr<IContextHubCallback>& in_cb) {
if (in_contextHubId == kMockHubId) {
diff --git a/contexthub/aidl/default/contexthub-default.xml b/contexthub/aidl/default/contexthub-default.xml
index e383c50..930f672 100644
--- a/contexthub/aidl/default/contexthub-default.xml
+++ b/contexthub/aidl/default/contexthub-default.xml
@@ -1,7 +1,10 @@
<manifest version="1.0" type="device">
<hal format="aidl">
<name>android.hardware.contexthub</name>
- <version>1</version>
- <fqname>IContextHub/default</fqname>
+ <version>2</version>
+ <interface>
+ <name>IContextHub</name>
+ <instance>default</instance>
+ </interface>
</hal>
</manifest>
diff --git a/contexthub/aidl/default/include/contexthub-impl/ContextHub.h b/contexthub/aidl/default/include/contexthub-impl/ContextHub.h
index 03d8432..4aeb948 100644
--- a/contexthub/aidl/default/include/contexthub-impl/ContextHub.h
+++ b/contexthub/aidl/default/include/contexthub-impl/ContextHub.h
@@ -19,6 +19,7 @@
#include <aidl/android/hardware/contexthub/BnContextHub.h>
#include <unordered_set>
+#include <vector>
namespace aidl {
namespace android {
@@ -37,6 +38,8 @@
int32_t in_transactionId) override;
::ndk::ScopedAStatus onSettingChanged(Setting in_setting, bool in_enabled) override;
::ndk::ScopedAStatus queryNanoapps(int32_t in_contextHubId) override;
+ ::ndk::ScopedAStatus getPreloadedNanoappIds(
+ std::vector<int64_t>* out_preloadedNanoappIds) override;
::ndk::ScopedAStatus registerCallback(
int32_t in_contextHubId, const std::shared_ptr<IContextHubCallback>& in_cb) override;
::ndk::ScopedAStatus sendMessageToHub(int32_t in_contextHubId,
diff --git a/contexthub/aidl/vts/Android.bp b/contexthub/aidl/vts/Android.bp
index 673eac0..1534b40 100644
--- a/contexthub/aidl/vts/Android.bp
+++ b/contexthub/aidl/vts/Android.bp
@@ -32,7 +32,7 @@
"libbinder",
],
static_libs: [
- "android.hardware.contexthub-V1-cpp",
+ "android.hardware.contexthub-V2-cpp",
"VtsHalContexthubUtils",
],
test_suites: [
diff --git a/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp b/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp
index 3c01c6b..8104f27 100644
--- a/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp
+++ b/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp
@@ -156,6 +156,19 @@
}
}
+// Calls getPreloadedNanoapps() and verifies there are preloaded nanoapps
+TEST_P(ContextHubAidl, TestGetPreloadedNanoapps) {
+ std::vector<int64_t> preloadedNanoappIds;
+ Status status = contextHub->getPreloadedNanoappIds(&preloadedNanoappIds);
+ if (status.exceptionCode() == Status::EX_UNSUPPORTED_OPERATION ||
+ status.transactionError() == android::UNKNOWN_TRANSACTION) {
+ return; // not supported -> old API; or not implemented
+ }
+
+ ASSERT_TRUE(status.isOk());
+ ASSERT_FALSE(preloadedNanoappIds.empty());
+}
+
// Helper callback that puts the TransactionResult for the expectedTransactionId into a
// promise
class TransactionResultCallback : public android::hardware::contexthub::BnContextHubCallback {
diff --git a/current.txt b/current.txt
index 146ded6..0fb8b49 100644
--- a/current.txt
+++ b/current.txt
@@ -931,5 +931,6 @@
# ABI preserving changes to HALs during Android U
2aa559cda86c358c6429114ef6bc72c1b43281e98f9eb6b4df5e7073c8d05767 android.hardware.automotive.vehicle@2.0::types
+42abd285a4293dadb8c89bc63b90cae2872fbffe90c4517aa3ea4965e8aecff7 android.hardware.graphics.common@1.2::types
# There will be no more HIDL HALs. Use AIDL instead.
diff --git a/graphics/common/1.2/types.hal b/graphics/common/1.2/types.hal
index ebea1dc..07e9882 100644
--- a/graphics/common/1.2/types.hal
+++ b/graphics/common/1.2/types.hal
@@ -77,6 +77,8 @@
HEIF = 0x1004,
};
+@export(name="android_color_mode_v1_2_t", value_prefix="HAL_COLOR_MODE_",
+ export_parent="false")
enum ColorMode : @1.1::ColorMode {
/**
* DISPLAY_BT2020 corresponds with display settings that implement the ITU-R
diff --git a/graphics/common/aidl/Android.bp b/graphics/common/aidl/Android.bp
index 84bc1af..6c8ff4b 100644
--- a/graphics/common/aidl/Android.bp
+++ b/graphics/common/aidl/Android.bp
@@ -39,6 +39,9 @@
],
min_sdk_version: "29",
},
+ rust: {
+ enabled: true,
+ }
},
frozen: false,
versions_with_info: [
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Dataspace.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Dataspace.aidl
index 668b033..563b6c1 100644
--- a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Dataspace.aidl
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Dataspace.aidl
@@ -94,5 +94,6 @@
DYNAMIC_DEPTH = 4098,
JPEG_APP_SEGMENTS = 4099,
HEIF = 4100,
+ JPEG_R = 4101,
BT709_FULL_RANGE = 146866176,
}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/Dataspace.aidl b/graphics/common/aidl/android/hardware/graphics/common/Dataspace.aidl
index 5e9360f..b44e613 100644
--- a/graphics/common/aidl/android/hardware/graphics/common/Dataspace.aidl
+++ b/graphics/common/aidl/android/hardware/graphics/common/Dataspace.aidl
@@ -668,6 +668,19 @@
HEIF = 0x1004,
/**
+ * ISO/IEC TBD
+ *
+ * JPEG image with embedded 10-bit recovery map following the Jpeg/R specification.
+ *
+ * This value must always remain aligned with the public ImageFormat Jpeg/R definition and is
+ * valid with formats:
+ * HAL_PIXEL_FORMAT_BLOB: JPEG image encoded by Jpeg/R encoder according to ISO/IEC TBD.
+ * The image contains a standard SDR JPEG and a recovery map. Jpeg/R decoders can use the
+ * map to recover the 10-bit input image.
+ */
+ JPEG_R = 0x1005,
+
+ /**
* ITU-R Recommendation 709 (BT.709)
*
* High-definition television
diff --git a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
index 4822678..b66ee19 100644
--- a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
+++ b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
@@ -657,6 +657,7 @@
IComposerClient::Attribute::WIDTH);
mDisplayHeight = mComposerClient->getDisplayAttribute(mPrimaryDisplay, activeConfig,
IComposerClient::Attribute::HEIGHT);
+
mWriter = std::make_unique<CommandWriterBase>(1024);
mReader = std::make_unique<TestCommandReader>();
}
@@ -666,11 +667,13 @@
ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::TearDown());
}
- NativeHandleWrapper allocate() {
+ NativeHandleWrapper allocate() { return allocate(mDisplayWidth, mDisplayHeight); }
+
+ NativeHandleWrapper allocate(uint32_t width, uint32_t height) {
uint64_t usage =
static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN |
BufferUsage::COMPOSER_OVERLAY);
- return mGralloc->allocate(mDisplayWidth, mDisplayHeight, 1, PixelFormat::RGBA_8888, usage);
+ return mGralloc->allocate(width, height, 1, PixelFormat::RGBA_8888, usage);
}
void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); }
@@ -884,6 +887,57 @@
}
/**
+ * Test IComposerClient::Command::SET_LAYER_BUFFER with the behavior used for clearing buffer slots.
+ */
+TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_BUFFER_TO_CLEAR_BUFFER_SLOTS) {
+ // A buffer used to clear buffer slots
+ auto clearSlotBuffer = allocate(1u, 1u);
+
+ auto handle1 = allocate();
+ ASSERT_NE(nullptr, handle1.get());
+ IComposerClient::Rect displayFrame{0, 0, mDisplayWidth, mDisplayHeight};
+ Layer layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->selectLayer(layer);
+ mWriter->setLayerCompositionType(IComposerClient::Composition::DEVICE);
+ mWriter->setLayerDisplayFrame(displayFrame);
+ mWriter->setLayerBuffer(0, handle1.get(), -1);
+ mWriter->setLayerDataspace(Dataspace::UNKNOWN);
+ mWriter->validateDisplay();
+ execute();
+ if (mReader->mCompositionChanges.size() != 0) {
+ GTEST_SUCCEED() << "Composition change requested, skipping test";
+ return;
+ }
+ ASSERT_EQ(0, mReader->mErrors.size());
+
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->presentDisplay();
+ execute();
+ ASSERT_EQ(0, mReader->mErrors.size());
+
+ // Ensure we can clear a buffer slot and then set that same slot with a new buffer
+ auto handle2 = allocate();
+ ASSERT_NE(nullptr, handle2.get());
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->selectLayer(layer);
+ mWriter->setLayerBuffer(0, clearSlotBuffer.get(), -1);
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->selectLayer(layer);
+ mWriter->setLayerBuffer(0, handle2.get(), -1);
+ mWriter->validateDisplay();
+ execute();
+ ASSERT_EQ(0, mReader->mErrors.size());
+
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->presentDisplay();
+ execute();
+ ASSERT_EQ(0, mReader->mErrors.size());
+}
+
+/**
* Test IComposerClient::Command::SET_LAYER_SURFACE_DAMAGE.
*/
TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_SURFACE_DAMAGE) {
diff --git a/graphics/composer/2.2/utils/vts/Android.bp b/graphics/composer/2.2/utils/vts/Android.bp
index 478e2b7..d11592f 100644
--- a/graphics/composer/2.2/utils/vts/Android.bp
+++ b/graphics/composer/2.2/utils/vts/Android.bp
@@ -29,6 +29,7 @@
"android.hardware.graphics.allocator-ndk_static",
"android.hardware.graphics.composer3-ndk_static",
"hidl_defaults",
+ "librenderengine_deps",
],
srcs: [
"ComposerVts.cpp",
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/Android.bp b/graphics/composer/2.2/vts/functional/Android.bp
index c693d35..3476376 100644
--- a/graphics/composer/2.2/vts/functional/Android.bp
+++ b/graphics/composer/2.2/vts/functional/Android.bp
@@ -29,8 +29,7 @@
"VtsHalTargetTestDefaults",
"android.hardware.graphics.allocator-ndk_static",
"android.hardware.graphics.composer3-ndk_static",
- // Needed for librenderengine
- "skia_deps",
+ "librenderengine_deps",
],
tidy_timeout_srcs: [
"VtsHalGraphicsComposerV2_2ReadbackTest.cpp",
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/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LayerCommand.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LayerCommand.aidl
index 0c5fac9..6d32218 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LayerCommand.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LayerCommand.aidl
@@ -54,4 +54,5 @@
@nullable android.hardware.graphics.composer3.PerFrameMetadata[] perFrameMetadata;
@nullable android.hardware.graphics.composer3.PerFrameMetadataBlob[] perFrameMetadataBlob;
@nullable android.hardware.graphics.common.Rect[] blockingRegion;
+ @nullable int[] bufferSlotsToClear;
}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/LayerCommand.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/LayerCommand.aidl
index f3b67a9..fd50be9 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/LayerCommand.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/LayerCommand.aidl
@@ -258,4 +258,11 @@
* the screen.
*/
@nullable Rect[] blockingRegion;
+
+ /**
+ * Specifies which buffer slots should be cleared of buffer references
+ * because these buffers will no longer be used and the memory should
+ * be freed.
+ */
+ @nullable int[] bufferSlotsToClear;
}
diff --git a/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h b/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h
index 0c8742f..22020c0 100644
--- a/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h
+++ b/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h
@@ -91,7 +91,7 @@
void setClientTarget(int64_t display, uint32_t slot, const native_handle_t* target,
int acquireFence, Dataspace dataspace, const std::vector<Rect>& damage) {
ClientTarget clientTargetCommand;
- clientTargetCommand.buffer = getBuffer(slot, target, acquireFence);
+ clientTargetCommand.buffer = getBufferCommand(slot, target, acquireFence);
clientTargetCommand.dataspace = dataspace;
clientTargetCommand.damage.assign(damage.begin(), damage.end());
getDisplayCommand(display).clientTarget.emplace(std::move(clientTargetCommand));
@@ -100,7 +100,7 @@
void setOutputBuffer(int64_t display, uint32_t slot, const native_handle_t* buffer,
int releaseFence) {
getDisplayCommand(display).virtualDisplayOutputBuffer.emplace(
- getBuffer(slot, buffer, releaseFence));
+ getBufferCommand(slot, buffer, releaseFence));
}
void validateDisplay(int64_t display,
@@ -132,7 +132,22 @@
void setLayerBuffer(int64_t display, int64_t layer, uint32_t slot,
const native_handle_t* buffer, int acquireFence) {
- getLayerCommand(display, layer).buffer = getBuffer(slot, buffer, acquireFence);
+ getLayerCommand(display, layer).buffer = getBufferCommand(slot, buffer, acquireFence);
+ }
+
+ void setLayerBufferWithNewCommand(int64_t display, int64_t layer, uint32_t slot,
+ const native_handle_t* buffer, int acquireFence) {
+ flushLayerCommand();
+ getLayerCommand(display, layer).buffer = getBufferCommand(slot, buffer, acquireFence);
+ flushLayerCommand();
+ }
+
+ void setLayerBufferSlotsToClear(int64_t display, int64_t layer,
+ const std::vector<uint32_t>& slotsToClear) {
+ LayerCommand& layerCommand = getLayerCommand(display, layer);
+ for (auto slot : slotsToClear) {
+ layerCommand.bufferSlotsToClear.emplace(static_cast<int32_t>(slot));
+ }
}
void setLayerSurfaceDamage(int64_t display, int64_t layer, const std::vector<Rect>& damage) {
@@ -234,7 +249,7 @@
std::vector<DisplayCommand> mCommands;
const int64_t mDisplay;
- Buffer getBuffer(uint32_t slot, const native_handle_t* bufferHandle, int fence) {
+ Buffer getBufferCommand(uint32_t slot, const native_handle_t* bufferHandle, int fence) {
Buffer bufferCommand;
bufferCommand.slot = static_cast<int32_t>(slot);
if (bufferHandle) bufferCommand.handle.emplace(::android::dupToAidl(bufferHandle));
diff --git a/graphics/composer/aidl/vts/Android.bp b/graphics/composer/aidl/vts/Android.bp
index cbd2da5..88b5de4 100644
--- a/graphics/composer/aidl/vts/Android.bp
+++ b/graphics/composer/aidl/vts/Android.bp
@@ -28,8 +28,7 @@
defaults: [
"VtsHalTargetTestDefaults",
"use_libaidlvintf_gtest_helper_static",
- // Needed for librenderengine
- "skia_deps",
+ "librenderengine_deps",
"android.hardware.graphics.common-ndk_static",
"android.hardware.graphics.composer3-ndk_static",
],
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/VtsComposerClient.cpp b/graphics/composer/aidl/vts/VtsComposerClient.cpp
index 34cc802..00b578b 100644
--- a/graphics/composer/aidl/vts/VtsComposerClient.cpp
+++ b/graphics/composer/aidl/vts/VtsComposerClient.cpp
@@ -58,6 +58,12 @@
return verifyComposerCallbackParams() && destroyAllLayers();
}
+std::pair<ScopedAStatus, int32_t> VtsComposerClient::getInterfaceVersion() {
+ int32_t version = 1;
+ auto status = mComposerClient->getInterfaceVersion(&version);
+ return {std::move(status), version};
+}
+
std::pair<ScopedAStatus, VirtualDisplay> VtsComposerClient::createVirtualDisplay(
int32_t width, int32_t height, PixelFormat pixelFormat, int32_t bufferSlotCount) {
VirtualDisplay outVirtualDisplay;
diff --git a/graphics/composer/aidl/vts/VtsComposerClient.h b/graphics/composer/aidl/vts/VtsComposerClient.h
index 1883336..e61fde9 100644
--- a/graphics/composer/aidl/vts/VtsComposerClient.h
+++ b/graphics/composer/aidl/vts/VtsComposerClient.h
@@ -61,6 +61,8 @@
bool tearDown();
+ std::pair<ScopedAStatus, int32_t> getInterfaceVersion();
+
std::pair<ScopedAStatus, VirtualDisplay> createVirtualDisplay(int32_t width, int32_t height,
PixelFormat pixelFormat,
int32_t bufferSlotCount);
diff --git a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
index 6fa3392..166127d 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,296 @@
}
}
+TEST_P(GraphicsCompositionTest, SetLayerBufferWithSlotsToClear) {
+ const auto& [versionStatus, version] = mComposerClient->getInterfaceVersion();
+ ASSERT_TRUE(versionStatus.isOk());
+ if (version == 1) {
+ GTEST_SUCCEED() << "Device does not support the new API for clearing buffer slots";
+ return;
+ }
+
+ const auto& [readbackStatus, readbackBufferAttributes] =
+ mComposerClient->getReadbackBufferAttributes(getPrimaryDisplayId());
+ if (!readbackStatus.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);
+
+ // 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));
+
+ // green buffer
+ sp<GraphicBuffer> greenBuffer = allocateBuffer(usage);
+ ASSERT_NE(nullptr, greenBuffer);
+ int greenFence;
+ ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBufferAndGetFence(greenBuffer, GREEN, &greenFence));
+
+ // layer defaults
+ common::Rect rectFullDisplay = {0, 0, getDisplayWidth(), getDisplayHeight()};
+ int64_t display = getPrimaryDisplayId();
+ const 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);
+ }
+
+ // change the layer to the green buffer
+ // should be green
+ {
+ auto status = mComposerClient->setReadbackBuffer(display, readbackBuffer->handle, noFence);
+ ASSERT_TRUE(status.isOk());
+ mWriter->setLayerBuffer(display, layer, /*slot*/ 2, greenBuffer->handle, greenFence);
+ 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(GREEN, readbackBuffer, fence);
+ }
+
+ // clear the slots for all buffers
+ // should still be green since the active buffer should not be cleared by the HAL implementation
+ {
+ auto status = mComposerClient->setReadbackBuffer(display, readbackBuffer->handle, noFence);
+ ASSERT_TRUE(status.isOk());
+ mWriter->setLayerBufferSlotsToClear(display, layer, /*slotsToClear*/ {0, 1, 2});
+ 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(GREEN, readbackBuffer, fence);
+ }
+
+ // clear the slot for the green 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->setLayerBufferSlotsToClear(display, layer, /*slotsToClear*/ {2});
+ mWriter->setLayerBuffer(display, layer, /*slot*/ 2, 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);
+ }
+}
+
+TEST_P(GraphicsCompositionTest, SetLayerBufferWithSlotsToClear_backwardsCompatible) {
+ const auto& [versionStatus, version] = mComposerClient->getInterfaceVersion();
+ ASSERT_TRUE(versionStatus.isOk());
+ if (version > 1) {
+ GTEST_SUCCEED() << "Device does not need a backwards compatible way to clear buffer slots";
+ return;
+ }
+
+ const auto& [readbackStatus, readbackBufferAttributes] =
+ mComposerClient->getReadbackBufferAttributes(getPrimaryDisplayId());
+ if (!readbackStatus.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));
+
+ // green buffer
+ sp<GraphicBuffer> greenBuffer = allocateBuffer(usage);
+ ASSERT_NE(nullptr, greenBuffer);
+ int greenFence;
+ ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBufferAndGetFence(greenBuffer, GREEN, &greenFence));
+
+ // layer defaults
+ common::Rect rectFullDisplay = {0, 0, getDisplayWidth(), getDisplayHeight()};
+ int64_t display = getPrimaryDisplayId();
+ const 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);
+ }
+
+ // change the layer to the green buffer
+ // should be green
+ {
+ auto status = mComposerClient->setReadbackBuffer(display, readbackBuffer->handle, noFence);
+ ASSERT_TRUE(status.isOk());
+ mWriter->setLayerBuffer(display, layer, /*slot*/ 2, greenBuffer->handle, greenFence);
+ 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(GREEN, readbackBuffer, fence);
+ }
+
+ // clear the slot for the blue buffer
+ // should still be green
+ {
+ auto status = mComposerClient->setReadbackBuffer(display, readbackBuffer->handle, noFence);
+ ASSERT_TRUE(status.isOk());
+ mWriter->setLayerBufferWithNewCommand(display, layer, /*slot*/ 0, clearSlotBuffer->handle,
+ /*fence*/ -1);
+ // SurfaceFlinger will re-set the active buffer slot after other buffer slots are cleared
+ mWriter->setLayerBufferWithNewCommand(display, layer, /*slot*/ 2, /*handle*/ nullptr,
+ /*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(GREEN, readbackBuffer, fence);
+ }
+
+ // clear the slot for all buffers, and set the buffer with the same slot as the green buffer
+ // should be blue now
+ {
+ auto status = mComposerClient->setReadbackBuffer(display, readbackBuffer->handle, noFence);
+ ASSERT_TRUE(status.isOk());
+ mWriter->setLayerBufferWithNewCommand(display, layer, /*slot*/ 0, clearSlotBuffer->handle,
+ /*fence*/ -1);
+ mWriter->setLayerBufferWithNewCommand(display, layer, /*slot*/ 1, clearSlotBuffer->handle,
+ /*fence*/ -1);
+ // SurfaceFlinger will never clear the active buffer (slot 2), but will free up the
+ // buffer slot so it will be re-used for the next setLayerBuffer command
+ mWriter->setLayerBuffer(display, layer, /*slot*/ 2, 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);
+ }
+}
+
TEST_P(GraphicsCompositionTest, SetLayerBufferNoEffect) {
for (ColorMode mode : mTestColorModes) {
EXPECT_TRUE(mComposerClient
@@ -399,10 +689,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 +702,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 +730,7 @@
}
ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
- getDisplayHeight(), mPixelFormat, mDataspace);
+ getDisplayHeight(), mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
}
@@ -454,10 +743,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 +827,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 +840,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 +904,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 +923,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 +946,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 +1009,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 +1077,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 +1143,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 +1200,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 +1310,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 +1446,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 +1491,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 +1531,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 +1605,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 +1650,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 +1695,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/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
index fa66812..7b852e0 100644
--- a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
+++ b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
@@ -811,8 +811,7 @@
EXPECT_TRUE(status.isOk());
}
-// TODO(b/250036572): disable this due to no implementation and revup on cuttlefish
-TEST_P(GraphicsComposerAidlTest, DISABLED_GetOverlaySupport) {
+TEST_P(GraphicsComposerAidlTest, GetOverlaySupport) {
const auto& [status, _] = mComposerClient->getOverlaySupport();
if (!status.isOk() && status.getExceptionCode() == EX_SERVICE_SPECIFIC &&
status.getServiceSpecificError() == IComposerClient::EX_UNSUPPORTED) {
@@ -1132,17 +1131,21 @@
}
}
- sp<GraphicBuffer> allocate(::android::PixelFormat pixelFormat) {
+ sp<GraphicBuffer> allocate(uint32_t width, uint32_t height,
+ ::android::PixelFormat pixelFormat) {
return sp<GraphicBuffer>::make(
- static_cast<uint32_t>(getPrimaryDisplay().getDisplayWidth()),
- static_cast<uint32_t>(getPrimaryDisplay().getDisplayHeight()), pixelFormat,
- /*layerCount*/ 1U,
- (static_cast<uint64_t>(common::BufferUsage::CPU_WRITE_OFTEN) |
- static_cast<uint64_t>(common::BufferUsage::CPU_READ_OFTEN) |
- static_cast<uint64_t>(common::BufferUsage::COMPOSER_OVERLAY)),
+ width, height, pixelFormat, /*layerCount*/ 1U,
+ static_cast<uint64_t>(common::BufferUsage::CPU_WRITE_OFTEN) |
+ static_cast<uint64_t>(common::BufferUsage::CPU_READ_OFTEN) |
+ static_cast<uint64_t>(common::BufferUsage::COMPOSER_OVERLAY),
"VtsHalGraphicsComposer3_TargetTest");
}
+ sp<GraphicBuffer> allocate(::android::PixelFormat pixelFormat) {
+ return allocate(static_cast<uint32_t>(getPrimaryDisplay().getDisplayWidth()),
+ static_cast<uint32_t>(getPrimaryDisplay().getDisplayHeight()), pixelFormat);
+ }
+
void sendRefreshFrame(const VtsDisplay& display, const VsyncPeriodChangeTimeline* timeline) {
if (timeline != nullptr) {
// Refresh time should be before newVsyncAppliedTimeNanos
@@ -1643,6 +1646,90 @@
execute();
}
+TEST_P(GraphicsComposerAidlCommandTest, SetLayerBufferWithSlotsToClear) {
+ const auto& [versionStatus, version] = mComposerClient->getInterfaceVersion();
+ ASSERT_TRUE(versionStatus.isOk());
+ if (version == 1) {
+ GTEST_SUCCEED() << "Device does not support the new API for clearing buffer slots";
+ return;
+ }
+
+ const auto& [layerStatus, layer] =
+ mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
+ EXPECT_TRUE(layerStatus.isOk());
+
+ auto& writer = getWriter(getPrimaryDisplayId());
+
+ const auto buffer1 = allocate(::android::PIXEL_FORMAT_RGBA_8888);
+ ASSERT_NE(nullptr, buffer1);
+ const auto handle1 = buffer1->handle;
+ writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, handle1, /*acquireFence*/ -1);
+ execute();
+ ASSERT_TRUE(mReader.takeErrors().empty());
+
+ const auto buffer2 = allocate(::android::PIXEL_FORMAT_RGBA_8888);
+ ASSERT_NE(nullptr, buffer2);
+ const auto handle2 = buffer2->handle;
+ writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 1, handle2, /*acquireFence*/ -1);
+ execute();
+ ASSERT_TRUE(mReader.takeErrors().empty());
+
+ // Ensure we can clear the buffer slots and then set the active slot with a new buffer
+ const auto buffer3 = allocate(::android::PIXEL_FORMAT_RGBA_8888);
+ ASSERT_NE(nullptr, buffer3);
+ const auto handle3 = buffer3->handle;
+ writer.setLayerBufferSlotsToClear(getPrimaryDisplayId(), layer, /*slotsToClear*/ {0, 1});
+ writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 1, handle3, /*acquireFence*/ -1);
+ execute();
+ ASSERT_TRUE(mReader.takeErrors().empty());
+}
+
+TEST_P(GraphicsComposerAidlCommandTest, SetLayerBufferWithSlotsToClear_backwardsCompatible) {
+ const auto& [versionStatus, version] = mComposerClient->getInterfaceVersion();
+ ASSERT_TRUE(versionStatus.isOk());
+ if (version > 1) {
+ GTEST_SUCCEED() << "Device does not need a backwards compatible way to clear buffer slots";
+ return;
+ }
+
+ auto clearSlotBuffer = allocate(1u, 1u, ::android::PIXEL_FORMAT_RGB_888);
+ ASSERT_NE(nullptr, clearSlotBuffer);
+ auto clearSlotBufferHandle = clearSlotBuffer->handle;
+
+ const auto& [layerStatus, layer] =
+ mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
+ EXPECT_TRUE(layerStatus.isOk());
+
+ auto& writer = getWriter(getPrimaryDisplayId());
+
+ const auto buffer1 = allocate(::android::PIXEL_FORMAT_RGBA_8888);
+ ASSERT_NE(nullptr, buffer1);
+ const auto handle1 = buffer1->handle;
+ writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, handle1, /*acquireFence*/ -1);
+ execute();
+ ASSERT_TRUE(mReader.takeErrors().empty());
+
+ const auto buffer2 = allocate(::android::PIXEL_FORMAT_RGBA_8888);
+ ASSERT_NE(nullptr, buffer2);
+ const auto handle2 = buffer2->handle;
+ EXPECT_TRUE(layerStatus.isOk());
+ writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 1, handle2, /*acquireFence*/ -1);
+ execute();
+ ASSERT_TRUE(mReader.takeErrors().empty());
+
+ // Ensure we can clear a buffer slot and then set that same slot with a new buffer
+ const auto buffer3 = allocate(::android::PIXEL_FORMAT_RGBA_8888);
+ ASSERT_NE(nullptr, buffer3);
+ const auto handle3 = buffer2->handle;
+ // SurfaceFlinger will never clear the active buffer, instead it will clear non-active buffers
+ // and then re-use the active buffer's slot for the new buffer
+ writer.setLayerBufferWithNewCommand(getPrimaryDisplayId(), layer, /*slot*/ 0,
+ clearSlotBufferHandle, /*acquireFence*/ -1);
+ writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 1, handle3, /*acquireFence*/ -1);
+ execute();
+ ASSERT_TRUE(mReader.takeErrors().empty());
+}
+
TEST_P(GraphicsComposerAidlCommandTest, SetLayerSurfaceDamage) {
const auto& [layerStatus, layer] =
mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
diff --git a/graphics/mapper/stable-c/Android.bp b/graphics/mapper/stable-c/Android.bp
index c03f67e..fa3087a 100644
--- a/graphics/mapper/stable-c/Android.bp
+++ b/graphics/mapper/stable-c/Android.bp
@@ -35,6 +35,25 @@
],
}
+cc_library_shared {
+ name: "libimapper_stablec_abicheck",
+ visibility: ["//visibility:private"],
+ defaults: [
+ "android.hardware.graphics.allocator-ndk_shared",
+ "android.hardware.graphics.common-ndk_shared",
+ ],
+ header_libs: [
+ "libimapper_stablec",
+ ],
+ srcs: [
+ "imapper5_abicheck.cpp",
+ ],
+ header_abi_checker: {
+ enabled: true,
+ symbol_file: "imapper.map.txt",
+ },
+}
+
cc_library_headers {
name: "libimapper_providerutils",
vendor_available: true,
@@ -61,6 +80,10 @@
srcs: [
"implutils/impltests.cpp",
],
+ shared_libs: [
+ "libgralloctypes",
+ "libhidlbase",
+ ],
visibility: [":__subpackages__"],
cpp_std: "experimental",
}
diff --git a/graphics/mapper/stable-c/imapper.map.txt b/graphics/mapper/stable-c/imapper.map.txt
new file mode 100644
index 0000000..43abd33
--- /dev/null
+++ b/graphics/mapper/stable-c/imapper.map.txt
@@ -0,0 +1,4 @@
+LIBIMAPPER { # introduced=UpsideDownCake
+ global:
+ AIMapper_loadIMapper;
+}
diff --git a/graphics/mapper/stable-c/imapper5_abicheck.cpp b/graphics/mapper/stable-c/imapper5_abicheck.cpp
new file mode 100644
index 0000000..92f7198
--- /dev/null
+++ b/graphics/mapper/stable-c/imapper5_abicheck.cpp
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/hardware/graphics/mapper/IMapper.h>
+
+AIMapper_Error AIMapper_loadIMapper(AIMapper* _Nullable* _Nonnull outImplementation) {
+ static AIMapper mapper = {AIMAPPER_VERSION_5, {}};
+ *outImplementation = &mapper;
+ return AIMAPPER_ERROR_NONE;
+}
\ No newline at end of file
diff --git a/graphics/mapper/stable-c/implutils/impltests.cpp b/graphics/mapper/stable-c/implutils/impltests.cpp
index 9c5d70b..f12b069 100644
--- a/graphics/mapper/stable-c/implutils/impltests.cpp
+++ b/graphics/mapper/stable-c/implutils/impltests.cpp
@@ -18,123 +18,29 @@
#include <android/hardware/graphics/mapper/utils/IMapperMetadataTypes.h>
#include <android/hardware/graphics/mapper/utils/IMapperProvider.h>
+#include <drm/drm_fourcc.h>
+#include <gralloctypes/Gralloc4.h>
+#include <span>
#include <vector>
+using namespace ::android;
using namespace ::android::hardware::graphics::mapper;
using namespace ::aidl::android::hardware::graphics::common;
+namespace gralloc4 = ::android::gralloc4;
+using ::android::hardware::hidl_vec;
// These tests are primarily interested in hitting all the different *types* that can be
// serialized/deserialized than in exhaustively testing all the StandardMetadataTypes.
// Exhaustive testing of the actual metadata types is relegated for IMapper's VTS suite
// where meaning & correctness of values are more narrowly defined (eg, read-only values)
-TEST(Metadata, setGetBufferId) {
- using BufferId = StandardMetadata<StandardMetadataType::BUFFER_ID>::value;
+static constexpr auto HeaderSize = 69;
- std::vector<char> buffer;
- buffer.resize(12, 0);
- *reinterpret_cast<int64_t*>(buffer.data()) = 42;
-
- EXPECT_EQ(8, BufferId::encode(18, buffer.data(), 0));
- EXPECT_EQ(42, *reinterpret_cast<int64_t*>(buffer.data()));
- EXPECT_EQ(8, BufferId::encode(18, buffer.data(), buffer.size()));
- EXPECT_EQ(18, *reinterpret_cast<int64_t*>(buffer.data()));
- EXPECT_FALSE(BufferId::decode(buffer.data(), 0));
- auto read = BufferId::decode(buffer.data(), buffer.size());
- EXPECT_TRUE(read.has_value());
- EXPECT_EQ(18, read.value_or(0));
+static std::span<uint8_t> SkipHeader(std::vector<uint8_t>& buffer) {
+ return std::span<uint8_t>(buffer).subspan(HeaderSize);
}
-TEST(Metadata, setGetDataspace) {
- using DataspaceValue = StandardMetadata<StandardMetadataType::DATASPACE>::value;
- using intType = std::underlying_type_t<Dataspace>;
- std::vector<char> buffer;
- buffer.resize(12, 0);
-
- EXPECT_EQ(4, DataspaceValue::encode(Dataspace::BT2020, buffer.data(), 0));
- EXPECT_EQ(0, *reinterpret_cast<intType*>(buffer.data()));
- EXPECT_EQ(4, DataspaceValue::encode(Dataspace::BT2020, buffer.data(), buffer.size()));
- EXPECT_EQ(static_cast<intType>(Dataspace::BT2020), *reinterpret_cast<intType*>(buffer.data()));
- EXPECT_FALSE(DataspaceValue::decode(buffer.data(), 0));
- auto read = DataspaceValue::decode(buffer.data(), buffer.size());
- ASSERT_TRUE(read.has_value());
- EXPECT_EQ(Dataspace::BT2020, *read);
-}
-
-TEST(Metadata, setGetValidName) {
- using NameValue = StandardMetadata<StandardMetadataType::NAME>::value;
-
- std::vector<char> buffer;
- buffer.resize(100, 'a');
- buffer[buffer.size() - 1] = '\0';
-
- // len("Hello") + sizeof(int64)
- constexpr int expectedSize = 5 + sizeof(int64_t);
- EXPECT_EQ(expectedSize, NameValue::encode("Hello", buffer.data(), buffer.size()));
- EXPECT_EQ(5, *reinterpret_cast<int64_t*>(buffer.data()));
- // Verify didn't write past the end of the desired size
- EXPECT_EQ('a', buffer[expectedSize]);
-
- auto readValue = NameValue::decode(buffer.data(), buffer.size());
- ASSERT_TRUE(readValue.has_value());
- EXPECT_EQ(5, readValue->length());
- EXPECT_EQ("Hello", *readValue);
-}
-
-TEST(Metadata, setGetInvalidName) {
- using NameValue = StandardMetadata<StandardMetadataType::NAME>::value;
-
- std::vector<char> buffer;
- buffer.resize(12, 'a');
- buffer[buffer.size() - 1] = '\0';
-
- // len("This is a long string") + sizeof(int64)
- constexpr int expectedSize = 21 + sizeof(int64_t);
- EXPECT_EQ(expectedSize,
- NameValue::encode("This is a long string", buffer.data(), buffer.size()));
- EXPECT_EQ(21, *reinterpret_cast<int64_t*>(buffer.data()));
- // Verify didn't write the too-long string
- EXPECT_EQ('a', buffer[9]);
- EXPECT_EQ('\0', buffer[buffer.size() - 1]);
-
- auto readValue = NameValue::decode(buffer.data(), buffer.size());
- EXPECT_FALSE(readValue.has_value());
- readValue = NameValue::decode(buffer.data(), 0);
- ASSERT_FALSE(readValue.has_value());
-}
-
-TEST(Metadata, wouldOverflowName) {
- using NameValue = StandardMetadata<StandardMetadataType::NAME>::value;
- std::vector<char> buffer(100, 0);
-
- // int_max + sizeof(int64) overflows int32
- std::string_view bad_string{"badbeef", std::numeric_limits<int32_t>::max()};
- EXPECT_EQ(-AIMAPPER_ERROR_BAD_VALUE,
- NameValue::encode(bad_string, buffer.data(), buffer.size()));
-
- // check barely overflows
- bad_string = std::string_view{"badbeef", std::numeric_limits<int32_t>::max() - 7};
- EXPECT_EQ(-AIMAPPER_ERROR_BAD_VALUE,
- NameValue::encode(bad_string, buffer.data(), buffer.size()));
-}
-
-TEST(Metadata, setGetCompression) {
- using CompressionValue = StandardMetadata<StandardMetadataType::COMPRESSION>::value;
- ExtendableType myCompression{"bestest_compression_ever", 42};
- std::vector<char> buffer(100, '\0');
- const int expectedSize = myCompression.name.length() + sizeof(int64_t) + sizeof(int64_t);
- EXPECT_EQ(expectedSize, CompressionValue::encode(myCompression, buffer.data(), 0));
- EXPECT_EQ(0, buffer[0]);
- EXPECT_EQ(expectedSize, CompressionValue::encode(myCompression, buffer.data(), buffer.size()));
- EXPECT_EQ(myCompression.name.length(), *reinterpret_cast<int64_t*>(buffer.data()));
- EXPECT_FALSE(CompressionValue::decode(buffer.data(), 0).has_value());
- auto read = CompressionValue::decode(buffer.data(), buffer.size());
- ASSERT_TRUE(read.has_value());
- EXPECT_EQ(myCompression, read.value());
-}
-
-TEST(Metadata, setGetPlaneLayout) {
- using PlaneLayoutValue = StandardMetadata<StandardMetadataType::PLANE_LAYOUTS>::value;
+static std::vector<PlaneLayout> fakePlaneLayouts() {
PlaneLayout myPlaneLayout;
myPlaneLayout.offsetInBytes = 10;
myPlaneLayout.sampleIncrementInBits = 11;
@@ -153,23 +59,147 @@
it.sizeInBits = 30 + i;
}
- std::vector<PlaneLayout> layouts{myPlaneLayout, PlaneLayout{}};
+ return std::vector<PlaneLayout>{myPlaneLayout, PlaneLayout{}};
+}
- std::vector<char> buffer(5000, '\0');
+TEST(Metadata, setGetBufferId) {
+ using BufferId = StandardMetadata<StandardMetadataType::BUFFER_ID>::value;
+
+ std::vector<uint8_t> buffer(10000, 0);
+ int64_t* payload = reinterpret_cast<int64_t*>(SkipHeader(buffer).data());
+ *payload = 42;
+
+ EXPECT_EQ(8 + HeaderSize, BufferId::encode(18, buffer.data(), 0));
+ EXPECT_EQ(42, *payload);
+ EXPECT_EQ(8 + HeaderSize, BufferId::encode(18, buffer.data(), buffer.size()));
+ EXPECT_EQ(18, *payload);
+ EXPECT_FALSE(BufferId::decode(buffer.data(), 0));
+ auto read = BufferId::decode(buffer.data(), buffer.size());
+ EXPECT_TRUE(read.has_value());
+ EXPECT_EQ(18, read.value_or(0));
+}
+
+TEST(Metadata, setGetDataspace) {
+ using DataspaceValue = StandardMetadata<StandardMetadataType::DATASPACE>::value;
+ using intType = std::underlying_type_t<Dataspace>;
+ std::vector<uint8_t> buffer(10000, 0);
+ auto data = SkipHeader(buffer);
+
+ EXPECT_EQ(4 + HeaderSize, DataspaceValue::encode(Dataspace::BT2020, buffer.data(), 0));
+ EXPECT_EQ(0, *reinterpret_cast<intType*>(data.data()));
+ EXPECT_EQ(4 + HeaderSize,
+ DataspaceValue::encode(Dataspace::BT2020, buffer.data(), buffer.size()));
+ EXPECT_EQ(static_cast<intType>(Dataspace::BT2020), *reinterpret_cast<intType*>(data.data()));
+ EXPECT_FALSE(DataspaceValue::decode(buffer.data(), 0));
+ auto read = DataspaceValue::decode(buffer.data(), buffer.size());
+ ASSERT_TRUE(read.has_value());
+ EXPECT_EQ(Dataspace::BT2020, *read);
+}
+
+TEST(Metadata, setGetValidName) {
+ using NameValue = StandardMetadata<StandardMetadataType::NAME>::value;
+
+ std::vector<uint8_t> buffer(10000, 'a');
+
+ // len("Hello") + sizeof(int64)
+ constexpr int expectedSize = 5 + sizeof(int64_t) + HeaderSize;
+ EXPECT_EQ(expectedSize, NameValue::encode("Hello", buffer.data(), buffer.size()));
+ EXPECT_EQ(5, *reinterpret_cast<int64_t*>(SkipHeader(buffer).data()));
+ // Verify didn't write past the end of the desired size
+ EXPECT_EQ('a', buffer[expectedSize]);
+
+ auto readValue = NameValue::decode(buffer.data(), buffer.size());
+ ASSERT_TRUE(readValue.has_value());
+ EXPECT_EQ(5, readValue->length());
+ EXPECT_EQ("Hello", *readValue);
+}
+
+TEST(Metadata, setGetInvalidName) {
+ using NameValue = StandardMetadata<StandardMetadataType::NAME>::value;
+
+ std::vector<uint8_t> buffer;
+ buffer.resize(12 + HeaderSize, 'a');
+ buffer[buffer.size() - 1] = '\0';
+
+ // len("This is a long string") + sizeof(int64)
+ constexpr int expectedSize = 21 + sizeof(int64_t) + HeaderSize;
+ EXPECT_EQ(expectedSize,
+ NameValue::encode("This is a long string", buffer.data(), buffer.size()));
+ EXPECT_EQ(21, *reinterpret_cast<int64_t*>(SkipHeader(buffer).data()));
+
+ auto readValue = NameValue::decode(buffer.data(), buffer.size());
+ EXPECT_FALSE(readValue.has_value());
+ readValue = NameValue::decode(buffer.data(), 0);
+ ASSERT_FALSE(readValue.has_value());
+}
+
+TEST(Metadata, wouldOverflowName) {
+ using NameValue = StandardMetadata<StandardMetadataType::NAME>::value;
+ std::vector<uint8_t> buffer(10000, 0);
+
+ // int_max + sizeof(int64) overflows int32
+ std::string_view bad_string{"badbeef", std::numeric_limits<int32_t>::max()};
+ EXPECT_EQ(-AIMAPPER_ERROR_BAD_VALUE,
+ NameValue::encode(bad_string, buffer.data(), buffer.size()));
+
+ // check barely overflows
+ bad_string = std::string_view{"badbeef", std::numeric_limits<int32_t>::max() - 7};
+ EXPECT_EQ(-AIMAPPER_ERROR_BAD_VALUE,
+ NameValue::encode(bad_string, buffer.data(), buffer.size()));
+}
+
+TEST(Metadata, setGetMismatchedWidthHight) {
+ // Validates that the header is properly validated on decode
+ using WidthValue = StandardMetadata<StandardMetadataType::WIDTH>::value;
+ using HeightValue = StandardMetadata<StandardMetadataType::HEIGHT>::value;
+ std::vector<uint8_t> buffer(10000, 0);
+
+ EXPECT_EQ(8 + HeaderSize, WidthValue::encode(100, buffer.data(), buffer.size()));
+ EXPECT_EQ(100, *reinterpret_cast<uint64_t*>(SkipHeader(buffer).data()));
+ auto read = WidthValue::decode(buffer.data(), buffer.size());
+ ASSERT_TRUE(read.has_value());
+ EXPECT_EQ(100, *read);
+ read = HeightValue::decode(buffer.data(), buffer.size());
+ EXPECT_FALSE(read.has_value());
+}
+
+TEST(Metadata, setGetCompression) {
+ using CompressionValue = StandardMetadata<StandardMetadataType::COMPRESSION>::value;
+ ExtendableType myCompression{"bestest_compression_ever", 42};
+ std::vector<uint8_t> buffer(10000, 0);
+ const int expectedSize =
+ myCompression.name.length() + sizeof(int64_t) + sizeof(int64_t) + HeaderSize;
+ EXPECT_EQ(expectedSize, CompressionValue::encode(myCompression, buffer.data(), 0));
+ EXPECT_EQ(0, buffer[0]);
+ EXPECT_EQ(expectedSize, CompressionValue::encode(myCompression, buffer.data(), buffer.size()));
+ EXPECT_EQ(myCompression.name.length(), *reinterpret_cast<int64_t*>(SkipHeader(buffer).data()));
+ EXPECT_FALSE(CompressionValue::decode(buffer.data(), 0).has_value());
+ auto read = CompressionValue::decode(buffer.data(), buffer.size());
+ ASSERT_TRUE(read.has_value());
+ EXPECT_EQ(myCompression, read.value());
+}
+
+TEST(Metadata, setGetPlaneLayout) {
+ using PlaneLayoutValue = StandardMetadata<StandardMetadataType::PLANE_LAYOUTS>::value;
+
+ std::vector<PlaneLayout> layouts = fakePlaneLayouts();
+
+ std::vector<uint8_t> buffer(10000, 0);
constexpr int componentSize = 8 + (4 * sizeof(int64_t));
constexpr int firstLayoutSize = (8 + 1) * sizeof(int64_t) + (3 * componentSize);
constexpr int secondLayoutSize = (8 + 1) * sizeof(int64_t);
- constexpr int expectedSize = firstLayoutSize + secondLayoutSize + sizeof(int64_t);
+ constexpr int expectedSize = firstLayoutSize + secondLayoutSize + sizeof(int64_t) + HeaderSize;
EXPECT_EQ(expectedSize, PlaneLayoutValue::encode(layouts, buffer.data(), 0));
EXPECT_EQ(0, buffer[0]);
EXPECT_EQ(expectedSize, PlaneLayoutValue::encode(layouts, buffer.data(), buffer.size()));
- EXPECT_EQ(3, reinterpret_cast<int64_t*>(buffer.data())[1]);
- EXPECT_EQ(8, reinterpret_cast<int64_t*>(buffer.data())[2]);
- EXPECT_EQ(40, reinterpret_cast<int64_t*>(buffer.data())[4]);
- EXPECT_EQ(31, reinterpret_cast<int64_t*>(buffer.data())[11]);
- EXPECT_EQ(22, reinterpret_cast<int64_t*>(buffer.data())[15]);
- EXPECT_EQ(10, reinterpret_cast<int64_t*>(buffer.data())[17]);
- EXPECT_EQ(11, reinterpret_cast<int64_t*>(buffer.data())[18]);
+ int64_t* payload = reinterpret_cast<int64_t*>(SkipHeader(buffer).data());
+ EXPECT_EQ(3, payload[1]);
+ EXPECT_EQ(8, payload[2]);
+ EXPECT_EQ(40, payload[4]);
+ EXPECT_EQ(31, payload[11]);
+ EXPECT_EQ(22, payload[15]);
+ EXPECT_EQ(10, payload[17]);
+ EXPECT_EQ(11, payload[18]);
EXPECT_FALSE(PlaneLayoutValue::decode(buffer.data(), 0).has_value());
auto read = PlaneLayoutValue::decode(buffer.data(), buffer.size());
ASSERT_TRUE(read.has_value());
@@ -178,15 +208,15 @@
TEST(Metadata, setGetRects) {
using RectsValue = StandardMetadata<StandardMetadataType::CROP>::value;
- std::vector<uint8_t> buffer(500, 0);
+ std::vector<uint8_t> buffer(10000, 0);
std::vector<Rect> cropRects{2};
cropRects[0] = Rect{10, 11, 12, 13};
cropRects[1] = Rect{20, 21, 22, 23};
- constexpr int expectedSize = sizeof(int64_t) + (8 * sizeof(int32_t));
+ constexpr int expectedSize = sizeof(int64_t) + (8 * sizeof(int32_t)) + HeaderSize;
EXPECT_EQ(expectedSize, RectsValue::encode(cropRects, buffer.data(), buffer.size()));
- EXPECT_EQ(2, reinterpret_cast<int64_t*>(buffer.data())[0]);
- EXPECT_EQ(10, reinterpret_cast<int32_t*>(buffer.data())[2]);
+ EXPECT_EQ(2, reinterpret_cast<int64_t*>(SkipHeader(buffer).data())[0]);
+ EXPECT_EQ(10, reinterpret_cast<int32_t*>(SkipHeader(buffer).data())[2]);
auto read = RectsValue::decode(buffer.data(), buffer.size());
ASSERT_TRUE(read.has_value());
EXPECT_EQ(cropRects.size(), read->size());
@@ -203,8 +233,8 @@
source.primaryGreen = XyColor{.3f, .4f};
source.primaryBlue = XyColor{.5f, .6f};
- constexpr int expectedSize = 10 * sizeof(float);
- std::vector<uint8_t> buffer(500, 0);
+ constexpr int expectedSize = 10 * sizeof(float) + HeaderSize;
+ std::vector<uint8_t> buffer(10000, 0);
EXPECT_EQ(expectedSize, Smpte2086Value::encode(source, buffer.data(), buffer.size()));
auto read = Smpte2086Value::decode(buffer.data(), buffer.size());
ASSERT_TRUE(read.has_value());
@@ -223,8 +253,8 @@
source.maxFrameAverageLightLevel = 244.55f;
source.maxContentLightLevel = 202.202f;
- constexpr int expectedSize = 2 * sizeof(float);
- std::vector<uint8_t> buffer(500, 0);
+ constexpr int expectedSize = 2 * sizeof(float) + HeaderSize;
+ std::vector<uint8_t> buffer(10000, 0);
EXPECT_EQ(expectedSize, Cta861_3Value::encode(source, buffer.data(), buffer.size()));
auto read = Cta861_3Value::decode(buffer.data(), buffer.size());
ASSERT_TRUE(read.has_value());
@@ -240,14 +270,14 @@
TEST(Metadata, setGetSmpte2094_10) {
using SMPTE2094_10Value = StandardMetadata<StandardMetadataType::SMPTE2094_10>::value;
- std::vector<uint8_t> buffer(500, 0);
+ std::vector<uint8_t> buffer(10000, 0);
EXPECT_EQ(0, SMPTE2094_10Value::encode(std::nullopt, buffer.data(), buffer.size()));
auto read = SMPTE2094_10Value::decode(buffer.data(), 0);
ASSERT_TRUE(read.has_value());
EXPECT_FALSE(read->has_value());
const std::vector<uint8_t> emptyBuffer;
- EXPECT_EQ(sizeof(int64_t),
+ EXPECT_EQ(sizeof(int64_t) + HeaderSize,
SMPTE2094_10Value::encode(emptyBuffer, buffer.data(), buffer.size()));
read = SMPTE2094_10Value::decode(buffer.data(), buffer.size());
ASSERT_TRUE(read.has_value());
@@ -255,7 +285,7 @@
EXPECT_EQ(0, read->value().size());
const std::vector<uint8_t> simpleBuffer{0, 1, 2, 3, 4, 5};
- EXPECT_EQ(sizeof(int64_t) + 6,
+ EXPECT_EQ(sizeof(int64_t) + 6 + HeaderSize,
SMPTE2094_10Value::encode(simpleBuffer, buffer.data(), buffer.size()));
read = SMPTE2094_10Value::decode(buffer.data(), buffer.size());
ASSERT_TRUE(read.has_value());
@@ -266,7 +296,7 @@
TEST(MetadataProvider, bufferId) {
using BufferId = StandardMetadata<StandardMetadataType::BUFFER_ID>::value;
- std::vector<uint8_t> buffer(500, 0);
+ std::vector<uint8_t> buffer(10000, 0);
int result = provideStandardMetadata(StandardMetadataType::BUFFER_ID, buffer.data(),
buffer.size(), []<StandardMetadataType T>(auto&& provide) {
if constexpr (T == StandardMetadataType::BUFFER_ID) {
@@ -275,7 +305,7 @@
return 0;
});
- EXPECT_EQ(8, result);
+ EXPECT_EQ(8 + HeaderSize, result);
auto read = BufferId::decode(buffer.data(), buffer.size());
EXPECT_EQ(42, read.value_or(0));
}
@@ -312,3 +342,193 @@
EXPECT_EQ(-AIMAPPER_ERROR_UNSUPPORTED, result)
<< "100 (out of range) should have resulted in UNSUPPORTED";
}
+
+template <StandardMetadataType T>
+std::vector<uint8_t> encode(const typename StandardMetadata<T>::value_type& value) {
+ using Value = typename StandardMetadata<T>::value;
+
+ int desiredSize = Value::encode(value, nullptr, 0);
+ EXPECT_GE(desiredSize, 0);
+ std::vector<uint8_t> buffer;
+ buffer.resize(desiredSize);
+ EXPECT_EQ(desiredSize, Value::encode(value, buffer.data(), buffer.size()));
+ return buffer;
+}
+
+TEST(MetadataGralloc4Interop, BufferId) {
+ auto mpbuf = encode<StandardMetadataType::BUFFER_ID>(42);
+ hidl_vec<uint8_t> g4buf;
+ ASSERT_EQ(NO_ERROR, gralloc4::encodeBufferId(42, &g4buf));
+ EXPECT_EQ(mpbuf, g4buf);
+}
+
+TEST(MetadataGralloc4Interop, Name) {
+ auto mpbuf = encode<StandardMetadataType::NAME>("Hello, Interop!");
+ hidl_vec<uint8_t> g4buf;
+ ASSERT_EQ(NO_ERROR, gralloc4::encodeName("Hello, Interop!", &g4buf));
+ EXPECT_EQ(mpbuf, g4buf);
+}
+
+TEST(MetadataGralloc4Interop, Width) {
+ auto mpbuf = encode<StandardMetadataType::WIDTH>(128);
+ hidl_vec<uint8_t> g4buf;
+ ASSERT_EQ(NO_ERROR, gralloc4::encodeWidth(128, &g4buf));
+ EXPECT_EQ(mpbuf, g4buf);
+}
+
+TEST(MetadataGralloc4Interop, Height) {
+ auto mpbuf = encode<StandardMetadataType::HEIGHT>(64);
+ hidl_vec<uint8_t> g4buf;
+ ASSERT_EQ(NO_ERROR, gralloc4::encodeHeight(64, &g4buf));
+ EXPECT_EQ(mpbuf, g4buf);
+}
+
+TEST(MetadataGralloc4Interop, LayerCount) {
+ auto mpbuf = encode<StandardMetadataType::LAYER_COUNT>(3);
+ hidl_vec<uint8_t> g4buf;
+ ASSERT_EQ(NO_ERROR, gralloc4::encodeLayerCount(3, &g4buf));
+ EXPECT_EQ(mpbuf, g4buf);
+}
+
+TEST(MetadataGralloc4Interop, PixelFormatRequested) {
+ auto mpbuf = encode<StandardMetadataType::PIXEL_FORMAT_REQUESTED>(PixelFormat::RGBX_8888);
+ hidl_vec<uint8_t> g4buf;
+ ASSERT_EQ(NO_ERROR, gralloc4::encodePixelFormatRequested(
+ hardware::graphics::common::V1_2::PixelFormat::RGBX_8888, &g4buf));
+ EXPECT_EQ(mpbuf, g4buf);
+}
+
+TEST(MetadataGralloc4Interop, PixelFormatFourcc) {
+ auto mpbuf = encode<StandardMetadataType::PIXEL_FORMAT_FOURCC>(DRM_FORMAT_ABGR8888);
+ hidl_vec<uint8_t> g4buf;
+ ASSERT_EQ(NO_ERROR, gralloc4::encodePixelFormatFourCC(DRM_FORMAT_ABGR8888, &g4buf));
+ EXPECT_EQ(mpbuf, g4buf);
+}
+
+TEST(MetadataGralloc4Interop, PixelFormatModifier) {
+ auto mpbuf = encode<StandardMetadataType::PIXEL_FORMAT_MODIFIER>(123456);
+ hidl_vec<uint8_t> g4buf;
+ ASSERT_EQ(NO_ERROR, gralloc4::encodePixelFormatModifier(123456, &g4buf));
+ EXPECT_EQ(mpbuf, g4buf);
+}
+
+TEST(MetadataGralloc4Interop, Usage) {
+ auto mpbuf = encode<StandardMetadataType::USAGE>(BufferUsage::COMPOSER_OVERLAY);
+ hidl_vec<uint8_t> g4buf;
+ ASSERT_EQ(NO_ERROR,
+ gralloc4::encodeUsage(
+ static_cast<uint64_t>(
+ hardware::graphics::common::V1_2::BufferUsage::COMPOSER_OVERLAY),
+ &g4buf));
+ EXPECT_EQ(mpbuf, g4buf);
+}
+
+TEST(MetadataGralloc4Interop, AllocationSize) {
+ auto mpbuf = encode<StandardMetadataType::ALLOCATION_SIZE>(10200);
+ hidl_vec<uint8_t> g4buf;
+ ASSERT_EQ(NO_ERROR, gralloc4::encodeAllocationSize(10200, &g4buf));
+ EXPECT_EQ(mpbuf, g4buf);
+}
+
+TEST(MetadataGralloc4Interop, ProtectedContent) {
+ auto mpbuf = encode<StandardMetadataType::PROTECTED_CONTENT>(1);
+ hidl_vec<uint8_t> g4buf;
+ ASSERT_EQ(NO_ERROR, gralloc4::encodeProtectedContent(1, &g4buf));
+ EXPECT_EQ(mpbuf, g4buf);
+}
+
+TEST(MetadataGralloc4Interop, Compression) {
+ auto mpbuf = encode<StandardMetadataType::COMPRESSION>(
+ gralloc4::Compression_DisplayStreamCompression);
+ hidl_vec<uint8_t> g4buf;
+ ASSERT_EQ(NO_ERROR,
+ gralloc4::encodeCompression(gralloc4::Compression_DisplayStreamCompression, &g4buf));
+ EXPECT_EQ(mpbuf, g4buf);
+}
+
+TEST(MetadataGralloc4Interop, Interlaced) {
+ auto mpbuf = encode<StandardMetadataType::INTERLACED>(gralloc4::Interlaced_TopBottom);
+ hidl_vec<uint8_t> g4buf;
+ ASSERT_EQ(NO_ERROR, gralloc4::encodeInterlaced(gralloc4::Interlaced_TopBottom, &g4buf));
+ EXPECT_EQ(mpbuf, g4buf);
+}
+
+TEST(MetadataGralloc4Interop, ChromeSitting) {
+ auto mpbuf =
+ encode<StandardMetadataType::CHROMA_SITING>(gralloc4::ChromaSiting_SitedInterstitial);
+ hidl_vec<uint8_t> g4buf;
+ ASSERT_EQ(NO_ERROR,
+ gralloc4::encodeChromaSiting(gralloc4::ChromaSiting_SitedInterstitial, &g4buf));
+ EXPECT_EQ(mpbuf, g4buf);
+}
+
+TEST(MetadataGralloc4Interop, PlaneLayouts) {
+ auto mpbuf = encode<StandardMetadataType::PLANE_LAYOUTS>(fakePlaneLayouts());
+ hidl_vec<uint8_t> g4buf;
+ ASSERT_EQ(NO_ERROR, gralloc4::encodePlaneLayouts(fakePlaneLayouts(), &g4buf));
+ EXPECT_EQ(mpbuf, g4buf);
+}
+
+TEST(MetadataGralloc4Interop, Crop) {
+ std::vector<Rect> cropRects{Rect{10, 11, 12, 13}, Rect{20, 21, 22, 23}};
+ auto mpbuf = encode<StandardMetadataType::CROP>(cropRects);
+ hidl_vec<uint8_t> g4buf;
+ ASSERT_EQ(NO_ERROR, gralloc4::encodeCrop(cropRects, &g4buf));
+ EXPECT_EQ(mpbuf, g4buf);
+}
+
+TEST(MetadataGralloc4Interop, Dataspace) {
+ auto mpbuf = encode<StandardMetadataType::DATASPACE>(Dataspace::DISPLAY_P3);
+ hidl_vec<uint8_t> g4buf;
+ ASSERT_EQ(NO_ERROR, gralloc4::encodeDataspace(Dataspace::DISPLAY_P3, &g4buf));
+ EXPECT_EQ(mpbuf, g4buf);
+}
+
+TEST(MetadataGralloc4Interop, BlendMode) {
+ auto mpbuf = encode<StandardMetadataType::BLEND_MODE>(BlendMode::PREMULTIPLIED);
+ hidl_vec<uint8_t> g4buf;
+ ASSERT_EQ(NO_ERROR, gralloc4::encodeBlendMode(BlendMode::PREMULTIPLIED, &g4buf));
+ EXPECT_EQ(mpbuf, g4buf);
+}
+
+TEST(MetadataGralloc4Interop, Smpte2086) {
+ Smpte2086 hdrdata{XyColor{.1f, .2f}, XyColor{.3f, .4f}, XyColor{.5f, .6f},
+ XyColor{.7f, .8f}, 452.889f, 12.335f};
+
+ auto mpbuf = encode<StandardMetadataType::SMPTE2086>(hdrdata);
+ hidl_vec<uint8_t> g4buf;
+ ASSERT_EQ(NO_ERROR, gralloc4::encodeSmpte2086(hdrdata, &g4buf));
+ EXPECT_EQ(mpbuf, g4buf);
+}
+
+TEST(MetadataGralloc4Interop, Cta861_3) {
+ Cta861_3 hdrdata{302.202f, 244.55f};
+ auto mpbuf = encode<StandardMetadataType::CTA861_3>(hdrdata);
+ hidl_vec<uint8_t> g4buf;
+ ASSERT_EQ(NO_ERROR, gralloc4::encodeCta861_3(hdrdata, &g4buf));
+ EXPECT_EQ(mpbuf, g4buf);
+}
+
+TEST(MetadataGralloc4Interop, Smpte2094_10) {
+ auto mpbuf = encode<StandardMetadataType::SMPTE2094_10>(std::nullopt);
+ hidl_vec<uint8_t> g4buf;
+ ASSERT_EQ(NO_ERROR, gralloc4::encodeSmpte2094_10(std::nullopt, &g4buf));
+ EXPECT_EQ(mpbuf, g4buf);
+
+ std::vector<uint8_t> hdrdata{1, 2, 3, 4, 5, 6};
+ mpbuf = encode<StandardMetadataType::SMPTE2094_10>(hdrdata);
+ ASSERT_EQ(NO_ERROR, gralloc4::encodeSmpte2094_10(hdrdata, &g4buf));
+ EXPECT_EQ(mpbuf, g4buf);
+}
+
+TEST(MetadataGralloc4Interop, Smpte2094_40) {
+ auto mpbuf = encode<StandardMetadataType::SMPTE2094_40>(std::nullopt);
+ hidl_vec<uint8_t> g4buf;
+ ASSERT_EQ(NO_ERROR, gralloc4::encodeSmpte2094_40(std::nullopt, &g4buf));
+ EXPECT_EQ(mpbuf, g4buf);
+
+ std::vector<uint8_t> hdrdata{1, 2, 3, 4, 5, 6};
+ mpbuf = encode<StandardMetadataType::SMPTE2094_40>(hdrdata);
+ ASSERT_EQ(NO_ERROR, gralloc4::encodeSmpte2094_40(hdrdata, &g4buf));
+ EXPECT_EQ(mpbuf, g4buf);
+}
diff --git a/graphics/mapper/stable-c/implutils/include/android/hardware/graphics/mapper/utils/IMapperMetadataTypes.h b/graphics/mapper/stable-c/implutils/include/android/hardware/graphics/mapper/utils/IMapperMetadataTypes.h
index 7861af8..25af6d1 100644
--- a/graphics/mapper/stable-c/implutils/include/android/hardware/graphics/mapper/utils/IMapperMetadataTypes.h
+++ b/graphics/mapper/stable-c/implutils/include/android/hardware/graphics/mapper/utils/IMapperMetadataTypes.h
@@ -82,7 +82,12 @@
explicit MetadataWriter(void* _Nullable destBuffer, size_t destBufferSize)
: mDest(reinterpret_cast<uint8_t*>(destBuffer)), mSizeRemaining(destBufferSize) {}
- int32_t desiredSize() const { return mDesiredSize; }
+ [[nodiscard]] int32_t desiredSize() const { return mDesiredSize; }
+
+ template <typename HEADER>
+ MetadataWriter& writeHeader() {
+ return write(HEADER::name).template write<int64_t>(HEADER::value);
+ }
template <typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
MetadataWriter& write(T value) {
@@ -150,6 +155,18 @@
[[nodiscard]] size_t remaining() const { return mSizeRemaining; }
[[nodiscard]] bool ok() const { return mOk; }
+ template <typename HEADER>
+ MetadataReader& checkHeader() {
+ if (HEADER::name != readString()) {
+ mOk = false;
+ }
+ auto value = readInt<int64_t>();
+ if (!value || *value != HEADER::value) {
+ mOk = false;
+ }
+ return *this;
+ }
+
template <typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
MetadataReader& read(T& dest) {
if (const void* src = advance(sizeof(T))) {
@@ -228,27 +245,33 @@
}
};
-template <typename T, class Enable = void>
+template <typename HEADER, typename T, class Enable = void>
struct MetadataValue {};
-template <typename T>
-struct MetadataValue<T, std::enable_if_t<std::is_integral_v<T>>> {
+template <typename HEADER, typename T>
+struct MetadataValue<HEADER, T, std::enable_if_t<std::is_integral_v<T>>> {
[[nodiscard]] static int32_t encode(T value, void* _Nullable destBuffer,
size_t destBufferSize) {
- return MetadataWriter{destBuffer, destBufferSize}.write(value).desiredSize();
+ return MetadataWriter{destBuffer, destBufferSize}
+ .template writeHeader<HEADER>()
+ .write(value)
+ .desiredSize();
}
[[nodiscard]] static std::optional<T> decode(const void* _Nonnull metadata,
size_t metadataSize) {
- return MetadataReader{metadata, metadataSize}.readInt<T>();
+ return MetadataReader{metadata, metadataSize}
+ .template checkHeader<HEADER>()
+ .template readInt<T>();
}
};
-template <typename T>
-struct MetadataValue<T, std::enable_if_t<std::is_enum_v<T>>> {
+template <typename HEADER, typename T>
+struct MetadataValue<HEADER, T, std::enable_if_t<std::is_enum_v<T>>> {
[[nodiscard]] static int32_t encode(T value, void* _Nullable destBuffer,
size_t destBufferSize) {
return MetadataWriter{destBuffer, destBufferSize}
+ .template writeHeader<HEADER>()
.write(static_cast<std::underlying_type_t<T>>(value))
.desiredSize();
}
@@ -256,47 +279,56 @@
[[nodiscard]] static std::optional<T> decode(const void* _Nonnull metadata,
size_t metadataSize) {
std::underlying_type_t<T> temp;
- return MetadataReader{metadata, metadataSize}.read(temp).ok()
+ return MetadataReader{metadata, metadataSize}.template checkHeader<HEADER>().read(temp).ok()
? std::optional<T>(static_cast<T>(temp))
: std::nullopt;
}
};
-template <>
-struct MetadataValue<std::string> {
+template <typename HEADER>
+struct MetadataValue<HEADER, std::string> {
[[nodiscard]] static int32_t encode(const std::string_view& value, void* _Nullable destBuffer,
size_t destBufferSize) {
- return MetadataWriter{destBuffer, destBufferSize}.write(value).desiredSize();
+ return MetadataWriter{destBuffer, destBufferSize}
+ .template writeHeader<HEADER>()
+ .write(value)
+ .desiredSize();
}
[[nodiscard]] static std::optional<std::string> decode(const void* _Nonnull metadata,
size_t metadataSize) {
- auto reader = MetadataReader{metadata, metadataSize};
+ auto reader = MetadataReader{metadata, metadataSize}.template checkHeader<HEADER>();
auto result = reader.readString();
return reader.ok() ? std::optional<std::string>{result} : std::nullopt;
}
};
-template <>
-struct MetadataValue<ExtendableType> {
+template <typename HEADER>
+struct MetadataValue<HEADER, ExtendableType> {
static_assert(sizeof(int64_t) == sizeof(ExtendableType::value));
[[nodiscard]] static int32_t encode(const ExtendableType& value, void* _Nullable destBuffer,
size_t destBufferSize) {
- return MetadataWriter{destBuffer, destBufferSize}.write(value).desiredSize();
+ return MetadataWriter{destBuffer, destBufferSize}
+ .template writeHeader<HEADER>()
+ .write(value)
+ .desiredSize();
}
[[nodiscard]] static std::optional<ExtendableType> decode(const void* _Nonnull metadata,
size_t metadataSize) {
- return MetadataReader{metadata, metadataSize}.readExtendable();
+ return MetadataReader{metadata, metadataSize}
+ .template checkHeader<HEADER>()
+ .readExtendable();
}
};
-template <>
-struct MetadataValue<std::vector<PlaneLayout>> {
+template <typename HEADER>
+struct MetadataValue<HEADER, std::vector<PlaneLayout>> {
[[nodiscard]] static int32_t encode(const std::vector<PlaneLayout>& values,
void* _Nullable destBuffer, size_t destBufferSize) {
MetadataWriter writer{destBuffer, destBufferSize};
+ writer.template writeHeader<HEADER>();
writer.write<int64_t>(values.size());
for (const auto& value : values) {
writer.write<int64_t>(value.components.size());
@@ -321,13 +353,14 @@
[[nodiscard]] static DecodeResult decode(const void* _Nonnull metadata, size_t metadataSize) {
std::vector<PlaneLayout> values;
MetadataReader reader{metadata, metadataSize};
+ reader.template checkHeader<HEADER>();
auto numPlanes = reader.readInt<int64_t>().value_or(0);
values.reserve(numPlanes);
for (int i = 0; i < numPlanes && reader.ok(); i++) {
PlaneLayout& value = values.emplace_back();
auto numPlaneComponents = reader.readInt<int64_t>().value_or(0);
value.components.reserve(numPlaneComponents);
- for (int i = 0; i < numPlaneComponents && reader.ok(); i++) {
+ for (int j = 0; j < numPlaneComponents && reader.ok(); j++) {
PlaneLayoutComponent& component = value.components.emplace_back();
reader.read(component.type)
.read<int64_t>(component.offsetInBits)
@@ -346,11 +379,12 @@
}
};
-template <>
-struct MetadataValue<std::vector<Rect>> {
+template <typename HEADER>
+struct MetadataValue<HEADER, std::vector<Rect>> {
[[nodiscard]] static int32_t encode(const std::vector<Rect>& value, void* _Nullable destBuffer,
size_t destBufferSize) {
MetadataWriter writer{destBuffer, destBufferSize};
+ writer.template writeHeader<HEADER>();
writer.write<int64_t>(value.size());
for (auto& rect : value) {
writer.write<int32_t>(rect.left)
@@ -364,6 +398,7 @@
using DecodeResult = std::optional<std::vector<Rect>>;
[[nodiscard]] static DecodeResult decode(const void* _Nonnull metadata, size_t metadataSize) {
MetadataReader reader{metadata, metadataSize};
+ reader.template checkHeader<HEADER>();
std::vector<Rect> value;
auto numRects = reader.readInt<int64_t>().value_or(0);
value.reserve(numRects);
@@ -378,13 +413,14 @@
}
};
-template <>
-struct MetadataValue<std::optional<Smpte2086>> {
+template <typename HEADER>
+struct MetadataValue<HEADER, std::optional<Smpte2086>> {
[[nodiscard]] static int32_t encode(const std::optional<Smpte2086>& optValue,
void* _Nullable destBuffer, size_t destBufferSize) {
if (optValue.has_value()) {
const auto& value = *optValue;
return MetadataWriter{destBuffer, destBufferSize}
+ .template writeHeader<HEADER>()
.write(value.primaryRed)
.write(value.primaryGreen)
.write(value.primaryBlue)
@@ -404,6 +440,7 @@
if (metadataSize > 0) {
Smpte2086 value;
MetadataReader reader{metadata, metadataSize};
+ reader.template checkHeader<HEADER>();
reader.read(value.primaryRed)
.read(value.primaryGreen)
.read(value.primaryBlue)
@@ -420,13 +457,14 @@
}
};
-template <>
-struct MetadataValue<std::optional<Cta861_3>> {
+template <typename HEADER>
+struct MetadataValue<HEADER, std::optional<Cta861_3>> {
[[nodiscard]] static int32_t encode(const std::optional<Cta861_3>& optValue,
void* _Nullable destBuffer, size_t destBufferSize) {
if (optValue.has_value()) {
const auto& value = *optValue;
return MetadataWriter{destBuffer, destBufferSize}
+ .template writeHeader<HEADER>()
.write(value.maxContentLightLevel)
.write(value.maxFrameAverageLightLevel)
.desiredSize();
@@ -441,6 +479,7 @@
std::optional<Cta861_3> optValue{std::nullopt};
if (metadataSize > 0) {
MetadataReader reader{metadata, metadataSize};
+ reader.template checkHeader<HEADER>();
Cta861_3 value;
reader.read(value.maxContentLightLevel).read(value.maxFrameAverageLightLevel);
if (reader.ok()) {
@@ -453,14 +492,17 @@
}
};
-template <>
-struct MetadataValue<std::optional<std::vector<uint8_t>>> {
+template <typename HEADER>
+struct MetadataValue<HEADER, std::optional<std::vector<uint8_t>>> {
[[nodiscard]] static int32_t encode(const std::optional<std::vector<uint8_t>>& value,
void* _Nullable destBuffer, size_t destBufferSize) {
if (!value.has_value()) {
return 0;
}
- return MetadataWriter{destBuffer, destBufferSize}.write(*value).desiredSize();
+ return MetadataWriter{destBuffer, destBufferSize}
+ .template writeHeader<HEADER>()
+ .write(*value)
+ .desiredSize();
}
using DecodeResult = std::optional<std::optional<std::vector<uint8_t>>>;
@@ -468,6 +510,7 @@
std::optional<std::vector<uint8_t>> optValue;
if (metadataSize > 0) {
MetadataReader reader{metadata, metadataSize};
+ reader.template checkHeader<HEADER>();
auto value = reader.readBuffer();
if (reader.ok()) {
optValue = std::move(value);
@@ -482,16 +525,20 @@
template <StandardMetadataType>
struct StandardMetadata {};
-#define DEFINE_TYPE(name, typeArg) \
- template <> \
- struct StandardMetadata<StandardMetadataType::name> { \
- using value_type = typeArg; \
- using value = MetadataValue<value_type>; \
- static_assert( \
- StandardMetadataType::name == \
- ndk::internal::enum_values<StandardMetadataType>[static_cast<size_t>( \
- StandardMetadataType::name)], \
- "StandardMetadataType must have equivalent value to index"); \
+#define DEFINE_TYPE(typeName, typeArg) \
+ template <> \
+ struct StandardMetadata<StandardMetadataType::typeName> { \
+ using value_type = typeArg; \
+ struct Header { \
+ static constexpr auto name = "android.hardware.graphics.common.StandardMetadataType"; \
+ static constexpr auto value = static_cast<int64_t>(StandardMetadataType::typeName); \
+ }; \
+ using value = MetadataValue<Header, value_type>; \
+ static_assert( \
+ StandardMetadataType::typeName == \
+ ndk::internal::enum_values<StandardMetadataType>[static_cast<size_t>( \
+ StandardMetadataType::typeName)], \
+ "StandardMetadataType must have equivalent value to index"); \
}
DEFINE_TYPE(BUFFER_ID, uint64_t);
diff --git a/graphics/mapper/stable-c/include/android/hardware/graphics/mapper/IMapper.h b/graphics/mapper/stable-c/include/android/hardware/graphics/mapper/IMapper.h
index 0f6d146..e9dea1a 100644
--- a/graphics/mapper/stable-c/include/android/hardware/graphics/mapper/IMapper.h
+++ b/graphics/mapper/stable-c/include/android/hardware/graphics/mapper/IMapper.h
@@ -26,10 +26,8 @@
#pragma once
+#include <stdint.h>
#include <sys/cdefs.h>
-#include <cinttypes>
-#include <cstddef>
-#include <type_traits>
#include <android/rect.h>
#include <cutils/native_handle.h>
diff --git a/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp b/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp
index 326346c..85246ee 100644
--- a/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp
+++ b/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp
@@ -234,7 +234,7 @@
sizeRequired = mapper()->v5.getStandardMetadata(bufferHandle, static_cast<int64_t>(T),
buffer.data(), buffer.size());
}
- if (sizeRequired < 0 || sizeRequired >= buffer.size()) {
+ if (sizeRequired < 0 || sizeRequired > buffer.size()) {
ADD_FAILURE() << "getStandardMetadata failed, received " << sizeRequired
<< " with buffer size " << buffer.size();
// Generate a fail type
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/identity/support/Android.bp b/identity/support/Android.bp
index 4e3d1f7..3096fe5 100644
--- a/identity/support/Android.bp
+++ b/identity/support/Android.bp
@@ -65,57 +65,3 @@
],
test_suites: ["general-tests"],
}
-
-// --
-
-cc_library {
- name: "libcppbor",
- vendor_available: true,
- host_supported: true,
- srcs: [
- "src/cppbor.cpp",
- "src/cppbor_parse.cpp",
- ],
- export_include_dirs: [
- "include/cppbor",
- ],
- shared_libs: [
- "libbase",
- ],
-}
-
-cc_test {
- name: "cppbor_test",
- tidy_timeout_srcs: [
- "tests/cppbor_test.cpp",
- ],
- srcs: [
- "tests/cppbor_test.cpp",
- ],
- shared_libs: [
- "libcppbor_external",
- "libbase",
- ],
- static_libs: [
- "libgmock",
- ],
- test_suites: ["general-tests"],
-}
-
-cc_test_host {
- name: "cppbor_host_test",
- tidy_timeout_srcs: [
- "tests/cppbor_test.cpp",
- ],
- srcs: [
- "tests/cppbor_test.cpp",
- ],
- shared_libs: [
- "libcppbor_external",
- "libbase",
- ],
- static_libs: [
- "libgmock",
- ],
- test_suites: ["general-tests"],
-}
diff --git a/identity/support/include/cppbor/README.md b/identity/support/include/cppbor/README.md
deleted file mode 100644
index 723bfcf..0000000
--- a/identity/support/include/cppbor/README.md
+++ /dev/null
@@ -1,216 +0,0 @@
-CppBor: A Modern C++ CBOR Parser and Generator
-==============================================
-
-CppBor provides a natural and easy-to-use syntax for constructing and
-parsing CBOR messages. It does not (yet) support all features of
-CBOR, nor (yet) support validation against CDDL schemata, though both
-are planned. CBOR features that aren't supported include:
-
-* Indefinite length values
-* Semantic tagging
-* Floating point
-
-CppBor requires C++-17.
-
-## CBOR representation
-
-CppBor represents CBOR data items as instances of the `Item` class or,
-more precisely, as instances of subclasses of `Item`, since `Item` is a
-pure interface. The subclasses of `Item` correspond almost one-to-one
-with CBOR major types, and are named to match the CDDL names to which
-they correspond. They are:
-
-* `Uint` corresponds to major type 0, and can hold unsigned integers
- up through (2^64 - 1).
-* `Nint` corresponds to major type 1. It can only hold values from -1
- to -(2^63 - 1), since it's internal representation is an int64_t.
- This can be fixed, but it seems unlikely that applications will need
- the omitted range from -(2^63) to (2^64 - 1), since it's
- inconvenient to represent them in many programming languages.
-* `Int` is an abstract base of `Uint` and `Nint` that facilitates
- working with all signed integers representable with int64_t.
-* `Bstr` corresponds to major type 2, a byte string.
-* `Tstr` corresponds to major type 3, a text string.
-* `Array` corresponds to major type 4, an Array. It holds a
- variable-length array of `Item`s.
-* `Map` corresponds to major type 5, a Map. It holds a
- variable-length array of pairs of `Item`s.
-* `Simple` corresponds to major type 7. It's an abstract class since
- items require more specific type.
-* `Bool` is the only currently-implemented subclass of `Simple`.
-
-Note that major type 6, semantic tag, is not yet implemented.
-
-In practice, users of CppBor will rarely use most of these classes
-when generating CBOR encodings. This is because CppBor provides
-straightforward conversions from the obvious normal C++ types.
-Specifically, the following conversions are provided in appropriate
-contexts:
-
-* Signed and unsigned integers convert to `Uint` or `Nint`, as
- appropriate.
-* `std::string`, `std::string_view`, `const char*` and
- `std::pair<char iterator, char iterator>` convert to `Tstr`.
-* `std::vector<uint8_t>`, `std::pair<uint8_t iterator, uint8_t
- iterator>` and `std::pair<uint8_t*, size_t>` convert to `Bstr`.
-* `bool` converts to `Bool`.
-
-## CBOR generation
-
-### Complete tree generation
-
-The set of `encode` methods in `Item` provide the interface for
-producing encoded CBOR. The basic process for "complete tree"
-generation (as opposed to "incremental" generation, which is discussed
-below) is to construct an `Item` which models the data to be encoded,
-and then call one of the `encode` methods, whichever is convenient for
-the encoding destination. A trivial example:
-
-```
-cppbor::Uint val(0);
-std::vector<uint8_t> encoding = val.encode();
-```
-
- It's relatively rare that single values are encoded as above. More often, the
- "root" data item will be an `Array` or `Map` which contains a more complex structure.For example
- :
-
-``` using cppbor::Map;
-using cppbor::Array;
-
-std::vector<uint8_t> vec = // ...
- Map val("key1", Array(Map("key_a", 99 "key_b", vec), "foo"), "key2", true);
-std::vector<uint8_t> encoding = val.encode();
-```
-
-This creates a map with two entries, with `Tstr` keys "Outer1" and
-"Outer2", respectively. The "Outer1" entry has as its value an
-`Array` containing a `Map` and a `Tstr`. The "Outer2" entry has a
-`Bool` value.
-
-This example demonstrates how automatic conversion of C++ types to
-CppBor `Item` subclass instances is done. Where the caller provides a
-C++ or C string, a `Tstr` entry is added. Where the caller provides
-an integer literal or variable, a `Uint` or `Nint` is added, depending
-on whether the value is positive or negative.
-
-As an alternative, a more fluent-style API is provided for building up
-structures. For example:
-
-```
-using cppbor::Map;
-using cppbor::Array;
-
-std::vector<uint8_t> vec = // ...
- Map val();
-val.add("key1", Array().add(Map().add("key_a", 99).add("key_b", vec)).add("foo")).add("key2", true);
-std::vector<uint8_t> encoding = val.encode();
-```
-
- An advantage of this interface over the constructor -
- based creation approach above is that it need not be done all at once
- .The `add` methods return a reference to the object added to to allow calls to be chained,
- but chaining is not necessary; calls can be made
-sequentially, as the data to add is available.
-
-#### `encode` methods
-
-There are several variations of `Item::encode`, all of which
-accomplish the same task but output the encoded data in different
-ways, and with somewhat different performance characteristics. The
-provided options are:
-
-* `bool encode(uint8\_t** pos, const uint8\_t* end)` encodes into the
- buffer referenced by the range [`*pos`, end). `*pos` is moved. If
- the encoding runs out of buffer space before finishing, the method
- returns false. This is the most efficient way to encode, into an
- already-allocated buffer.
-* `void encode(EncodeCallback encodeCallback)` calls `encodeCallback`
- for each encoded byte. It's the responsibility of the implementor
- of the callback to behave safely in the event that the output buffer
- (if applicable) is exhausted. This is less efficient than the prior
- method because it imposes an additional function call for each byte.
-* `template </*...*/> void encode(OutputIterator i)`
- encodes into the provided iterator. SFINAE ensures that the
- template doesn't match for non-iterators. The implementation
- actually uses the callback-based method, plus has whatever overhead
- the iterator adds.
-* `std::vector<uint8_t> encode()` creates a new std::vector, reserves
- sufficient capacity to hold the encoding, and inserts the encoded
- bytes with a std::pushback_iterator and the previous method.
-* `std::string toString()` does the same as the previous method, but
- returns a string instead of a vector.
-
-### Incremental generation
-
-Incremental generation requires deeper understanding of CBOR, because
-the library can't do as much to ensure that the output is valid. The
-basic tool for intcremental generation is the `encodeHeader`
-function. There are two variations, one which writes into a buffer,
-and one which uses a callback. Both simply write out the bytes of a
-header. To construct the same map as in the above examples,
-incrementally, one might write:
-
-```
-using namespace cppbor; // For example brevity
-
-std::vector encoding;
-auto iter = std::back_inserter(result);
-encodeHeader(MAP, 2 /* # of map entries */, iter);
-std::string s = "key1";
-encodeHeader(TSTR, s.size(), iter);
-std::copy(s.begin(), s.end(), iter);
-encodeHeader(ARRAY, 2 /* # of array entries */, iter);
-Map().add("key_a", 99).add("key_b", vec).encode(iter)
-s = "foo";
-encodeHeader(TSTR, foo.size(), iter);
-std::copy(s.begin(), s.end(), iter);
-s = "key2";
-encodeHeader(TSTR, foo.size(), iter);
-std::copy(s.begin(), s.end(), iter);
-encodeHeader(SIMPLE, TRUE, iter);
-```
-
-As the above example demonstrates, the styles can be mixed -- Note the
-creation and encoding of the inner Map using the fluent style.
-
-## Parsing
-
-CppBor also supports parsing of encoded CBOR data, with the same
-feature set as encoding. There are two basic approaches to parsing,
-"full" and "stream"
-
-### Full parsing
-
-Full parsing means completely parsing a (possibly-compound) data
-item from a byte buffer. The `parse` functions that do not take a
-`ParseClient` pointer do this. They return a `ParseResult` which is a
-tuple of three values:
-
-* std::unique_ptr<Item> that points to the parsed item, or is nullptr
- if there was a parse error.
-* const uint8_t* that points to the byte after the end of the decoded
- item, or to the first unparseable byte in the event of an error.
-* std::string that is empty on success or contains an error message if
- a parse error occurred.
-
-Assuming a successful parse, you can then use `Item::type()` to
-discover the type of the parsed item (e.g. MAP), and then use the
-appropriate `Item::as*()` method (e.g. `Item::asMap()`) to get a
-pointer to an interface which allows you to retrieve specific values.
-
-### Stream parsing
-
-Stream parsing is more complex, but more flexible. To use
-StreamParsing, you must create your own subclass of `ParseClient` and
-call one of the `parse` functions that accepts it. See the
-`ParseClient` methods docstrings for details.
-
-One unusual feature of stream parsing is that the `ParseClient`
-callback methods not only provide the parsed Item, but also pointers
-to the portion of the buffer that encode that Item. This is useful
-if, for example, you want to find an element inside of a structure,
-and then copy the encoding of that sub-structure, without bothering to
-parse the rest.
-
-The full parser is implemented with the stream parser.
diff --git a/identity/support/include/cppbor/cppbor.h b/identity/support/include/cppbor/cppbor.h
deleted file mode 100644
index af5d82e..0000000
--- a/identity/support/include/cppbor/cppbor.h
+++ /dev/null
@@ -1,827 +0,0 @@
-/*
- * Copyright (c) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <cstdint>
-#include <functional>
-#include <iterator>
-#include <memory>
-#include <numeric>
-#include <string>
-#include <vector>
-
-namespace cppbor {
-
-enum MajorType : uint8_t {
- UINT = 0 << 5,
- NINT = 1 << 5,
- BSTR = 2 << 5,
- TSTR = 3 << 5,
- ARRAY = 4 << 5,
- MAP = 5 << 5,
- SEMANTIC = 6 << 5,
- SIMPLE = 7 << 5,
-};
-
-enum SimpleType {
- BOOLEAN,
- NULL_T, // Only two supported, as yet.
-};
-
-enum SpecialAddlInfoValues : uint8_t {
- FALSE = 20,
- TRUE = 21,
- NULL_V = 22,
- ONE_BYTE_LENGTH = 24,
- TWO_BYTE_LENGTH = 25,
- FOUR_BYTE_LENGTH = 26,
- EIGHT_BYTE_LENGTH = 27,
-};
-
-class Item;
-class Uint;
-class Nint;
-class Int;
-class Tstr;
-class Bstr;
-class Simple;
-class Bool;
-class Array;
-class Map;
-class Null;
-class Semantic;
-
-/**
- * Returns the size of a CBOR header that contains the additional info value addlInfo.
- */
-size_t headerSize(uint64_t addlInfo);
-
-/**
- * Encodes a CBOR header with the specified type and additional info into the range [pos, end).
- * Returns a pointer to one past the last byte written, or nullptr if there isn't sufficient space
- * to write the header.
- */
-uint8_t* encodeHeader(MajorType type, uint64_t addlInfo, uint8_t* pos, const uint8_t* end);
-
-using EncodeCallback = std::function<void(uint8_t)>;
-
-/**
- * Encodes a CBOR header with the specified type and additional info, passing each byte in turn to
- * encodeCallback.
- */
-void encodeHeader(MajorType type, uint64_t addlInfo, EncodeCallback encodeCallback);
-
-/**
- * Encodes a CBOR header with the specified type and additional info, writing each byte to the
- * provided OutputIterator.
- */
-template <typename OutputIterator,
- typename = std::enable_if_t<std::is_base_of_v<
- std::output_iterator_tag,
- typename std::iterator_traits<OutputIterator>::iterator_category>>>
-void encodeHeader(MajorType type, uint64_t addlInfo, OutputIterator iter) {
- return encodeHeader(type, addlInfo, [&](uint8_t v) { *iter++ = v; });
-}
-
-/**
- * Item represents a CBOR-encodeable data item. Item is an abstract interface with a set of virtual
- * methods that allow encoding of the item or conversion to the appropriate derived type.
- */
-class Item {
- public:
- virtual ~Item() {}
-
- /**
- * Returns the CBOR type of the item.
- */
- virtual MajorType type() const = 0;
-
- // These methods safely downcast an Item to the appropriate subclass.
- virtual const Int* asInt() const { return nullptr; }
- virtual const Uint* asUint() const { return nullptr; }
- virtual const Nint* asNint() const { return nullptr; }
- virtual const Tstr* asTstr() const { return nullptr; }
- virtual const Bstr* asBstr() const { return nullptr; }
- virtual const Simple* asSimple() const { return nullptr; }
- virtual const Map* asMap() const { return nullptr; }
- virtual const Array* asArray() const { return nullptr; }
- virtual const Semantic* asSemantic() const { return nullptr; }
-
- /**
- * Returns true if this is a "compound" item, i.e. one that contains one or more other items.
- */
- virtual bool isCompound() const { return false; }
-
- bool operator==(const Item& other) const&;
- bool operator!=(const Item& other) const& { return !(*this == other); }
-
- /**
- * Returns the number of bytes required to encode this Item into CBOR. Note that if this is a
- * complex Item, calling this method will require walking the whole tree.
- */
- virtual size_t encodedSize() const = 0;
-
- /**
- * Encodes the Item into buffer referenced by range [*pos, end). Returns a pointer to one past
- * the last position written. Returns nullptr if there isn't enough space to encode.
- */
- virtual uint8_t* encode(uint8_t* pos, const uint8_t* end) const = 0;
-
- /**
- * Encodes the Item by passing each encoded byte to encodeCallback.
- */
- virtual void encode(EncodeCallback encodeCallback) const = 0;
-
- /**
- * Clones the Item
- */
- virtual std::unique_ptr<Item> clone() const = 0;
-
- /**
- * Encodes the Item into the provided OutputIterator.
- */
- template <typename OutputIterator,
- typename = typename std::iterator_traits<OutputIterator>::iterator_category>
- void encode(OutputIterator i) const {
- return encode([&](uint8_t v) { *i++ = v; });
- }
-
- /**
- * Encodes the Item into a new std::vector<uint8_t>.
- */
- std::vector<uint8_t> encode() const {
- std::vector<uint8_t> retval;
- retval.reserve(encodedSize());
- encode(std::back_inserter(retval));
- return retval;
- }
-
- /**
- * Encodes the Item into a new std::string.
- */
- std::string toString() const {
- std::string retval;
- retval.reserve(encodedSize());
- encode([&](uint8_t v) { retval.push_back(v); });
- return retval;
- }
-
- /**
- * Encodes only the header of the Item.
- */
- inline uint8_t* encodeHeader(uint64_t addlInfo, uint8_t* pos, const uint8_t* end) const {
- return ::cppbor::encodeHeader(type(), addlInfo, pos, end);
- }
-
- /**
- * Encodes only the header of the Item.
- */
- inline void encodeHeader(uint64_t addlInfo, EncodeCallback encodeCallback) const {
- ::cppbor::encodeHeader(type(), addlInfo, encodeCallback);
- }
-};
-
-/**
- * Int is an abstraction that allows Uint and Nint objects to be manipulated without caring about
- * the sign.
- */
-class Int : public Item {
- public:
- bool operator==(const Int& other) const& { return value() == other.value(); }
-
- virtual int64_t value() const = 0;
-
- const Int* asInt() const override { return this; }
-};
-
-/**
- * Uint is a concrete Item that implements CBOR major type 0.
- */
-class Uint : public Int {
- public:
- static constexpr MajorType kMajorType = UINT;
-
- explicit Uint(uint64_t v) : mValue(v) {}
-
- bool operator==(const Uint& other) const& { return mValue == other.mValue; }
-
- MajorType type() const override { return kMajorType; }
- const Uint* asUint() const override { return this; }
-
- size_t encodedSize() const override { return headerSize(mValue); }
-
- int64_t value() const override { return mValue; }
- uint64_t unsignedValue() const { return mValue; }
-
- using Item::encode;
- uint8_t* encode(uint8_t* pos, const uint8_t* end) const override {
- return encodeHeader(mValue, pos, end);
- }
- void encode(EncodeCallback encodeCallback) const override {
- encodeHeader(mValue, encodeCallback);
- }
-
- virtual std::unique_ptr<Item> clone() const override { return std::make_unique<Uint>(mValue); }
-
- private:
- uint64_t mValue;
-};
-
-/**
- * Nint is a concrete Item that implements CBOR major type 1.
-
- * Note that it is incapable of expressing the full range of major type 1 values, becaue it can only
- * express values that fall into the range [std::numeric_limits<int64_t>::min(), -1]. It cannot
- * express values in the range [std::numeric_limits<int64_t>::min() - 1,
- * -std::numeric_limits<uint64_t>::max()].
- */
-class Nint : public Int {
- public:
- static constexpr MajorType kMajorType = NINT;
-
- explicit Nint(int64_t v);
-
- bool operator==(const Nint& other) const& { return mValue == other.mValue; }
-
- MajorType type() const override { return kMajorType; }
- const Nint* asNint() const override { return this; }
- size_t encodedSize() const override { return headerSize(addlInfo()); }
-
- int64_t value() const override { return mValue; }
-
- using Item::encode;
- uint8_t* encode(uint8_t* pos, const uint8_t* end) const override {
- return encodeHeader(addlInfo(), pos, end);
- }
- void encode(EncodeCallback encodeCallback) const override {
- encodeHeader(addlInfo(), encodeCallback);
- }
-
- virtual std::unique_ptr<Item> clone() const override { return std::make_unique<Nint>(mValue); }
-
- private:
- uint64_t addlInfo() const { return -1LL - mValue; }
-
- int64_t mValue;
-};
-
-/**
- * Bstr is a concrete Item that implements major type 2.
- */
-class Bstr : public Item {
- public:
- static constexpr MajorType kMajorType = BSTR;
-
- // Construct from a vector
- explicit Bstr(std::vector<uint8_t> v) : mValue(std::move(v)) {}
-
- // Construct from a string
- explicit Bstr(const std::string& v)
- : mValue(reinterpret_cast<const uint8_t*>(v.data()),
- reinterpret_cast<const uint8_t*>(v.data()) + v.size()) {}
-
- // Construct from a pointer/size pair
- explicit Bstr(const std::pair<const uint8_t*, size_t>& buf)
- : mValue(buf.first, buf.first + buf.second) {}
-
- // Construct from a pair of iterators
- template <typename I1, typename I2,
- typename = typename std::iterator_traits<I1>::iterator_category,
- typename = typename std::iterator_traits<I2>::iterator_category>
- explicit Bstr(const std::pair<I1, I2>& pair) : mValue(pair.first, pair.second) {}
-
- // Construct from an iterator range.
- template <typename I1, typename I2,
- typename = typename std::iterator_traits<I1>::iterator_category,
- typename = typename std::iterator_traits<I2>::iterator_category>
- Bstr(I1 begin, I2 end) : mValue(begin, end) {}
-
- bool operator==(const Bstr& other) const& { return mValue == other.mValue; }
-
- MajorType type() const override { return kMajorType; }
- const Bstr* asBstr() const override { return this; }
- size_t encodedSize() const override { return headerSize(mValue.size()) + mValue.size(); }
- using Item::encode;
- uint8_t* encode(uint8_t* pos, const uint8_t* end) const override;
- void encode(EncodeCallback encodeCallback) const override {
- encodeHeader(mValue.size(), encodeCallback);
- encodeValue(encodeCallback);
- }
-
- const std::vector<uint8_t>& value() const { return mValue; }
-
- virtual std::unique_ptr<Item> clone() const override { return std::make_unique<Bstr>(mValue); }
-
- private:
- void encodeValue(EncodeCallback encodeCallback) const;
-
- std::vector<uint8_t> mValue;
-};
-
-/**
- * Bstr is a concrete Item that implements major type 3.
- */
-class Tstr : public Item {
- public:
- static constexpr MajorType kMajorType = TSTR;
-
- // Construct from a string
- explicit Tstr(std::string v) : mValue(std::move(v)) {}
-
- // Construct from a string_view
- explicit Tstr(const std::string_view& v) : mValue(v) {}
-
- // Construct from a C string
- explicit Tstr(const char* v) : mValue(std::string(v)) {}
-
- // Construct from a pair of iterators
- template <typename I1, typename I2,
- typename = typename std::iterator_traits<I1>::iterator_category,
- typename = typename std::iterator_traits<I2>::iterator_category>
- explicit Tstr(const std::pair<I1, I2>& pair) : mValue(pair.first, pair.second) {}
-
- // Construct from an iterator range
- template <typename I1, typename I2,
- typename = typename std::iterator_traits<I1>::iterator_category,
- typename = typename std::iterator_traits<I2>::iterator_category>
- Tstr(I1 begin, I2 end) : mValue(begin, end) {}
-
- bool operator==(const Tstr& other) const& { return mValue == other.mValue; }
-
- MajorType type() const override { return kMajorType; }
- const Tstr* asTstr() const override { return this; }
- size_t encodedSize() const override { return headerSize(mValue.size()) + mValue.size(); }
- using Item::encode;
- uint8_t* encode(uint8_t* pos, const uint8_t* end) const override;
- void encode(EncodeCallback encodeCallback) const override {
- encodeHeader(mValue.size(), encodeCallback);
- encodeValue(encodeCallback);
- }
-
- const std::string& value() const { return mValue; }
-
- virtual std::unique_ptr<Item> clone() const override { return std::make_unique<Tstr>(mValue); }
-
- private:
- void encodeValue(EncodeCallback encodeCallback) const;
-
- std::string mValue;
-};
-
-/**
- * CompoundItem is an abstract Item that provides common functionality for Items that contain other
- * items, i.e. Arrays (CBOR type 4) and Maps (CBOR type 5).
- */
-class CompoundItem : public Item {
- public:
- bool operator==(const CompoundItem& other) const&;
-
- virtual size_t size() const { return mEntries.size(); }
-
- bool isCompound() const override { return true; }
-
- size_t encodedSize() const override {
- return std::accumulate(mEntries.begin(), mEntries.end(), headerSize(size()),
- [](size_t sum, auto& entry) { return sum + entry->encodedSize(); });
- }
-
- using Item::encode; // Make base versions visible.
- uint8_t* encode(uint8_t* pos, const uint8_t* end) const override;
- void encode(EncodeCallback encodeCallback) const override;
-
- virtual uint64_t addlInfo() const = 0;
-
- protected:
- std::vector<std::unique_ptr<Item>> mEntries;
-};
-
-/*
- * Array is a concrete Item that implements CBOR major type 4.
- *
- * Note that Arrays are not copyable. This is because copying them is expensive and making them
- * move-only ensures that they're never copied accidentally. If you actually want to copy an Array,
- * use the clone() method.
- */
-class Array : public CompoundItem {
- public:
- static constexpr MajorType kMajorType = ARRAY;
-
- Array() = default;
- Array(const Array& other) = delete;
- Array(Array&&) = default;
- Array& operator=(const Array&) = delete;
- Array& operator=(Array&&) = default;
-
- /**
- * Construct an Array from a variable number of arguments of different types. See
- * details::makeItem below for details on what types may be provided. In general, this accepts
- * all of the types you'd expect and doest the things you'd expect (integral values are addes as
- * Uint or Nint, std::string and char* are added as Tstr, bools are added as Bool, etc.).
- */
- template <typename... Args, typename Enable>
- Array(Args&&... args);
-
- /**
- * Append a single element to the Array, of any compatible type.
- */
- template <typename T>
- Array& add(T&& v) &;
- template <typename T>
- Array&& add(T&& v) &&;
-
- const std::unique_ptr<Item>& operator[](size_t index) const { return mEntries[index]; }
- std::unique_ptr<Item>& operator[](size_t index) { return mEntries[index]; }
-
- MajorType type() const override { return kMajorType; }
- const Array* asArray() const override { return this; }
-
- virtual std::unique_ptr<Item> clone() const override;
-
- uint64_t addlInfo() const override { return size(); }
-};
-
-/*
- * Map is a concrete Item that implements CBOR major type 5.
- *
- * Note that Maps are not copyable. This is because copying them is expensive and making them
- * move-only ensures that they're never copied accidentally. If you actually want to copy a
- * Map, use the clone() method.
- */
-class Map : public CompoundItem {
- public:
- static constexpr MajorType kMajorType = MAP;
-
- Map() = default;
- Map(const Map& other) = delete;
- Map(Map&&) = default;
- Map& operator=(const Map& other) = delete;
- Map& operator=(Map&&) = default;
-
- /**
- * Construct a Map from a variable number of arguments of different types. An even number of
- * arguments must be provided (this is verified statically). See details::makeItem below for
- * details on what types may be provided. In general, this accepts all of the types you'd
- * expect and doest the things you'd expect (integral values are addes as Uint or Nint,
- * std::string and char* are added as Tstr, bools are added as Bool, etc.).
- */
- template <typename... Args, typename Enable>
- Map(Args&&... args);
-
- /**
- * Append a key/value pair to the Map, of any compatible types.
- */
- template <typename Key, typename Value>
- Map& add(Key&& key, Value&& value) &;
- template <typename Key, typename Value>
- Map&& add(Key&& key, Value&& value) &&;
-
- size_t size() const override {
- assertInvariant();
- return mEntries.size() / 2;
- }
-
- template <typename Key, typename Enable>
- std::pair<std::unique_ptr<Item>&, bool> get(Key key);
-
- std::pair<const std::unique_ptr<Item>&, const std::unique_ptr<Item>&> operator[](
- size_t index) const {
- assertInvariant();
- return {mEntries[index * 2], mEntries[index * 2 + 1]};
- }
-
- std::pair<std::unique_ptr<Item>&, std::unique_ptr<Item>&> operator[](size_t index) {
- assertInvariant();
- return {mEntries[index * 2], mEntries[index * 2 + 1]};
- }
-
- MajorType type() const override { return kMajorType; }
- const Map* asMap() const override { return this; }
-
- virtual std::unique_ptr<Item> clone() const override;
-
- uint64_t addlInfo() const override { return size(); }
-
- private:
- void assertInvariant() const;
-};
-
-class Semantic : public CompoundItem {
- public:
- static constexpr MajorType kMajorType = SEMANTIC;
-
- template <typename T>
- explicit Semantic(uint64_t value, T&& child);
-
- Semantic(const Semantic& other) = delete;
- Semantic(Semantic&&) = default;
- Semantic& operator=(const Semantic& other) = delete;
- Semantic& operator=(Semantic&&) = default;
-
- size_t size() const override {
- assertInvariant();
- return 1;
- }
-
- size_t encodedSize() const override {
- return std::accumulate(mEntries.begin(), mEntries.end(), headerSize(mValue),
- [](size_t sum, auto& entry) { return sum + entry->encodedSize(); });
- }
-
- MajorType type() const override { return kMajorType; }
- const Semantic* asSemantic() const override { return this; }
-
- const std::unique_ptr<Item>& child() const {
- assertInvariant();
- return mEntries[0];
- }
-
- std::unique_ptr<Item>& child() {
- assertInvariant();
- return mEntries[0];
- }
-
- uint64_t value() const { return mValue; }
-
- uint64_t addlInfo() const override { return value(); }
-
- virtual std::unique_ptr<Item> clone() const override {
- assertInvariant();
- return std::make_unique<Semantic>(mValue, mEntries[0]->clone());
- }
-
- protected:
- Semantic() = default;
- Semantic(uint64_t value) : mValue(value) {}
- uint64_t mValue;
-
- private:
- void assertInvariant() const;
-};
-
-/**
- * Simple is abstract Item that implements CBOR major type 7. It is intended to be subclassed to
- * create concrete Simple types. At present only Bool is provided.
- */
-class Simple : public Item {
- public:
- static constexpr MajorType kMajorType = SIMPLE;
-
- bool operator==(const Simple& other) const&;
-
- virtual SimpleType simpleType() const = 0;
- MajorType type() const override { return kMajorType; }
-
- const Simple* asSimple() const override { return this; }
-
- virtual const Bool* asBool() const { return nullptr; };
- virtual const Null* asNull() const { return nullptr; };
-};
-
-/**
- * Bool is a concrete type that implements CBOR major type 7, with additional item values for TRUE
- * and FALSE.
- */
-class Bool : public Simple {
- public:
- static constexpr SimpleType kSimpleType = BOOLEAN;
-
- explicit Bool(bool v) : mValue(v) {}
-
- bool operator==(const Bool& other) const& { return mValue == other.mValue; }
-
- SimpleType simpleType() const override { return kSimpleType; }
- const Bool* asBool() const override { return this; }
-
- size_t encodedSize() const override { return 1; }
-
- using Item::encode;
- uint8_t* encode(uint8_t* pos, const uint8_t* end) const override {
- return encodeHeader(mValue ? TRUE : FALSE, pos, end);
- }
- void encode(EncodeCallback encodeCallback) const override {
- encodeHeader(mValue ? TRUE : FALSE, encodeCallback);
- }
-
- bool value() const { return mValue; }
-
- virtual std::unique_ptr<Item> clone() const override { return std::make_unique<Bool>(mValue); }
-
- private:
- bool mValue;
-};
-
-/**
- * Null is a concrete type that implements CBOR major type 7, with additional item value for NULL
- */
-class Null : public Simple {
- public:
- static constexpr SimpleType kSimpleType = NULL_T;
-
- explicit Null() {}
-
- SimpleType simpleType() const override { return kSimpleType; }
- const Null* asNull() const override { return this; }
-
- size_t encodedSize() const override { return 1; }
-
- using Item::encode;
- uint8_t* encode(uint8_t* pos, const uint8_t* end) const override {
- return encodeHeader(NULL_V, pos, end);
- }
- void encode(EncodeCallback encodeCallback) const override {
- encodeHeader(NULL_V, encodeCallback);
- }
-
- virtual std::unique_ptr<Item> clone() const override { return std::make_unique<Null>(); }
-};
-
-template <typename T>
-std::unique_ptr<T> downcastItem(std::unique_ptr<Item>&& v) {
- static_assert(std::is_base_of_v<Item, T> && !std::is_abstract_v<T>,
- "returned type is not an Item or is an abstract class");
- if (v && T::kMajorType == v->type()) {
- if constexpr (std::is_base_of_v<Simple, T>) {
- if (T::kSimpleType != v->asSimple()->simpleType()) {
- return nullptr;
- }
- }
- return std::unique_ptr<T>(static_cast<T*>(v.release()));
- } else {
- return nullptr;
- }
-}
-
-/**
- * Details. Mostly you shouldn't have to look below, except perhaps at the docstring for makeItem.
- */
-namespace details {
-
-template <typename T, typename V, typename Enable = void>
-struct is_iterator_pair_over : public std::false_type {};
-
-template <typename I1, typename I2, typename V>
-struct is_iterator_pair_over<
- std::pair<I1, I2>, V,
- typename std::enable_if_t<std::is_same_v<V, typename std::iterator_traits<I1>::value_type>>>
- : public std::true_type {};
-
-template <typename T, typename V, typename Enable = void>
-struct is_unique_ptr_of_subclass_of_v : public std::false_type {};
-
-template <typename T, typename P>
-struct is_unique_ptr_of_subclass_of_v<T, std::unique_ptr<P>,
- typename std::enable_if_t<std::is_base_of_v<T, P>>>
- : public std::true_type {};
-
-/* check if type is one of std::string (1), std::string_view (2), null-terminated char* (3) or pair
- * of iterators (4)*/
-template <typename T, typename Enable = void>
-struct is_text_type_v : public std::false_type {};
-
-template <typename T>
-struct is_text_type_v<
- T, typename std::enable_if_t<
- /* case 1 */ //
- std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>, std::string>
- /* case 2 */ //
- || std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>, std::string_view>
- /* case 3 */ //
- || std::is_same_v<std::remove_cv_t<std::decay_t<T>>, char*> //
- || std::is_same_v<std::remove_cv_t<std::decay_t<T>>, const char*>
- /* case 4 */
- || details::is_iterator_pair_over<T, char>::value>> : public std::true_type {};
-
-/**
- * Construct a unique_ptr<Item> from many argument types. Accepts:
- *
- * (a) booleans;
- * (b) integers, all sizes and signs;
- * (c) text strings, as defined by is_text_type_v above;
- * (d) byte strings, as std::vector<uint8_t>(d1), pair of iterators (d2) or pair<uint8_t*, size_T>
- * (d3); and
- * (e) Item subclass instances, including Array and Map. Items may be provided by naked pointer
- * (e1), unique_ptr (e2), reference (e3) or value (e3). If provided by reference or value, will
- * be moved if possible. If provided by pointer, ownership is taken.
- * (f) null pointer;
- */
-template <typename T>
-std::unique_ptr<Item> makeItem(T v) {
- Item* p = nullptr;
- if constexpr (/* case a */ std::is_same_v<T, bool>) {
- p = new Bool(v);
- } else if constexpr (/* case b */ std::is_integral_v<T>) { // b
- if (v < 0) {
- p = new Nint(v);
- } else {
- p = new Uint(static_cast<uint64_t>(v));
- }
- } else if constexpr (/* case c */ //
- details::is_text_type_v<T>::value) {
- p = new Tstr(v);
- } else if constexpr (/* case d1 */ //
- std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>,
- std::vector<uint8_t>>
- /* case d2 */ //
- || details::is_iterator_pair_over<T, uint8_t>::value
- /* case d3 */ //
- || std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>,
- std::pair<uint8_t*, size_t>>) {
- p = new Bstr(v);
- } else if constexpr (/* case e1 */ //
- std::is_pointer_v<T> &&
- std::is_base_of_v<Item, std::remove_pointer_t<T>>) {
- p = v;
- } else if constexpr (/* case e2 */ //
- details::is_unique_ptr_of_subclass_of_v<Item, T>::value) {
- p = v.release();
- } else if constexpr (/* case e3 */ //
- std::is_base_of_v<Item, T>) {
- p = new T(std::move(v));
- } else if constexpr (/* case f */ std::is_null_pointer_v<T>) {
- p = new Null();
- } else {
- // It's odd that this can't be static_assert(false), since it shouldn't be evaluated if one
- // of the above ifs matches. But static_assert(false) always triggers.
- static_assert(std::is_same_v<T, bool>, "makeItem called with unsupported type");
- }
- return std::unique_ptr<Item>(p);
-}
-
-} // namespace details
-
-template <typename... Args,
- /* Prevent use as copy ctor */ typename = std::enable_if_t<
- (sizeof...(Args)) != 1 ||
- !(std::is_same_v<Array, std::remove_cv_t<std::remove_reference_t<Args>>> || ...)>>
-Array::Array(Args&&... args) {
- mEntries.reserve(sizeof...(args));
- (mEntries.push_back(details::makeItem(std::forward<Args>(args))), ...);
-}
-
-template <typename T>
-Array& Array::add(T&& v) & {
- mEntries.push_back(details::makeItem(std::forward<T>(v)));
- return *this;
-}
-
-template <typename T>
-Array&& Array::add(T&& v) && {
- mEntries.push_back(details::makeItem(std::forward<T>(v)));
- return std::move(*this);
-}
-
-template <typename... Args,
- /* Prevent use as copy ctor */ typename = std::enable_if_t<(sizeof...(Args)) != 1>>
-Map::Map(Args&&... args) {
- static_assert((sizeof...(Args)) % 2 == 0, "Map must have an even number of entries");
- mEntries.reserve(sizeof...(args));
- (mEntries.push_back(details::makeItem(std::forward<Args>(args))), ...);
-}
-
-template <typename Key, typename Value>
-Map& Map::add(Key&& key, Value&& value) & {
- mEntries.push_back(details::makeItem(std::forward<Key>(key)));
- mEntries.push_back(details::makeItem(std::forward<Value>(value)));
- return *this;
-}
-
-template <typename Key, typename Value>
-Map&& Map::add(Key&& key, Value&& value) && {
- this->add(std::forward<Key>(key), std::forward<Value>(value));
- return std::move(*this);
-}
-
-template <typename Key, typename = std::enable_if_t<std::is_integral_v<Key> ||
- details::is_text_type_v<Key>::value>>
-std::pair<std::unique_ptr<Item>&, bool> Map::get(Key key) {
- assertInvariant();
- auto keyItem = details::makeItem(key);
- for (size_t i = 0; i < mEntries.size(); i += 2) {
- if (*keyItem == *mEntries[i]) {
- return {mEntries[i + 1], true};
- }
- }
- return {keyItem, false};
-}
-
-template <typename T>
-Semantic::Semantic(uint64_t value, T&& child) : mValue(value) {
- mEntries.reserve(1);
- mEntries.push_back(details::makeItem(std::forward<T>(child)));
-}
-
-} // namespace cppbor
diff --git a/identity/support/include/cppbor/cppbor_parse.h b/identity/support/include/cppbor/cppbor_parse.h
deleted file mode 100644
index 66cd5a3..0000000
--- a/identity/support/include/cppbor/cppbor_parse.h
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (c) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "cppbor.h"
-
-namespace cppbor {
-
-using ParseResult = std::tuple<std::unique_ptr<Item> /* result */, const uint8_t* /* newPos */,
- std::string /* errMsg */>;
-
-/**
- * Parse the first CBOR data item (possibly compound) from the range [begin, end).
- *
- * Returns a tuple of Item pointer, buffer pointer and error message. If parsing is successful, the
- * Item pointer is non-null, the buffer pointer points to the first byte after the
- * successfully-parsed item and the error message string is empty. If parsing fails, the Item
- * pointer is null, the buffer pointer points to the first byte that was unparseable (the first byte
- * of a data item header that is malformed in some way, e.g. an invalid value, or a length that is
- * too large for the remining buffer, etc.) and the string contains an error message describing the
- * problem encountered.
- */
-ParseResult parse(const uint8_t* begin, const uint8_t* end);
-
-/**
- * Parse the first CBOR data item (possibly compound) from the byte vector.
- *
- * Returns a tuple of Item pointer, buffer pointer and error message. If parsing is successful, the
- * Item pointer is non-null, the buffer pointer points to the first byte after the
- * successfully-parsed item and the error message string is empty. If parsing fails, the Item
- * pointer is null, the buffer pointer points to the first byte that was unparseable (the first byte
- * of a data item header that is malformed in some way, e.g. an invalid value, or a length that is
- * too large for the remining buffer, etc.) and the string contains an error message describing the
- * problem encountered.
- */
-inline ParseResult parse(const std::vector<uint8_t>& encoding) {
- return parse(encoding.data(), encoding.data() + encoding.size());
-}
-
-/**
- * Parse the first CBOR data item (possibly compound) from the range [begin, begin + size).
- *
- * Returns a tuple of Item pointer, buffer pointer and error message. If parsing is successful, the
- * Item pointer is non-null, the buffer pointer points to the first byte after the
- * successfully-parsed item and the error message string is empty. If parsing fails, the Item
- * pointer is null, the buffer pointer points to the first byte that was unparseable (the first byte
- * of a data item header that is malformed in some way, e.g. an invalid value, or a length that is
- * too large for the remining buffer, etc.) and the string contains an error message describing the
- * problem encountered.
- */
-inline ParseResult parse(const uint8_t* begin, size_t size) {
- return parse(begin, begin + size);
-}
-
-class ParseClient;
-
-/**
- * Parse the CBOR data in the range [begin, end) in streaming fashion, calling methods on the
- * provided ParseClient when elements are found.
- */
-void parse(const uint8_t* begin, const uint8_t* end, ParseClient* parseClient);
-
-/**
- * Parse the CBOR data in the vector in streaming fashion, calling methods on the
- * provided ParseClient when elements are found.
- */
-inline void parse(const std::vector<uint8_t>& encoding, ParseClient* parseClient) {
- return parse(encoding.data(), encoding.data() + encoding.size(), parseClient);
-}
-
-/**
- * A pure interface that callers of the streaming parse functions must implement.
- */
-class ParseClient {
- public:
- virtual ~ParseClient() {}
-
- /**
- * Called when an item is found. The Item pointer points to the found item; use type() and
- * the appropriate as*() method to examine the value. hdrBegin points to the first byte of the
- * header, valueBegin points to the first byte of the value and end points one past the end of
- * the item. In the case of header-only items, such as integers, and compound items (ARRAY,
- * MAP or SEMANTIC) whose end has not yet been found, valueBegin and end are equal and point to
- * the byte past the header.
- *
- * Note that for compound types (ARRAY, MAP, and SEMANTIC), the Item will have no content. For
- * Map and Array items, the size() method will return a correct value, but the index operators
- * are unsafe, and the object cannot be safely compared with another Array/Map.
- *
- * The method returns a ParseClient*. In most cases "return this;" will be the right answer,
- * but a different ParseClient may be returned, which the parser will begin using. If the method
- * returns nullptr, parsing will be aborted immediately.
- */
- virtual ParseClient* item(std::unique_ptr<Item>& item, const uint8_t* hdrBegin,
- const uint8_t* valueBegin, const uint8_t* end) = 0;
-
- /**
- * Called when the end of a compound item (MAP or ARRAY) is found. The item argument will be
- * the same one passed to the item() call -- and may be empty if item() moved its value out.
- * hdrBegin, valueBegin and end point to the beginning of the item header, the beginning of the
- * first contained value, and one past the end of the last contained value, respectively.
- *
- * Note that the Item will have no content.
- *
- * As with item(), itemEnd() can change the ParseClient by returning a different one, or end the
- * parsing by returning nullptr;
- */
- virtual ParseClient* itemEnd(std::unique_ptr<Item>& item, const uint8_t* hdrBegin,
- const uint8_t* valueBegin, const uint8_t* end) = 0;
-
- /**
- * Called when parsing encounters an error. position is set to the first unparsed byte (one
- * past the last successfully-parsed byte) and errorMessage contains an message explaining what
- * sort of error occurred.
- */
- virtual void error(const uint8_t* position, const std::string& errorMessage) = 0;
-};
-
-} // namespace cppbor
diff --git a/identity/support/src/cppbor.cpp b/identity/support/src/cppbor.cpp
deleted file mode 100644
index d289985..0000000
--- a/identity/support/src/cppbor.cpp
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * Copyright (c) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "cppbor.h"
-#include "cppbor_parse.h"
-
-#define LOG_TAG "CppBor"
-#include <android-base/logging.h>
-
-namespace cppbor {
-
-namespace {
-
-template <typename T, typename Iterator, typename = std::enable_if<std::is_unsigned<T>::value>>
-Iterator writeBigEndian(T value, Iterator pos) {
- for (unsigned i = 0; i < sizeof(value); ++i) {
- *pos++ = static_cast<uint8_t>(value >> (8 * (sizeof(value) - 1)));
- value = static_cast<T>(value << 8);
- }
- return pos;
-}
-
-template <typename T, typename = std::enable_if<std::is_unsigned<T>::value>>
-void writeBigEndian(T value, std::function<void(uint8_t)>& cb) {
- for (unsigned i = 0; i < sizeof(value); ++i) {
- cb(static_cast<uint8_t>(value >> (8 * (sizeof(value) - 1))));
- value = static_cast<T>(value << 8);
- }
-}
-
-} // namespace
-
-size_t headerSize(uint64_t addlInfo) {
- if (addlInfo < ONE_BYTE_LENGTH) return 1;
- if (addlInfo <= std::numeric_limits<uint8_t>::max()) return 2;
- if (addlInfo <= std::numeric_limits<uint16_t>::max()) return 3;
- if (addlInfo <= std::numeric_limits<uint32_t>::max()) return 5;
- return 9;
-}
-
-uint8_t* encodeHeader(MajorType type, uint64_t addlInfo, uint8_t* pos, const uint8_t* end) {
- size_t sz = headerSize(addlInfo);
- if (end - pos < static_cast<ssize_t>(sz)) return nullptr;
- switch (sz) {
- case 1:
- *pos++ = type | static_cast<uint8_t>(addlInfo);
- return pos;
- case 2:
- *pos++ = type | ONE_BYTE_LENGTH;
- *pos++ = static_cast<uint8_t>(addlInfo);
- return pos;
- case 3:
- *pos++ = type | TWO_BYTE_LENGTH;
- return writeBigEndian(static_cast<uint16_t>(addlInfo), pos);
- case 5:
- *pos++ = type | FOUR_BYTE_LENGTH;
- return writeBigEndian(static_cast<uint32_t>(addlInfo), pos);
- case 9:
- *pos++ = type | EIGHT_BYTE_LENGTH;
- return writeBigEndian(addlInfo, pos);
- default:
- CHECK(false); // Impossible to get here.
- return nullptr;
- }
-}
-
-void encodeHeader(MajorType type, uint64_t addlInfo, EncodeCallback encodeCallback) {
- size_t sz = headerSize(addlInfo);
- switch (sz) {
- case 1:
- encodeCallback(type | static_cast<uint8_t>(addlInfo));
- break;
- case 2:
- encodeCallback(type | ONE_BYTE_LENGTH);
- encodeCallback(static_cast<uint8_t>(addlInfo));
- break;
- case 3:
- encodeCallback(type | TWO_BYTE_LENGTH);
- writeBigEndian(static_cast<uint16_t>(addlInfo), encodeCallback);
- break;
- case 5:
- encodeCallback(type | FOUR_BYTE_LENGTH);
- writeBigEndian(static_cast<uint32_t>(addlInfo), encodeCallback);
- break;
- case 9:
- encodeCallback(type | EIGHT_BYTE_LENGTH);
- writeBigEndian(addlInfo, encodeCallback);
- break;
- default:
- CHECK(false); // Impossible to get here.
- }
-}
-
-bool Item::operator==(const Item& other) const& {
- if (type() != other.type()) return false;
- switch (type()) {
- case UINT:
- return *asUint() == *(other.asUint());
- case NINT:
- return *asNint() == *(other.asNint());
- case BSTR:
- return *asBstr() == *(other.asBstr());
- case TSTR:
- return *asTstr() == *(other.asTstr());
- case ARRAY:
- return *asArray() == *(other.asArray());
- case MAP:
- return *asMap() == *(other.asMap());
- case SIMPLE:
- return *asSimple() == *(other.asSimple());
- case SEMANTIC:
- return *asSemantic() == *(other.asSemantic());
- default:
- CHECK(false); // Impossible to get here.
- return false;
- }
-}
-
-Nint::Nint(int64_t v) : mValue(v) {
- CHECK(v < 0) << "Only negative values allowed";
-}
-
-bool Simple::operator==(const Simple& other) const& {
- if (simpleType() != other.simpleType()) return false;
-
- switch (simpleType()) {
- case BOOLEAN:
- return *asBool() == *(other.asBool());
- case NULL_T:
- return true;
- default:
- CHECK(false); // Impossible to get here.
- return false;
- }
-}
-
-uint8_t* Bstr::encode(uint8_t* pos, const uint8_t* end) const {
- pos = encodeHeader(mValue.size(), pos, end);
- if (!pos || end - pos < static_cast<ptrdiff_t>(mValue.size())) return nullptr;
- return std::copy(mValue.begin(), mValue.end(), pos);
-}
-
-void Bstr::encodeValue(EncodeCallback encodeCallback) const {
- for (auto c : mValue) {
- encodeCallback(c);
- }
-}
-
-uint8_t* Tstr::encode(uint8_t* pos, const uint8_t* end) const {
- pos = encodeHeader(mValue.size(), pos, end);
- if (!pos || end - pos < static_cast<ptrdiff_t>(mValue.size())) return nullptr;
- return std::copy(mValue.begin(), mValue.end(), pos);
-}
-
-void Tstr::encodeValue(EncodeCallback encodeCallback) const {
- for (auto c : mValue) {
- encodeCallback(static_cast<uint8_t>(c));
- }
-}
-
-bool CompoundItem::operator==(const CompoundItem& other) const& {
- return type() == other.type() //
- && addlInfo() == other.addlInfo() //
- // Can't use vector::operator== because the contents are pointers. std::equal lets us
- // provide a predicate that does the dereferencing.
- && std::equal(mEntries.begin(), mEntries.end(), other.mEntries.begin(),
- [](auto& a, auto& b) -> bool { return *a == *b; });
-}
-
-uint8_t* CompoundItem::encode(uint8_t* pos, const uint8_t* end) const {
- pos = encodeHeader(addlInfo(), pos, end);
- if (!pos) return nullptr;
- for (auto& entry : mEntries) {
- pos = entry->encode(pos, end);
- if (!pos) return nullptr;
- }
- return pos;
-}
-
-void CompoundItem::encode(EncodeCallback encodeCallback) const {
- encodeHeader(addlInfo(), encodeCallback);
- for (auto& entry : mEntries) {
- entry->encode(encodeCallback);
- }
-}
-
-void Map::assertInvariant() const {
- CHECK(mEntries.size() % 2 == 0);
-}
-
-std::unique_ptr<Item> Map::clone() const {
- assertInvariant();
- auto res = std::make_unique<Map>();
- for (size_t i = 0; i < mEntries.size(); i += 2) {
- res->add(mEntries[i]->clone(), mEntries[i + 1]->clone());
- }
- return res;
-}
-
-std::unique_ptr<Item> Array::clone() const {
- auto res = std::make_unique<Array>();
- for (size_t i = 0; i < mEntries.size(); i++) {
- res->add(mEntries[i]->clone());
- }
- return res;
-}
-
-void Semantic::assertInvariant() const {
- CHECK(mEntries.size() == 1);
-}
-
-} // namespace cppbor
diff --git a/identity/support/src/cppbor_parse.cpp b/identity/support/src/cppbor_parse.cpp
deleted file mode 100644
index c9ebb8a..0000000
--- a/identity/support/src/cppbor_parse.cpp
+++ /dev/null
@@ -1,351 +0,0 @@
-/*
- * Copyright (c) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "cppbor_parse.h"
-
-#include <sstream>
-#include <stack>
-
-#define LOG_TAG "CppBor"
-#include <android-base/logging.h>
-
-namespace cppbor {
-
-namespace {
-
-std::string insufficientLengthString(size_t bytesNeeded, size_t bytesAvail,
- const std::string& type) {
- std::stringstream errStream;
- errStream << "Need " << bytesNeeded << " byte(s) for " << type << ", have " << bytesAvail
- << ".";
- return errStream.str();
-}
-
-template <typename T, typename = std::enable_if_t<std::is_unsigned_v<T>>>
-std::tuple<bool, uint64_t, const uint8_t*> parseLength(const uint8_t* pos, const uint8_t* end,
- ParseClient* parseClient) {
- if (pos + sizeof(T) > end) {
- parseClient->error(pos - 1, insufficientLengthString(sizeof(T), end - pos, "length field"));
- return {false, 0, pos};
- }
-
- const uint8_t* intEnd = pos + sizeof(T);
- T result = 0;
- do {
- result = static_cast<T>((result << 8) | *pos++);
- } while (pos < intEnd);
- return {true, result, pos};
-}
-
-std::tuple<const uint8_t*, ParseClient*> parseRecursively(const uint8_t* begin, const uint8_t* end,
- ParseClient* parseClient);
-
-std::tuple<const uint8_t*, ParseClient*> handleUint(uint64_t value, const uint8_t* hdrBegin,
- const uint8_t* hdrEnd,
- ParseClient* parseClient) {
- std::unique_ptr<Item> item = std::make_unique<Uint>(value);
- return {hdrEnd,
- parseClient->item(item, hdrBegin, hdrEnd /* valueBegin */, hdrEnd /* itemEnd */)};
-}
-
-std::tuple<const uint8_t*, ParseClient*> handleNint(uint64_t value, const uint8_t* hdrBegin,
- const uint8_t* hdrEnd,
- ParseClient* parseClient) {
- if (value > std::numeric_limits<int64_t>::max()) {
- parseClient->error(hdrBegin, "NINT values that don't fit in int64_t are not supported.");
- return {hdrBegin, nullptr /* end parsing */};
- }
- std::unique_ptr<Item> item = std::make_unique<Nint>(-1 - static_cast<uint64_t>(value));
- return {hdrEnd,
- parseClient->item(item, hdrBegin, hdrEnd /* valueBegin */, hdrEnd /* itemEnd */)};
-}
-
-std::tuple<const uint8_t*, ParseClient*> handleBool(uint64_t value, const uint8_t* hdrBegin,
- const uint8_t* hdrEnd,
- ParseClient* parseClient) {
- std::unique_ptr<Item> item = std::make_unique<Bool>(value == TRUE);
- return {hdrEnd,
- parseClient->item(item, hdrBegin, hdrEnd /* valueBegin */, hdrEnd /* itemEnd */)};
-}
-
-std::tuple<const uint8_t*, ParseClient*> handleNull(const uint8_t* hdrBegin, const uint8_t* hdrEnd,
- ParseClient* parseClient) {
- std::unique_ptr<Item> item = std::make_unique<Null>();
- return {hdrEnd,
- parseClient->item(item, hdrBegin, hdrEnd /* valueBegin */, hdrEnd /* itemEnd */)};
-}
-
-template <typename T>
-std::tuple<const uint8_t*, ParseClient*> handleString(uint64_t length, const uint8_t* hdrBegin,
- const uint8_t* valueBegin, const uint8_t* end,
- const std::string& errLabel,
- ParseClient* parseClient) {
- if (end - valueBegin < static_cast<ssize_t>(length)) {
- parseClient->error(hdrBegin, insufficientLengthString(length, end - valueBegin, errLabel));
- return {hdrBegin, nullptr /* end parsing */};
- }
-
- std::unique_ptr<Item> item = std::make_unique<T>(valueBegin, valueBegin + length);
- return {valueBegin + length,
- parseClient->item(item, hdrBegin, valueBegin, valueBegin + length)};
-}
-
-class IncompleteItem {
- public:
- virtual ~IncompleteItem() {}
- virtual void add(std::unique_ptr<Item> item) = 0;
-};
-
-class IncompleteArray : public Array, public IncompleteItem {
- public:
- IncompleteArray(size_t size) : mSize(size) {}
-
- // We return the "complete" size, rather than the actual size.
- size_t size() const override { return mSize; }
-
- void add(std::unique_ptr<Item> item) override {
- mEntries.reserve(mSize);
- mEntries.push_back(std::move(item));
- }
-
- private:
- size_t mSize;
-};
-
-class IncompleteMap : public Map, public IncompleteItem {
- public:
- IncompleteMap(size_t size) : mSize(size) {}
-
- // We return the "complete" size, rather than the actual size.
- size_t size() const override { return mSize; }
-
- void add(std::unique_ptr<Item> item) override {
- mEntries.reserve(mSize * 2);
- mEntries.push_back(std::move(item));
- }
-
- private:
- size_t mSize;
-};
-
-class IncompleteSemantic : public Semantic, public IncompleteItem {
- public:
- IncompleteSemantic(uint64_t value) : Semantic(value) {}
-
- // We return the "complete" size, rather than the actual size.
- size_t size() const override { return 1; }
-
- void add(std::unique_ptr<Item> item) override {
- mEntries.reserve(1);
- mEntries.push_back(std::move(item));
- }
-};
-
-std::tuple<const uint8_t*, ParseClient*> handleEntries(size_t entryCount, const uint8_t* hdrBegin,
- const uint8_t* pos, const uint8_t* end,
- const std::string& typeName,
- ParseClient* parseClient) {
- while (entryCount > 0) {
- --entryCount;
- if (pos == end) {
- parseClient->error(hdrBegin, "Not enough entries for " + typeName + ".");
- return {hdrBegin, nullptr /* end parsing */};
- }
- std::tie(pos, parseClient) = parseRecursively(pos, end, parseClient);
- if (!parseClient) return {hdrBegin, nullptr};
- }
- return {pos, parseClient};
-}
-
-std::tuple<const uint8_t*, ParseClient*> handleCompound(
- std::unique_ptr<Item> item, uint64_t entryCount, const uint8_t* hdrBegin,
- const uint8_t* valueBegin, const uint8_t* end, const std::string& typeName,
- ParseClient* parseClient) {
- parseClient =
- parseClient->item(item, hdrBegin, valueBegin, valueBegin /* don't know the end yet */);
- if (!parseClient) return {hdrBegin, nullptr};
-
- const uint8_t* pos;
- std::tie(pos, parseClient) =
- handleEntries(entryCount, hdrBegin, valueBegin, end, typeName, parseClient);
- if (!parseClient) return {hdrBegin, nullptr};
-
- return {pos, parseClient->itemEnd(item, hdrBegin, valueBegin, pos)};
-}
-
-std::tuple<const uint8_t*, ParseClient*> parseRecursively(const uint8_t* begin, const uint8_t* end,
- ParseClient* parseClient) {
- const uint8_t* pos = begin;
-
- MajorType type = static_cast<MajorType>(*pos & 0xE0);
- uint8_t tagInt = *pos & 0x1F;
- ++pos;
-
- bool success = true;
- uint64_t addlData;
- if (tagInt < ONE_BYTE_LENGTH || tagInt > EIGHT_BYTE_LENGTH) {
- addlData = tagInt;
- } else {
- switch (tagInt) {
- case ONE_BYTE_LENGTH:
- std::tie(success, addlData, pos) = parseLength<uint8_t>(pos, end, parseClient);
- break;
-
- case TWO_BYTE_LENGTH:
- std::tie(success, addlData, pos) = parseLength<uint16_t>(pos, end, parseClient);
- break;
-
- case FOUR_BYTE_LENGTH:
- std::tie(success, addlData, pos) = parseLength<uint32_t>(pos, end, parseClient);
- break;
-
- case EIGHT_BYTE_LENGTH:
- std::tie(success, addlData, pos) = parseLength<uint64_t>(pos, end, parseClient);
- break;
-
- default:
- CHECK(false); // It's impossible to get here
- break;
- }
- }
-
- if (!success) return {begin, nullptr};
-
- switch (type) {
- case UINT:
- return handleUint(addlData, begin, pos, parseClient);
-
- case NINT:
- return handleNint(addlData, begin, pos, parseClient);
-
- case BSTR:
- return handleString<Bstr>(addlData, begin, pos, end, "byte string", parseClient);
-
- case TSTR:
- return handleString<Tstr>(addlData, begin, pos, end, "text string", parseClient);
-
- case ARRAY:
- return handleCompound(std::make_unique<IncompleteArray>(addlData), addlData, begin, pos,
- end, "array", parseClient);
-
- case MAP:
- return handleCompound(std::make_unique<IncompleteMap>(addlData), addlData * 2, begin,
- pos, end, "map", parseClient);
-
- case SEMANTIC:
- return handleCompound(std::make_unique<IncompleteSemantic>(addlData), 1, begin, pos,
- end, "semantic", parseClient);
-
- case SIMPLE:
- switch (addlData) {
- case TRUE:
- case FALSE:
- return handleBool(addlData, begin, pos, parseClient);
- case NULL_V:
- return handleNull(begin, pos, parseClient);
- }
- }
- CHECK(false); // Impossible to get here.
- return {};
-}
-
-class FullParseClient : public ParseClient {
- public:
- virtual ParseClient* item(std::unique_ptr<Item>& item, const uint8_t*, const uint8_t*,
- const uint8_t* end) override {
- if (mParentStack.empty() && !item->isCompound()) {
- // This is the first and only item.
- mTheItem = std::move(item);
- mPosition = end;
- return nullptr; // We're done.
- }
-
- if (item->isCompound()) {
- // Starting a new compound data item, i.e. a new parent. Save it on the parent stack.
- // It's safe to save a raw pointer because the unique_ptr is guaranteed to stay in
- // existence until the corresponding itemEnd() call.
- assert(dynamic_cast<CompoundItem*>(item.get()));
- mParentStack.push(static_cast<CompoundItem*>(item.get()));
- return this;
- } else {
- appendToLastParent(std::move(item));
- return this;
- }
- }
-
- virtual ParseClient* itemEnd(std::unique_ptr<Item>& item, const uint8_t*, const uint8_t*,
- const uint8_t* end) override {
- CHECK(item->isCompound() && item.get() == mParentStack.top());
- mParentStack.pop();
-
- if (mParentStack.empty()) {
- mTheItem = std::move(item);
- mPosition = end;
- return nullptr; // We're done
- } else {
- appendToLastParent(std::move(item));
- return this;
- }
- }
-
- virtual void error(const uint8_t* position, const std::string& errorMessage) override {
- mPosition = position;
- mErrorMessage = errorMessage;
- }
-
- std::tuple<std::unique_ptr<Item> /* result */, const uint8_t* /* newPos */,
- std::string /* errMsg */>
- parseResult() {
- std::unique_ptr<Item> p = std::move(mTheItem);
- return {std::move(p), mPosition, std::move(mErrorMessage)};
- }
-
- private:
- void appendToLastParent(std::unique_ptr<Item> item) {
- auto parent = mParentStack.top();
- assert(dynamic_cast<IncompleteItem*>(parent));
- if (parent->type() == ARRAY) {
- static_cast<IncompleteArray*>(parent)->add(std::move(item));
- } else if (parent->type() == MAP) {
- static_cast<IncompleteMap*>(parent)->add(std::move(item));
- } else if (parent->type() == SEMANTIC) {
- static_cast<IncompleteSemantic*>(parent)->add(std::move(item));
- } else {
- CHECK(false); // Impossible to get here.
- }
- }
-
- std::unique_ptr<Item> mTheItem;
- std::stack<CompoundItem*> mParentStack;
- const uint8_t* mPosition = nullptr;
- std::string mErrorMessage;
-};
-
-} // anonymous namespace
-
-void parse(const uint8_t* begin, const uint8_t* end, ParseClient* parseClient) {
- parseRecursively(begin, end, parseClient);
-}
-
-std::tuple<std::unique_ptr<Item> /* result */, const uint8_t* /* newPos */,
- std::string /* errMsg */>
-parse(const uint8_t* begin, const uint8_t* end) {
- FullParseClient parseClient;
- parse(begin, end, &parseClient);
- return parseClient.parseResult();
-}
-
-} // namespace cppbor
diff --git a/identity/support/tests/cppbor_test.cpp b/identity/support/tests/cppbor_test.cpp
deleted file mode 100644
index 3eb5598..0000000
--- a/identity/support/tests/cppbor_test.cpp
+++ /dev/null
@@ -1,1013 +0,0 @@
-/*
- * Copyright (c) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <iomanip>
-#include <sstream>
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-#include "cppbor.h"
-#include "cppbor_parse.h"
-
-using namespace cppbor;
-using namespace std;
-
-using ::testing::_;
-using ::testing::AllOf;
-using ::testing::ByRef;
-using ::testing::InSequence;
-using ::testing::IsNull;
-using ::testing::NotNull;
-using ::testing::Return;
-using ::testing::Truly;
-using ::testing::Unused;
-
-string hexDump(const string& str) {
- stringstream s;
- for (auto c : str) {
- s << setfill('0') << setw(2) << hex << (static_cast<unsigned>(c) & 0xff);
- }
- return s.str();
-}
-
-TEST(SimpleValueTest, UnsignedValueSizes) {
- // Check that unsigned integers encode to correct lengths, and that encodedSize() is correct.
- vector<pair<uint64_t /* value */, size_t /* expected encoded size */>> testCases{
- {0, 1},
- {1, 1},
- {23, 1},
- {24, 2},
- {255, 2},
- {256, 3},
- {65535, 3},
- {65536, 5},
- {4294967295, 5},
- {4294967296, 9},
- {std::numeric_limits<uint64_t>::max(), 9},
- };
- for (auto& testCase : testCases) {
- Uint val(testCase.first);
- EXPECT_EQ(testCase.second, val.encodedSize()) << "Wrong size for value " << testCase.first;
- EXPECT_EQ(val.encodedSize(), val.toString().size())
- << "encodedSize and encoding disagree for value " << testCase.first;
- }
-}
-
-TEST(SimpleValueTest, UnsignedValueEncodings) {
- EXPECT_EQ("\x00"s, Uint(0u).toString());
- EXPECT_EQ("\x01"s, Uint(1u).toString());
- EXPECT_EQ("\x0a"s, Uint(10u).toString());
- EXPECT_EQ("\x17"s, Uint(23u).toString());
- EXPECT_EQ("\x18\x18"s, Uint(24u).toString());
- EXPECT_EQ("\x18\x19"s, Uint(25u).toString());
- EXPECT_EQ("\x18\x64"s, Uint(100u).toString());
- EXPECT_EQ("\x19\x03\xe8"s, Uint(1000u).toString());
- EXPECT_EQ("\x1a\x00\x0f\x42\x40"s, Uint(1000000u).toString());
- EXPECT_EQ("\x1b\x00\x00\x00\xe8\xd4\xa5\x10\x00"s, Uint(1000000000000u).toString());
- EXPECT_EQ("\x1B\x7f\xff\xff\xff\xff\xff\xff\xff"s,
- Uint(std::numeric_limits<int64_t>::max()).toString());
-}
-
-TEST(SimpleValueTest, NegativeValueEncodings) {
- EXPECT_EQ("\x20"s, Nint(-1).toString());
- EXPECT_EQ("\x28"s, Nint(-9).toString());
- EXPECT_EQ("\x29"s, Nint(-10).toString());
- EXPECT_EQ("\x36"s, Nint(-23).toString());
- EXPECT_EQ("\x37"s, Nint(-24).toString());
- EXPECT_EQ("\x38\x18"s, Nint(-25).toString());
- EXPECT_EQ("\x38\x62"s, Nint(-99).toString());
- EXPECT_EQ("\x38\x63"s, Nint(-100).toString());
- EXPECT_EQ("\x39\x03\xe6"s, Nint(-999).toString());
- EXPECT_EQ("\x39\x03\xe7"s, Nint(-1000).toString());
- EXPECT_EQ("\x3a\x00\x0f\x42\x3F"s, Nint(-1000000).toString());
- EXPECT_EQ("\x3b\x00\x00\x00\xe8\xd4\xa5\x0f\xff"s, Nint(-1000000000000).toString());
- EXPECT_EQ("\x3B\x7f\xff\xff\xff\xff\xff\xff\xff"s,
- Nint(std::numeric_limits<int64_t>::min()).toString());
-}
-
-TEST(SimpleValueDeathTest, NegativeValueEncodings) {
- EXPECT_DEATH(Nint(0), "");
- EXPECT_DEATH(Nint(1), "");
-}
-
-TEST(SimpleValueTest, BooleanEncodings) {
- EXPECT_EQ("\xf4"s, Bool(false).toString());
- EXPECT_EQ("\xf5"s, Bool(true).toString());
-}
-
-TEST(SimpleValueTest, ByteStringEncodings) {
- EXPECT_EQ("\x40", Bstr("").toString());
- EXPECT_EQ("\x41\x61", Bstr("a").toString());
- EXPECT_EQ("\x41\x41", Bstr("A").toString());
- EXPECT_EQ("\x44\x49\x45\x54\x46", Bstr("IETF").toString());
- EXPECT_EQ("\x42\x22\x5c", Bstr("\"\\").toString());
- EXPECT_EQ("\x42\xc3\xbc", Bstr("\xc3\xbc").toString());
- EXPECT_EQ("\x43\xe6\xb0\xb4", Bstr("\xe6\xb0\xb4").toString());
- EXPECT_EQ("\x44\xf0\x90\x85\x91", Bstr("\xf0\x90\x85\x91").toString());
- EXPECT_EQ("\x44\x01\x02\x03\x04", Bstr("\x01\x02\x03\x04").toString());
- EXPECT_EQ("\x44\x40\x40\x40\x40", Bstr("@@@@").toString());
-}
-
-TEST(SimpleValueTest, TextStringEncodings) {
- EXPECT_EQ("\x60"s, Tstr("").toString());
- EXPECT_EQ("\x61\x61"s, Tstr("a").toString());
- EXPECT_EQ("\x61\x41"s, Tstr("A").toString());
- EXPECT_EQ("\x64\x49\x45\x54\x46"s, Tstr("IETF").toString());
- EXPECT_EQ("\x62\x22\x5c"s, Tstr("\"\\").toString());
- EXPECT_EQ("\x62\xc3\xbc"s, Tstr("\xc3\xbc").toString());
- EXPECT_EQ("\x63\xe6\xb0\xb4"s, Tstr("\xe6\xb0\xb4").toString());
- EXPECT_EQ("\x64\xf0\x90\x85\x91"s, Tstr("\xf0\x90\x85\x91").toString());
- EXPECT_EQ("\x64\x01\x02\x03\x04"s, Tstr("\x01\x02\x03\x04").toString());
-}
-
-TEST(IsIteratorPairOverTest, All) {
- EXPECT_TRUE((
- details::is_iterator_pair_over<pair<string::iterator, string::iterator>, char>::value));
- EXPECT_TRUE((details::is_iterator_pair_over<pair<string::const_iterator, string::iterator>,
- char>::value));
- EXPECT_TRUE((details::is_iterator_pair_over<pair<string::iterator, string::const_iterator>,
- char>::value));
- EXPECT_TRUE((details::is_iterator_pair_over<pair<char*, char*>, char>::value));
- EXPECT_TRUE((details::is_iterator_pair_over<pair<const char*, char*>, char>::value));
- EXPECT_TRUE((details::is_iterator_pair_over<pair<char*, const char*>, char>::value));
- EXPECT_FALSE((details::is_iterator_pair_over<pair<string::iterator, string::iterator>,
- uint8_t>::value));
- EXPECT_FALSE((details::is_iterator_pair_over<pair<char*, char*>, uint8_t>::value));
- EXPECT_TRUE((details::is_iterator_pair_over<
- pair<vector<uint8_t>::iterator, vector<uint8_t>::iterator>, uint8_t>::value));
- EXPECT_TRUE((details::is_iterator_pair_over<
- pair<vector<uint8_t>::const_iterator, vector<uint8_t>::iterator>,
- uint8_t>::value));
- EXPECT_TRUE((details::is_iterator_pair_over<
- pair<vector<uint8_t>::iterator, vector<uint8_t>::const_iterator>,
- uint8_t>::value));
- EXPECT_TRUE((details::is_iterator_pair_over<pair<uint8_t*, uint8_t*>, uint8_t>::value));
- EXPECT_TRUE((details::is_iterator_pair_over<pair<const uint8_t*, uint8_t*>, uint8_t>::value));
- EXPECT_TRUE((details::is_iterator_pair_over<pair<uint8_t*, const uint8_t*>, uint8_t>::value));
- EXPECT_FALSE((details::is_iterator_pair_over<
- pair<vector<uint8_t>::iterator, vector<uint8_t>::iterator>, char>::value));
- EXPECT_FALSE((details::is_iterator_pair_over<pair<uint8_t*, const uint8_t*>, char>::value));
-}
-
-TEST(MakeEntryTest, Boolean) {
- EXPECT_EQ("\xf4"s, details::makeItem(false)->toString());
-}
-
-TEST(MakeEntryTest, Integers) {
- EXPECT_EQ("\x00"s, details::makeItem(static_cast<uint8_t>(0))->toString());
- EXPECT_EQ("\x00"s, details::makeItem(static_cast<uint16_t>(0))->toString());
- EXPECT_EQ("\x00"s, details::makeItem(static_cast<uint32_t>(0))->toString());
- EXPECT_EQ("\x00"s, details::makeItem(static_cast<uint64_t>(0))->toString());
- EXPECT_EQ("\x00"s, details::makeItem(static_cast<int8_t>(0))->toString());
- EXPECT_EQ("\x00"s, details::makeItem(static_cast<int16_t>(0))->toString());
- EXPECT_EQ("\x00"s, details::makeItem(static_cast<int32_t>(0))->toString());
- EXPECT_EQ("\x00"s, details::makeItem(static_cast<int64_t>(0))->toString());
- EXPECT_EQ("\x20"s, details::makeItem(static_cast<int8_t>(-1))->toString());
- EXPECT_EQ("\x20"s, details::makeItem(static_cast<int16_t>(-1))->toString());
- EXPECT_EQ("\x20"s, details::makeItem(static_cast<int32_t>(-1))->toString());
- EXPECT_EQ("\x20"s, details::makeItem(static_cast<int64_t>(-1))->toString());
-
- EXPECT_EQ("\x1b\xff\xff\xff\xff\xff\xff\xff\xff"s,
- details::makeItem(static_cast<uint64_t>(std::numeric_limits<uint64_t>::max()))
- ->toString());
-}
-
-TEST(MakeEntryTest, StdStrings) {
- string s1("hello");
- const string s2("hello");
- EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s, details::makeItem(s1)->toString()); // copy of string
- EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s,
- details::makeItem(s2)->toString()); // copy of const string
- EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s,
- details::makeItem(std::move(s1))->toString()); // move string
- EXPECT_EQ(0U, s1.size()); // Prove string was moved, not copied.
-}
-
-TEST(MakeEntryTest, StdStringViews) {
- string_view s1("hello");
- const string_view s2("hello");
- EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s, details::makeItem(s1)->toString());
- EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s, details::makeItem(s2)->toString());
-}
-
-TEST(MakeEntryTest, CStrings) {
- char s1[] = "hello";
- const char s2[] = "hello";
- const char* s3 = "hello";
- EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s, details::makeItem(s1)->toString());
- EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s, details::makeItem(s2)->toString());
- EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s, details::makeItem(s3)->toString());
-}
-
-TEST(MakeEntryTest, StringIteratorPairs) {
- // Use iterators from string to prove that "real" iterators work
- string s1 = "hello"s;
- pair<string::iterator, string::iterator> p1 = make_pair(s1.begin(), s1.end());
-
- const pair<string::iterator, string::iterator> p2 = p1;
- EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s, details::makeItem(p1)->toString());
- EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s, details::makeItem(p2)->toString());
-
- // Use char*s as iterators
- const char* s2 = "hello";
- pair p3 = make_pair(s2, s2 + 5);
- const pair p4 = p3;
- EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s, details::makeItem(p3)->toString());
- EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s, details::makeItem(p4)->toString());
-}
-
-TEST(MakeEntryTest, ByteStrings) {
- vector<uint8_t> v1 = {0x00, 0x01, 0x02};
- const vector<uint8_t> v2 = {0x00, 0x01, 0x02};
- EXPECT_EQ("\x43\x00\x01\x02"s, details::makeItem(v1)->toString()); // copy of vector
- EXPECT_EQ("\x43\x00\x01\x02"s, details::makeItem(v2)->toString()); // copy of const vector
- EXPECT_EQ("\x43\x00\x01\x02"s, details::makeItem(std::move(v1))->toString()); // move vector
- EXPECT_EQ(0U, v1.size()); // Prove vector was moved, not copied.
-}
-
-TEST(MakeEntryTest, ByteStringIteratorPairs) {
- using vec = vector<uint8_t>;
- using iter = vec::iterator;
- vec v1 = {0x00, 0x01, 0x02};
- pair<iter, iter> p1 = make_pair(v1.begin(), v1.end());
- const pair<iter, iter> p2 = make_pair(v1.begin(), v1.end());
- EXPECT_EQ("\x43\x00\x01\x02"s, details::makeItem(p1)->toString());
- EXPECT_EQ("\x43\x00\x01\x02"s, details::makeItem(p2)->toString());
-
- // Use uint8_t*s as iterators
- uint8_t v2[] = {0x00, 0x01, 0x02};
- uint8_t* v3 = v2;
- pair<uint8_t*, uint8_t*> p3 = make_pair(v2, v2 + 3);
- const pair<uint8_t*, uint8_t*> p4 = make_pair(v2, v2 + 3);
- pair<uint8_t*, uint8_t*> p5 = make_pair(v3, v3 + 3);
- const pair<uint8_t*, uint8_t*> p6 = make_pair(v3, v3 + 3);
- EXPECT_EQ("\x43\x00\x01\x02"s, details::makeItem(p3)->toString());
- EXPECT_EQ("\x43\x00\x01\x02"s, details::makeItem(p4)->toString());
- EXPECT_EQ("\x43\x00\x01\x02"s, details::makeItem(p5)->toString());
- EXPECT_EQ("\x43\x00\x01\x02"s, details::makeItem(p6)->toString());
-}
-
-TEST(MakeEntryTest, ByteStringBuffers) {
- uint8_t v1[] = {0x00, 0x01, 0x02};
- EXPECT_EQ("\x43\x00\x01\x02"s, details::makeItem(make_pair(v1, 3))->toString());
-}
-
-TEST(MakeEntryTest, ItemPointer) {
- Uint* p1 = new Uint(0);
- EXPECT_EQ("\x00"s, details::makeItem(p1)->toString());
- EXPECT_EQ("\x60"s, details::makeItem(new Tstr(string()))->toString());
-}
-
-TEST(MakeEntryTest, ItemReference) {
- Tstr str("hello"s);
- Tstr& strRef = str;
- const Tstr& strConstRef = str;
- EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s, details::makeItem(str)->toString());
- EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s, details::makeItem(strRef)->toString());
- EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s, details::makeItem(strConstRef)->toString());
- EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s, details::makeItem(std::move(str))->toString());
- EXPECT_EQ("\x60"s, details::makeItem(str)->toString()); // Prove that it moved
-
- EXPECT_EQ("\x00"s, details::makeItem(Uint(0))->toString());
-
- EXPECT_EQ("\x43\x00\x01\x02"s,
- details::makeItem(Bstr(vector<uint8_t>{0x00, 0x01, 0x02}))->toString());
-
- EXPECT_EQ("\x80"s, details::makeItem(Array())->toString());
- EXPECT_EQ("\xa0"s, details::makeItem(Map())->toString());
-}
-
-TEST(CompoundValueTest, ArrayOfInts) {
- EXPECT_EQ("\x80"s, Array().toString());
- Array(Uint(0)).toString();
-
- EXPECT_EQ("\x81\x00"s, Array(Uint(0U)).toString());
- EXPECT_EQ("\x82\x00\x01"s, Array(Uint(0), Uint(1)).toString());
- EXPECT_EQ("\x83\x00\x01\x38\x62"s, Array(Uint(0), Uint(1), Nint(-99)).toString());
-
- EXPECT_EQ("\x81\x00"s, Array(0).toString());
- EXPECT_EQ("\x82\x00\x01"s, Array(0, 1).toString());
- EXPECT_EQ("\x83\x00\x01\x38\x62"s, Array(0, 1, -99).toString());
-}
-
-TEST(CompoundValueTest, MapOfInts) {
- EXPECT_EQ("\xA0"s, Map().toString());
- EXPECT_EQ("\xA1\x00\x01"s, Map(Uint(0), Uint(1)).toString());
- // Maps with an odd number of arguments will fail to compile. Uncomment the next lines to test.
- // EXPECT_EQ("\xA1\x00"s, Map(Int(0)).toString());
- // EXPECT_EQ("\xA1\x00\x01\x02"s, Map(Int(0), Int(1), Int(2)).toString());
-}
-
-TEST(CompoundValueTest, MixedArray) {
- vector<uint8_t> vec = {3, 2, 1};
- EXPECT_EQ("\x84\x01\x20\x43\x03\x02\x01\x65\x68\x65\x6C\x6C\x6F"s,
- Array(Uint(1), Nint(-1), Bstr(vec), Tstr("hello")).toString());
-
- EXPECT_EQ("\x84\x01\x20\x43\x03\x02\x01\x65\x68\x65\x6C\x6C\x6F"s,
- Array(1, -1, vec, "hello").toString());
-}
-
-TEST(CompoundValueTest, MixedMap) {
- vector<uint8_t> vec = {3, 2, 1};
- EXPECT_EQ("\xA2\x01\x20\x43\x03\x02\x01\x65\x68\x65\x6C\x6C\x6F"s,
- Map(Uint(1), Nint(-1), Bstr(vec), Tstr("hello")).toString());
-
- EXPECT_EQ("\xA2\x01\x20\x43\x03\x02\x01\x65\x68\x65\x6C\x6C\x6F"s,
- Map(1, -1, vec, "hello").toString());
-}
-
-TEST(CompoundValueTest, NestedStructures) {
- vector<uint8_t> vec = {3, 2, 1};
-
- string expectedEncoding =
- "\xA2\x66\x4F\x75\x74\x65\x72\x31\x82\xA2\x66\x49\x6E\x6E\x65\x72\x31\x18\x63\x66\x49"
- "\x6E"
- "\x6E\x65\x72\x32\x43\x03\x02\x01\x63\x66\x6F\x6F\x66\x4F\x75\x74\x65\x72\x32\x0A"s;
-
- // Do it with explicitly-created Items
- EXPECT_EQ(expectedEncoding,
- Map(Tstr("Outer1"),
- Array( //
- Map(Tstr("Inner1"), Uint(99), Tstr("Inner2"), Bstr(vec)), Tstr("foo")),
- Tstr("Outer2"), //
- Uint(10))
- .toString());
- EXPECT_EQ(3U, vec.size());
-
- // Now just use convertible types
- EXPECT_EQ(expectedEncoding, Map("Outer1",
- Array(Map("Inner1", 99, //
- "Inner2", vec),
- "foo"),
- "Outer2", 10)
- .toString());
- EXPECT_EQ(3U, vec.size());
-
- // Finally, do it with the .add() method. This is slightly less efficient, but has the
- // advantage you can build a structure up incrementally, or somewhat fluently if you like.
- // First, fluently.
- EXPECT_EQ(expectedEncoding, Map().add("Outer1", Array().add(Map() //
- .add("Inner1", 99)
- .add("Inner2", vec))
- .add("foo"))
- .add("Outer2", 10)
- .toString());
- EXPECT_EQ(3U, vec.size());
-
- // Next, more incrementally
- Array arr;
- arr.add(Map() //
- .add("Inner1", 99)
- .add("Inner2", vec))
- .add("foo");
- EXPECT_EQ(3U, vec.size());
-
- Map m;
- m.add("Outer1", std::move(arr)); // Moving is necessary; Map and Array cannot be copied.
- m.add("Outer2", 10);
- auto s = m.toString();
- EXPECT_EQ(expectedEncoding, s);
-}
-
-TEST(EncodingMethodsTest, AllVariants) {
- Map map;
- map.add("key1", Array().add(Map() //
- .add("key_a", 9999999)
- .add("key_b", std::vector<uint8_t>{0x01, 0x02, 0x03})
- .add("key_c", std::numeric_limits<uint64_t>::max())
- .add("key_d", std::numeric_limits<int16_t>::min()))
- .add("foo"))
- .add("key2", true);
-
- std::vector<uint8_t> buf;
- buf.resize(map.encodedSize());
-
- EXPECT_EQ(buf.data() + buf.size(), map.encode(buf.data(), buf.data() + buf.size()));
-
- EXPECT_EQ(buf, map.encode());
-
- std::vector<uint8_t> buf2;
- map.encode(std::back_inserter(buf2));
- EXPECT_EQ(buf, buf2);
-
- auto iter = buf.begin();
- map.encode([&](uint8_t c) { EXPECT_EQ(c, *iter++); });
-}
-
-TEST(EncodingMethodsTest, UintWithTooShortBuf) {
- Uint val(100000);
- vector<uint8_t> buf(val.encodedSize() - 1);
- EXPECT_EQ(nullptr, val.encode(buf.data(), buf.data() + buf.size()));
-}
-
-TEST(EncodingMethodsTest, TstrWithTooShortBuf) {
- Tstr val("01234567890123456789012345"s);
- vector<uint8_t> buf(1);
- EXPECT_EQ(nullptr, val.encode(buf.data(), buf.data() + buf.size()));
-
- buf.resize(val.encodedSize() - 1);
- EXPECT_EQ(nullptr, val.encode(buf.data(), buf.data() + buf.size()));
-}
-
-TEST(EncodingMethodsTest, BstrWithTooShortBuf) {
- Bstr val("01234567890123456789012345"s);
- vector<uint8_t> buf(1);
- EXPECT_EQ(nullptr, val.encode(buf.data(), buf.data() + buf.size()));
-
- buf.resize(val.encodedSize() - 1);
- EXPECT_EQ(nullptr, val.encode(buf.data(), buf.data() + buf.size()));
-}
-
-TEST(EncodingMethodsTest, ArrayWithTooShortBuf) {
- Array val("a", 5, -100);
-
- std::vector<uint8_t> buf(val.encodedSize() - 1);
- EXPECT_EQ(nullptr, val.encode(buf.data(), buf.data() + buf.size()));
-}
-
-TEST(EncodingMethodsTest, MapWithTooShortBuf) {
- Map map;
- map.add("key1", Array().add(Map() //
- .add("key_a", 99)
- .add("key_b", std::vector<uint8_t>{0x01, 0x02, 0x03}))
- .add("foo"))
- .add("key2", true);
-
- std::vector<uint8_t> buf(map.encodedSize() - 1);
- EXPECT_EQ(nullptr, map.encode(buf.data(), buf.data() + buf.size()));
-}
-
-TEST(EqualityTest, Uint) {
- Uint val(99);
- EXPECT_EQ(val, Uint(99));
-
- EXPECT_NE(val, Uint(98));
- EXPECT_NE(val, Nint(-1));
- EXPECT_NE(val, Tstr("99"));
- EXPECT_NE(val, Bstr("99"));
- EXPECT_NE(val, Bool(false));
- EXPECT_NE(val, Array(99, 1));
- EXPECT_NE(val, Map(99, 1));
-}
-
-TEST(EqualityTest, Nint) {
- Nint val(-1);
- EXPECT_EQ(val, Nint(-1));
-
- EXPECT_NE(val, Uint(99));
- EXPECT_NE(val, Nint(-4));
- EXPECT_NE(val, Tstr("99"));
- EXPECT_NE(val, Bstr("99"));
- EXPECT_NE(val, Bool(false));
- EXPECT_NE(val, Array(99));
- EXPECT_NE(val, Map(99, 1));
-}
-
-TEST(EqualityTest, Tstr) {
- Tstr val("99");
- EXPECT_EQ(val, Tstr("99"));
-
- EXPECT_NE(val, Uint(99));
- EXPECT_NE(val, Nint(-1));
- EXPECT_NE(val, Nint(-4));
- EXPECT_NE(val, Tstr("98"));
- EXPECT_NE(val, Bstr("99"));
- EXPECT_NE(val, Bool(false));
- EXPECT_NE(val, Array(99, 1));
- EXPECT_NE(val, Map(99, 1));
-}
-
-TEST(EqualityTest, Bstr) {
- Bstr val("99");
- EXPECT_EQ(val, Bstr("99"));
-
- EXPECT_NE(val, Uint(99));
- EXPECT_NE(val, Nint(-1));
- EXPECT_NE(val, Nint(-4));
- EXPECT_NE(val, Tstr("99"));
- EXPECT_NE(val, Bstr("98"));
- EXPECT_NE(val, Bool(false));
- EXPECT_NE(val, Array(99, 1));
- EXPECT_NE(val, Map(99, 1));
-}
-
-TEST(EqualityTest, Bool) {
- Bool val(false);
- EXPECT_EQ(val, Bool(false));
-
- EXPECT_NE(val, Uint(99));
- EXPECT_NE(val, Nint(-1));
- EXPECT_NE(val, Nint(-4));
- EXPECT_NE(val, Tstr("99"));
- EXPECT_NE(val, Bstr("98"));
- EXPECT_NE(val, Bool(true));
- EXPECT_NE(val, Array(99, 1));
- EXPECT_NE(val, Map(99, 1));
-}
-
-TEST(EqualityTest, Array) {
- Array val(99, 1);
- EXPECT_EQ(val, Array(99, 1));
-
- EXPECT_NE(val, Uint(99));
- EXPECT_NE(val, Nint(-1));
- EXPECT_NE(val, Nint(-4));
- EXPECT_NE(val, Tstr("99"));
- EXPECT_NE(val, Bstr("98"));
- EXPECT_NE(val, Bool(true));
- EXPECT_NE(val, Array(99, 2));
- EXPECT_NE(val, Array(98, 1));
- EXPECT_NE(val, Array(99, 1, 2));
- EXPECT_NE(val, Map(99, 1));
-}
-
-TEST(EqualityTest, Map) {
- Map val(99, 1);
- EXPECT_EQ(val, Map(99, 1));
-
- EXPECT_NE(val, Uint(99));
- EXPECT_NE(val, Nint(-1));
- EXPECT_NE(val, Nint(-4));
- EXPECT_NE(val, Tstr("99"));
- EXPECT_NE(val, Bstr("98"));
- EXPECT_NE(val, Bool(true));
- EXPECT_NE(val, Array(99, 1));
- EXPECT_NE(val, Map(99, 2));
- EXPECT_NE(val, Map(99, 1, 99, 2));
-}
-
-TEST(ConvertTest, Uint) {
- unique_ptr<Item> item = details::makeItem(10);
-
- EXPECT_EQ(UINT, item->type());
- EXPECT_NE(nullptr, item->asInt());
- EXPECT_NE(nullptr, item->asUint());
- EXPECT_EQ(nullptr, item->asNint());
- EXPECT_EQ(nullptr, item->asTstr());
- EXPECT_EQ(nullptr, item->asBstr());
- EXPECT_EQ(nullptr, item->asSimple());
- EXPECT_EQ(nullptr, item->asMap());
- EXPECT_EQ(nullptr, item->asArray());
-
- EXPECT_EQ(10, item->asInt()->value());
- EXPECT_EQ(10, item->asUint()->value());
-}
-
-TEST(ConvertTest, Nint) {
- unique_ptr<Item> item = details::makeItem(-10);
-
- EXPECT_EQ(NINT, item->type());
- EXPECT_NE(nullptr, item->asInt());
- EXPECT_EQ(nullptr, item->asUint());
- EXPECT_NE(nullptr, item->asNint());
- EXPECT_EQ(nullptr, item->asTstr());
- EXPECT_EQ(nullptr, item->asBstr());
- EXPECT_EQ(nullptr, item->asSimple());
- EXPECT_EQ(nullptr, item->asMap());
- EXPECT_EQ(nullptr, item->asArray());
-
- EXPECT_EQ(-10, item->asInt()->value());
- EXPECT_EQ(-10, item->asNint()->value());
-}
-
-TEST(ConvertTest, Tstr) {
- unique_ptr<Item> item = details::makeItem("hello");
-
- EXPECT_EQ(TSTR, item->type());
- EXPECT_EQ(nullptr, item->asInt());
- EXPECT_EQ(nullptr, item->asUint());
- EXPECT_EQ(nullptr, item->asNint());
- EXPECT_NE(nullptr, item->asTstr());
- EXPECT_EQ(nullptr, item->asBstr());
- EXPECT_EQ(nullptr, item->asSimple());
- EXPECT_EQ(nullptr, item->asMap());
- EXPECT_EQ(nullptr, item->asArray());
-
- EXPECT_EQ("hello"s, item->asTstr()->value());
-}
-
-TEST(ConvertTest, Bstr) {
- vector<uint8_t> vec{0x23, 0x24, 0x22};
- unique_ptr<Item> item = details::makeItem(vec);
-
- EXPECT_EQ(BSTR, item->type());
- EXPECT_EQ(nullptr, item->asInt());
- EXPECT_EQ(nullptr, item->asUint());
- EXPECT_EQ(nullptr, item->asNint());
- EXPECT_EQ(nullptr, item->asTstr());
- EXPECT_NE(nullptr, item->asBstr());
- EXPECT_EQ(nullptr, item->asSimple());
- EXPECT_EQ(nullptr, item->asMap());
- EXPECT_EQ(nullptr, item->asArray());
-
- EXPECT_EQ(vec, item->asBstr()->value());
-}
-
-TEST(ConvertTest, Bool) {
- unique_ptr<Item> item = details::makeItem(false);
-
- EXPECT_EQ(SIMPLE, item->type());
- EXPECT_EQ(nullptr, item->asInt());
- EXPECT_EQ(nullptr, item->asUint());
- EXPECT_EQ(nullptr, item->asNint());
- EXPECT_EQ(nullptr, item->asTstr());
- EXPECT_EQ(nullptr, item->asBstr());
- EXPECT_NE(nullptr, item->asSimple());
- EXPECT_EQ(nullptr, item->asMap());
- EXPECT_EQ(nullptr, item->asArray());
-
- EXPECT_EQ(BOOLEAN, item->asSimple()->simpleType());
- EXPECT_NE(nullptr, item->asSimple()->asBool());
-
- EXPECT_FALSE(item->asSimple()->asBool()->value());
-}
-
-TEST(ConvertTest, Map) {
- unique_ptr<Item> item(new Map);
-
- EXPECT_EQ(MAP, item->type());
- EXPECT_EQ(nullptr, item->asInt());
- EXPECT_EQ(nullptr, item->asUint());
- EXPECT_EQ(nullptr, item->asNint());
- EXPECT_EQ(nullptr, item->asTstr());
- EXPECT_EQ(nullptr, item->asBstr());
- EXPECT_EQ(nullptr, item->asSimple());
- EXPECT_NE(nullptr, item->asMap());
- EXPECT_EQ(nullptr, item->asArray());
-
- EXPECT_EQ(0U, item->asMap()->size());
-}
-
-TEST(ConvertTest, Array) {
- unique_ptr<Item> item(new Array);
-
- EXPECT_EQ(ARRAY, item->type());
- EXPECT_EQ(nullptr, item->asInt());
- EXPECT_EQ(nullptr, item->asUint());
- EXPECT_EQ(nullptr, item->asNint());
- EXPECT_EQ(nullptr, item->asTstr());
- EXPECT_EQ(nullptr, item->asBstr());
- EXPECT_EQ(nullptr, item->asSimple());
- EXPECT_EQ(nullptr, item->asMap());
- EXPECT_NE(nullptr, item->asArray());
-
- EXPECT_EQ(0U, item->asArray()->size());
-}
-
-class MockParseClient : public ParseClient {
- public:
- MOCK_METHOD4(item, ParseClient*(std::unique_ptr<Item>& item, const uint8_t* hdrBegin,
- const uint8_t* valueBegin, const uint8_t* end));
- MOCK_METHOD4(itemEnd, ParseClient*(std::unique_ptr<Item>& item, const uint8_t* hdrBegin,
- const uint8_t* valueBegin, const uint8_t* end));
- MOCK_METHOD2(error, void(const uint8_t* position, const std::string& errorMessage));
-};
-
-MATCHER_P(IsType, value, std::string("Type ") + (negation ? "doesn't match" : "matches")) {
- return arg->type() == value;
-}
-
-MATCHER_P(MatchesItem, value, "") {
- return arg && *arg == value;
-}
-
-MATCHER_P(IsArrayOfSize, value, "") {
- return arg->type() == ARRAY && arg->asArray()->size() == value;
-}
-
-MATCHER_P(IsMapOfSize, value, "") {
- return arg->type() == MAP && arg->asMap()->size() == value;
-}
-
-TEST(StreamParseTest, Uint) {
- MockParseClient mpc;
-
- Uint val(100);
- auto encoded = val.encode();
- uint8_t* encBegin = encoded.data();
- uint8_t* encEnd = encoded.data() + encoded.size();
-
- EXPECT_CALL(mpc, item(MatchesItem(val), encBegin, encEnd, encEnd)).WillOnce(Return(&mpc));
- EXPECT_CALL(mpc, itemEnd(_, _, _, _)).Times(0);
- EXPECT_CALL(mpc, error(_, _)).Times(0);
-
- parse(encoded.data(), encoded.data() + encoded.size(), &mpc);
-}
-
-TEST(StreamParseTest, Nint) {
- MockParseClient mpc;
-
- Nint val(-10);
- auto encoded = val.encode();
- uint8_t* encBegin = encoded.data();
- uint8_t* encEnd = encoded.data() + encoded.size();
-
- EXPECT_CALL(mpc, item(MatchesItem(val), encBegin, encEnd, encEnd)).WillOnce(Return(&mpc));
-
- EXPECT_CALL(mpc, itemEnd(_, _, _, _)).Times(0);
- EXPECT_CALL(mpc, error(_, _)).Times(0);
-
- parse(encoded.data(), encoded.data() + encoded.size(), &mpc);
-}
-
-TEST(StreamParseTest, Bool) {
- MockParseClient mpc;
-
- Bool val(true);
- auto encoded = val.encode();
- uint8_t* encBegin = encoded.data();
- uint8_t* encEnd = encoded.data() + encoded.size();
-
- EXPECT_CALL(mpc, item(MatchesItem(val), encBegin, encEnd, encEnd)).WillOnce(Return(&mpc));
- EXPECT_CALL(mpc, itemEnd(_, _, _, _)).Times(0);
- EXPECT_CALL(mpc, error(_, _)).Times(0);
-
- parse(encoded.data(), encoded.data() + encoded.size(), &mpc);
-}
-
-TEST(StreamParseTest, Tstr) {
- MockParseClient mpc;
-
- Tstr val("Hello");
- auto encoded = val.encode();
- uint8_t* encBegin = encoded.data();
- uint8_t* encEnd = encoded.data() + encoded.size();
-
- EXPECT_CALL(mpc, item(MatchesItem(val), encBegin, encBegin + 1, encEnd)).WillOnce(Return(&mpc));
- EXPECT_CALL(mpc, itemEnd(_, _, _, _)).Times(0);
- EXPECT_CALL(mpc, error(_, _)).Times(0);
-
- parse(encoded.data(), encoded.data() + encoded.size(), &mpc);
-}
-
-TEST(StreamParseTest, Bstr) {
- MockParseClient mpc;
-
- Bstr val("Hello");
- auto encoded = val.encode();
- uint8_t* encBegin = encoded.data();
- uint8_t* encEnd = encoded.data() + encoded.size();
-
- EXPECT_CALL(mpc, item(MatchesItem(val), encBegin, encBegin + 1, encEnd)).WillOnce(Return(&mpc));
- EXPECT_CALL(mpc, itemEnd(_, _, _, _)).Times(0);
- EXPECT_CALL(mpc, error(_, _)).Times(0);
-
- parse(encoded.data(), encoded.data() + encoded.size(), &mpc);
-}
-
-TEST(StreamParseTest, Array) {
- MockParseClient mpc;
-
- Array val("Hello", 4, Array(-9, "Goodbye"), std::numeric_limits<uint64_t>::max());
- ASSERT_NE(val[2]->asArray(), nullptr);
- const Array& interior = *(val[2]->asArray());
- auto encoded = val.encode();
- uint8_t* encBegin = encoded.data();
- uint8_t* encEnd = encoded.data() + encoded.size();
-
- {
- InSequence s;
- const uint8_t* pos = encBegin;
- EXPECT_CALL(mpc, item(IsArrayOfSize(val.size()), pos, pos + 1, pos + 1))
- .WillOnce(Return(&mpc));
- ++pos;
- EXPECT_CALL(mpc, item(MatchesItem(ByRef(*val[0])), pos, pos + 1, pos + 6))
- .WillOnce(Return(&mpc));
- pos += 6;
- EXPECT_CALL(mpc, item(MatchesItem(ByRef(*val[1])), pos, pos + 1, pos + 1))
- .WillOnce(Return(&mpc));
- ++pos;
- const uint8_t* innerArrayBegin = pos;
- EXPECT_CALL(mpc, item(IsArrayOfSize(interior.size()), pos, pos + 1, pos + 1))
- .WillOnce(Return(&mpc));
- ++pos;
- EXPECT_CALL(mpc, item(MatchesItem(ByRef(*interior[0])), pos, pos + 1, pos + 1))
- .WillOnce(Return(&mpc));
- ++pos;
- EXPECT_CALL(mpc, item(MatchesItem(ByRef(*interior[1])), pos, pos + 1, pos + 8))
- .WillOnce(Return(&mpc));
- pos += 8;
- EXPECT_CALL(mpc, itemEnd(IsArrayOfSize(interior.size()), innerArrayBegin,
- innerArrayBegin + 1, pos))
- .WillOnce(Return(&mpc));
- EXPECT_CALL(mpc, item(MatchesItem(ByRef(*val[3])), pos, pos + 9, pos + 9))
- .WillOnce(Return(&mpc));
- EXPECT_CALL(mpc, itemEnd(IsArrayOfSize(val.size()), encBegin, encBegin + 1, encEnd))
- .WillOnce(Return(&mpc));
- }
-
- EXPECT_CALL(mpc, error(_, _)) //
- .Times(0);
-
- parse(encoded.data(), encoded.data() + encoded.size(), &mpc);
-}
-
-TEST(StreamParseTest, Map) {
- MockParseClient mpc;
-
- Map val("Hello", 4, Array(-9, "Goodbye"), std::numeric_limits<uint64_t>::max());
- ASSERT_NE(val[1].first->asArray(), nullptr);
- const Array& interior = *(val[1].first->asArray());
- auto encoded = val.encode();
- uint8_t* encBegin = encoded.data();
- uint8_t* encEnd = encoded.data() + encoded.size();
-
- {
- InSequence s;
- const uint8_t* pos = encBegin;
- EXPECT_CALL(mpc, item(_, pos, pos + 1, pos + 1)).WillOnce(Return(&mpc));
- ++pos;
- EXPECT_CALL(mpc, item(MatchesItem(ByRef(*val[0].first)), pos, pos + 1, pos + 6))
- .WillOnce(Return(&mpc));
- pos += 6;
- EXPECT_CALL(mpc, item(MatchesItem(ByRef(*val[0].second)), pos, pos + 1, pos + 1))
- .WillOnce(Return(&mpc));
- ++pos;
- const uint8_t* innerArrayBegin = pos;
- EXPECT_CALL(mpc, item(IsArrayOfSize(interior.size()), pos, pos + 1, pos + 1))
- .WillOnce(Return(&mpc));
- ++pos;
- EXPECT_CALL(mpc, item(MatchesItem(ByRef(*interior[0])), pos, pos + 1, pos + 1))
- .WillOnce(Return(&mpc));
- ++pos;
- EXPECT_CALL(mpc, item(MatchesItem(ByRef(*interior[1])), pos, pos + 1, pos + 8))
- .WillOnce(Return(&mpc));
- pos += 8;
- EXPECT_CALL(mpc, itemEnd(IsArrayOfSize(interior.size()), innerArrayBegin,
- innerArrayBegin + 1, pos))
- .WillOnce(Return(&mpc));
- EXPECT_CALL(mpc, item(MatchesItem(ByRef(*val[1].second)), pos, pos + 9, pos + 9))
- .WillOnce(Return(&mpc));
- EXPECT_CALL(mpc, itemEnd(IsMapOfSize(val.size()), encBegin, encBegin + 1, encEnd))
- .WillOnce(Return(&mpc));
- }
-
- EXPECT_CALL(mpc, error(_, _)) //
- .Times(0);
-
- parse(encoded.data(), encoded.data() + encoded.size(), &mpc);
-}
-
-TEST(StreamParseTest, Semantic) {
- MockParseClient mpc;
-
- vector<uint8_t> encoded;
- auto iter = back_inserter(encoded);
- encodeHeader(SEMANTIC, 0, iter);
- Uint(999).encode(iter);
-
- EXPECT_CALL(mpc, item(_, _, _, _)).Times(0);
- EXPECT_CALL(mpc, itemEnd(_, _, _, _)).Times(0);
- EXPECT_CALL(mpc, error(encoded.data(), "Semantic tags not supported"));
-
- parse(encoded.data(), encoded.data() + encoded.size(), &mpc);
-}
-
-TEST(FullParserTest, Uint) {
- Uint val(10);
-
- auto [item, pos, message] = parse(val.encode());
- EXPECT_THAT(item, MatchesItem(val));
-}
-
-TEST(FullParserTest, Nint) {
- Nint val(-10);
-
- auto [item, pos, message] = parse(val.encode());
- EXPECT_THAT(item, MatchesItem(val));
-
- vector<uint8_t> minNint = {0x3B, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
-
- std::tie(item, pos, message) = parse(minNint);
- EXPECT_THAT(item, NotNull());
- EXPECT_EQ(item->asNint()->value(), std::numeric_limits<int64_t>::min());
-}
-
-TEST(FullParserTest, NintOutOfRange) {
- vector<uint8_t> outOfRangeNint = {0x3B, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
-
- auto [item, pos, message] = parse(outOfRangeNint);
- EXPECT_THAT(item, IsNull());
- EXPECT_EQ(pos, outOfRangeNint.data());
- EXPECT_EQ(message, "NINT values that don't fit in int64_t are not supported.");
-}
-
-TEST(FullParserTest, Tstr) {
- Tstr val("Hello");
-
- auto [item, pos, message] = parse(val.encode());
- EXPECT_THAT(item, MatchesItem(val));
-}
-
-TEST(FullParserTest, Bstr) {
- Bstr val("\x00\x01\0x02"s);
-
- auto [item, pos, message] = parse(val.encode());
- EXPECT_THAT(item, MatchesItem(val));
-}
-
-TEST(FullParserTest, Array) {
- Array val("hello", -4, 3);
-
- auto encoded = val.encode();
- auto [item, pos, message] = parse(encoded);
- EXPECT_THAT(item, MatchesItem(ByRef(val)));
- EXPECT_EQ(pos, encoded.data() + encoded.size());
- EXPECT_EQ("", message);
-
- // We've already checked it all, but walk it just for fun.
- ASSERT_NE(nullptr, item->asArray());
- const Array& arr = *(item->asArray());
- ASSERT_EQ(arr[0]->type(), TSTR);
- EXPECT_EQ(arr[0]->asTstr()->value(), "hello");
-}
-
-TEST(FullParserTest, Map) {
- Map val("hello", -4, 3, Bstr("hi"));
-
- auto [item, pos, message] = parse(val.encode());
- EXPECT_THAT(item, MatchesItem(ByRef(val)));
-}
-
-TEST(FullParserTest, Complex) {
- vector<uint8_t> vec = {0x01, 0x02, 0x08, 0x03};
- Map val("Outer1",
- Array(Map("Inner1", 99, //
- "Inner2", vec),
- "foo"),
- "Outer2", 10);
-
- std::unique_ptr<Item> item;
- const uint8_t* pos;
- std::string message;
- std::tie(item, pos, message) = parse(val.encode());
- EXPECT_THAT(item, MatchesItem(ByRef(val)));
-}
-
-TEST(FullParserTest, IncompleteUint) {
- Uint val(1000);
-
- auto encoding = val.encode();
- auto [item, pos, message] = parse(encoding.data(), encoding.size() - 1);
- EXPECT_EQ(nullptr, item.get());
- EXPECT_EQ(encoding.data(), pos);
- EXPECT_EQ("Need 2 byte(s) for length field, have 1.", message);
-}
-
-TEST(FullParserTest, IncompleteString) {
- Tstr val("hello");
-
- auto encoding = val.encode();
- auto [item, pos, message] = parse(encoding.data(), encoding.size() - 2);
- EXPECT_EQ(nullptr, item.get());
- EXPECT_EQ(encoding.data(), pos);
- EXPECT_EQ("Need 5 byte(s) for text string, have 3.", message);
-}
-
-TEST(FullParserTest, ArrayWithInsufficientEntries) {
- Array val(1, 2, 3, 4);
-
- auto encoding = val.encode();
- auto [item, pos, message] = parse(encoding.data(), encoding.size() - 1);
- EXPECT_EQ(nullptr, item.get());
- EXPECT_EQ(encoding.data(), pos);
- EXPECT_EQ("Not enough entries for array.", message);
-}
-
-TEST(FullParserTest, ArrayWithTruncatedEntry) {
- Array val(1, 2, 3, 400000);
-
- auto encoding = val.encode();
- auto [item, pos, message] = parse(encoding.data(), encoding.size() - 1);
- EXPECT_EQ(nullptr, item.get());
- EXPECT_EQ(encoding.data() + encoding.size() - 5, pos);
- EXPECT_EQ("Need 4 byte(s) for length field, have 3.", message);
-}
-
-TEST(FullParserTest, MapWithTruncatedEntry) {
- Map val(1, 2, 300000, 4);
-
- auto encoding = val.encode();
- auto [item, pos, message] = parse(encoding.data(), encoding.size() - 2);
- EXPECT_EQ(nullptr, item.get());
- EXPECT_EQ(encoding.data() + 3, pos);
- EXPECT_EQ("Need 4 byte(s) for length field, have 3.", message);
-}
-int main(int argc, char** argv) {
- ::testing::InitGoogleTest(&argc, argv);
- return RUN_ALL_TESTS();
-}
diff --git a/input/OWNERS b/input/OWNERS
new file mode 100644
index 0000000..21d208f
--- /dev/null
+++ b/input/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 136048
+include platform/frameworks/base:/INPUT_OWNERS
diff --git a/media/OWNERS b/media/OWNERS
new file mode 100644
index 0000000..71a53ef
--- /dev/null
+++ b/media/OWNERS
@@ -0,0 +1,7 @@
+# Bug component: 25690
+
+# Media team
+jgus@google.com
+lajos@google.com
+taklee@google.com
+wonsik@google.com
diff --git a/media/bufferpool/aidl/Android.bp b/media/bufferpool/aidl/Android.bp
index 68ac489..5ea2948 100644
--- a/media/bufferpool/aidl/Android.bp
+++ b/media/bufferpool/aidl/Android.bp
@@ -24,6 +24,7 @@
aidl_interface {
name: "android.hardware.media.bufferpool2",
vendor_available: true,
+ double_loadable: true,
srcs: ["android/hardware/media/bufferpool2/*.aidl"],
imports: [
"android.hardware.common-V2",
diff --git a/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/IClientManager.aidl b/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/IClientManager.aidl
index 54896d4..5899a40 100644
--- a/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/IClientManager.aidl
+++ b/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/IClientManager.aidl
@@ -34,5 +34,10 @@
package android.hardware.media.bufferpool2;
@VintfStability
interface IClientManager {
- long registerSender(in android.hardware.media.bufferpool2.IAccessor bufferPool);
+ android.hardware.media.bufferpool2.IClientManager.Registration registerSender(in android.hardware.media.bufferpool2.IAccessor bufferPool);
+ @VintfStability
+ parcelable Registration {
+ long connectionId;
+ boolean isNew = true;
+ }
}
diff --git a/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/IConnection.aidl b/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/IConnection.aidl
index 300fcba..844e920 100644
--- a/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/IConnection.aidl
+++ b/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/IConnection.aidl
@@ -35,12 +35,13 @@
@VintfStability
interface IConnection {
android.hardware.media.bufferpool2.IConnection.FetchResult[] fetch(in android.hardware.media.bufferpool2.IConnection.FetchInfo[] fetchInfos);
+ void sync();
parcelable FetchInfo {
long transactionId;
int bufferId;
}
union FetchResult {
android.hardware.media.bufferpool2.Buffer buffer;
- android.hardware.media.bufferpool2.ResultStatus failure;
+ int failure;
}
}
diff --git a/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/ResultStatus.aidl b/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/ResultStatus.aidl
index 7370998..4bc3889 100644
--- a/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/ResultStatus.aidl
+++ b/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/ResultStatus.aidl
@@ -34,7 +34,6 @@
package android.hardware.media.bufferpool2;
@VintfStability
parcelable ResultStatus {
- int resultStatus;
const int OK = 0;
const int NO_MEMORY = 1;
const int ALREADY_EXISTS = 2;
diff --git a/media/bufferpool/aidl/android/hardware/media/bufferpool2/IClientManager.aidl b/media/bufferpool/aidl/android/hardware/media/bufferpool2/IClientManager.aidl
index bf36e25..a3054cb 100644
--- a/media/bufferpool/aidl/android/hardware/media/bufferpool2/IClientManager.aidl
+++ b/media/bufferpool/aidl/android/hardware/media/bufferpool2/IClientManager.aidl
@@ -28,6 +28,16 @@
@VintfStability
interface IClientManager {
/**
+ * Result of registerSender.
+ */
+ @VintfStability
+ parcelable Registration {
+ /** registered connection id */
+ long connectionId;
+ /** true when the connection is new */
+ boolean isNew = true;
+ }
+ /**
* Sets up a buffer receiving communication node for the specified
* buffer pool. A manager must create a IConnection to the buffer
* pool if it does not already have a connection.
@@ -39,8 +49,7 @@
* sent to that connection during transfers.
* @throws ServiceSpecificException with one of the following values:
* ResultStatus::NO_MEMORY - Memory allocation failure occurred.
- * ResultStatus::ALREADY_EXISTS - A sender was registered already.
* ResultStatus::CRITICAL_ERROR - Other errors.
*/
- long registerSender(in IAccessor bufferPool);
+ Registration registerSender(in IAccessor bufferPool);
}
diff --git a/media/bufferpool/aidl/android/hardware/media/bufferpool2/IConnection.aidl b/media/bufferpool/aidl/android/hardware/media/bufferpool2/IConnection.aidl
index d869f47..68367c7 100644
--- a/media/bufferpool/aidl/android/hardware/media/bufferpool2/IConnection.aidl
+++ b/media/bufferpool/aidl/android/hardware/media/bufferpool2/IConnection.aidl
@@ -49,7 +49,7 @@
* ResultStatus::NOT_FOUND - A buffer was not found due to invalidation.
* ResultStatus::CRITICAL_ERROR - Other errors.
*/
- ResultStatus failure;
+ int failure;
}
/**
@@ -70,4 +70,12 @@
* ResultStatus::CRITICAL_ERROR - Other errors.
*/
FetchResult[] fetch(in FetchInfo[] fetchInfos);
+
+ /**
+ * Enforce processing of unprocessed bufferpool messages.
+ *
+ * BufferPool implementation optimizes message processing by piggy-backing approach.
+ * This method can ensure pending bufferpool messages being processed timely.
+ */
+ void sync();
}
diff --git a/media/bufferpool/aidl/android/hardware/media/bufferpool2/ResultStatus.aidl b/media/bufferpool/aidl/android/hardware/media/bufferpool2/ResultStatus.aidl
index 162f9a7..003d147 100644
--- a/media/bufferpool/aidl/android/hardware/media/bufferpool2/ResultStatus.aidl
+++ b/media/bufferpool/aidl/android/hardware/media/bufferpool2/ResultStatus.aidl
@@ -23,6 +23,4 @@
const int ALREADY_EXISTS = 2;
const int NOT_FOUND = 3;
const int CRITICAL_ERROR = 4;
-
- int resultStatus;
}
diff --git a/media/c2/aidl/Android.bp b/media/c2/aidl/Android.bp
index 10867c0..56531db 100644
--- a/media/c2/aidl/Android.bp
+++ b/media/c2/aidl/Android.bp
@@ -1,8 +1,18 @@
// This is the expected build file, but it may not be right in all cases
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
aidl_interface {
name: "android.hardware.media.c2",
vendor_available: true,
+ double_loadable: true,
srcs: ["android/hardware/media/c2/*.aidl"],
include_dirs: [
"frameworks/native/aidl/gui",
diff --git a/neuralnetworks/1.2/utils/src/BurstUtils.cpp b/neuralnetworks/1.2/utils/src/BurstUtils.cpp
index b589c46..c4c096d 100644
--- a/neuralnetworks/1.2/utils/src/BurstUtils.cpp
+++ b/neuralnetworks/1.2/utils/src/BurstUtils.cpp
@@ -190,12 +190,13 @@
size_t index = 0;
// validate packet information
- if (data.size() == 0 || data[index].getDiscriminator() != discriminator::packetInformation) {
+ if (index >= data.size() ||
+ data.at(index).getDiscriminator() != discriminator::packetInformation) {
return NN_ERROR() << "FMQ Request packet ill-formed";
}
// unpackage packet information
- const FmqRequestDatum::PacketInformation& packetInfo = data[index].packetInformation();
+ const FmqRequestDatum::PacketInformation& packetInfo = data.at(index).packetInformation();
index++;
const uint32_t packetSize = packetInfo.packetSize;
const uint32_t numberOfInputOperands = packetInfo.numberOfInputOperands;
@@ -212,13 +213,14 @@
inputs.reserve(numberOfInputOperands);
for (size_t operand = 0; operand < numberOfInputOperands; ++operand) {
// validate input operand information
- if (data[index].getDiscriminator() != discriminator::inputOperandInformation) {
+ if (index >= data.size() ||
+ data.at(index).getDiscriminator() != discriminator::inputOperandInformation) {
return NN_ERROR() << "FMQ Request packet ill-formed";
}
// unpackage operand information
const FmqRequestDatum::OperandInformation& operandInfo =
- data[index].inputOperandInformation();
+ data.at(index).inputOperandInformation();
index++;
const bool hasNoValue = operandInfo.hasNoValue;
const V1_0::DataLocation location = operandInfo.location;
@@ -229,12 +231,13 @@
dimensions.reserve(numberOfDimensions);
for (size_t i = 0; i < numberOfDimensions; ++i) {
// validate dimension
- if (data[index].getDiscriminator() != discriminator::inputOperandDimensionValue) {
+ if (index >= data.size() ||
+ data.at(index).getDiscriminator() != discriminator::inputOperandDimensionValue) {
return NN_ERROR() << "FMQ Request packet ill-formed";
}
// unpackage dimension
- const uint32_t dimension = data[index].inputOperandDimensionValue();
+ const uint32_t dimension = data.at(index).inputOperandDimensionValue();
index++;
// store result
@@ -251,13 +254,14 @@
outputs.reserve(numberOfOutputOperands);
for (size_t operand = 0; operand < numberOfOutputOperands; ++operand) {
// validate output operand information
- if (data[index].getDiscriminator() != discriminator::outputOperandInformation) {
+ if (index >= data.size() ||
+ data.at(index).getDiscriminator() != discriminator::outputOperandInformation) {
return NN_ERROR() << "FMQ Request packet ill-formed";
}
// unpackage operand information
const FmqRequestDatum::OperandInformation& operandInfo =
- data[index].outputOperandInformation();
+ data.at(index).outputOperandInformation();
index++;
const bool hasNoValue = operandInfo.hasNoValue;
const V1_0::DataLocation location = operandInfo.location;
@@ -268,12 +272,13 @@
dimensions.reserve(numberOfDimensions);
for (size_t i = 0; i < numberOfDimensions; ++i) {
// validate dimension
- if (data[index].getDiscriminator() != discriminator::outputOperandDimensionValue) {
+ if (index >= data.size() ||
+ data.at(index).getDiscriminator() != discriminator::outputOperandDimensionValue) {
return NN_ERROR() << "FMQ Request packet ill-formed";
}
// unpackage dimension
- const uint32_t dimension = data[index].outputOperandDimensionValue();
+ const uint32_t dimension = data.at(index).outputOperandDimensionValue();
index++;
// store result
@@ -290,12 +295,13 @@
slots.reserve(numberOfPools);
for (size_t pool = 0; pool < numberOfPools; ++pool) {
// validate input operand information
- if (data[index].getDiscriminator() != discriminator::poolIdentifier) {
+ if (index >= data.size() ||
+ data.at(index).getDiscriminator() != discriminator::poolIdentifier) {
return NN_ERROR() << "FMQ Request packet ill-formed";
}
// unpackage operand information
- const int32_t poolId = data[index].poolIdentifier();
+ const int32_t poolId = data.at(index).poolIdentifier();
index++;
// store result
@@ -303,17 +309,17 @@
}
// validate measureTiming
- if (data[index].getDiscriminator() != discriminator::measureTiming) {
+ if (index >= data.size() || data.at(index).getDiscriminator() != discriminator::measureTiming) {
return NN_ERROR() << "FMQ Request packet ill-formed";
}
// unpackage measureTiming
- const V1_2::MeasureTiming measure = data[index].measureTiming();
+ const V1_2::MeasureTiming measure = data.at(index).measureTiming();
index++;
// validate packet information
if (index != packetSize) {
- return NN_ERROR() << "FMQ Result packet ill-formed";
+ return NN_ERROR() << "FMQ Request packet ill-formed";
}
// return request
@@ -328,12 +334,13 @@
size_t index = 0;
// validate packet information
- if (data.size() == 0 || data[index].getDiscriminator() != discriminator::packetInformation) {
+ if (index >= data.size() ||
+ data.at(index).getDiscriminator() != discriminator::packetInformation) {
return NN_ERROR() << "FMQ Result packet ill-formed";
}
// unpackage packet information
- const FmqResultDatum::PacketInformation& packetInfo = data[index].packetInformation();
+ const FmqResultDatum::PacketInformation& packetInfo = data.at(index).packetInformation();
index++;
const uint32_t packetSize = packetInfo.packetSize;
const V1_0::ErrorStatus errorStatus = packetInfo.errorStatus;
@@ -349,12 +356,13 @@
outputShapes.reserve(numberOfOperands);
for (size_t operand = 0; operand < numberOfOperands; ++operand) {
// validate operand information
- if (data[index].getDiscriminator() != discriminator::operandInformation) {
+ if (index >= data.size() ||
+ data.at(index).getDiscriminator() != discriminator::operandInformation) {
return NN_ERROR() << "FMQ Result packet ill-formed";
}
// unpackage operand information
- const FmqResultDatum::OperandInformation& operandInfo = data[index].operandInformation();
+ const FmqResultDatum::OperandInformation& operandInfo = data.at(index).operandInformation();
index++;
const bool isSufficient = operandInfo.isSufficient;
const uint32_t numberOfDimensions = operandInfo.numberOfDimensions;
@@ -364,12 +372,13 @@
dimensions.reserve(numberOfDimensions);
for (size_t i = 0; i < numberOfDimensions; ++i) {
// validate dimension
- if (data[index].getDiscriminator() != discriminator::operandDimensionValue) {
+ if (index >= data.size() ||
+ data.at(index).getDiscriminator() != discriminator::operandDimensionValue) {
return NN_ERROR() << "FMQ Result packet ill-formed";
}
// unpackage dimension
- const uint32_t dimension = data[index].operandDimensionValue();
+ const uint32_t dimension = data.at(index).operandDimensionValue();
index++;
// store result
@@ -381,12 +390,13 @@
}
// validate execution timing
- if (data[index].getDiscriminator() != discriminator::executionTiming) {
+ if (index >= data.size() ||
+ data.at(index).getDiscriminator() != discriminator::executionTiming) {
return NN_ERROR() << "FMQ Result packet ill-formed";
}
// unpackage execution timing
- const V1_2::Timing timing = data[index].executionTiming();
+ const V1_2::Timing timing = data.at(index).executionTiming();
index++;
// validate packet information
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..9caa97a 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: {
@@ -151,6 +153,23 @@
}
aidl_interface {
+ name: "android.hardware.radio.sap",
+ vendor_available: true,
+ host_supported: true,
+ srcs: ["android/hardware/radio/sap/*.aidl"],
+ stability: "vintf",
+ backend: {
+ cpp: {
+ enabled: true,
+ },
+ java: {
+ sdk_version: "module_current",
+ },
+ },
+
+}
+
+aidl_interface {
name: "android.hardware.radio.sim",
vendor_available: true,
host_supported: true,
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.modem/current/android/hardware/radio/modem/IRadioModem.aidl b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/IRadioModem.aidl
index 74dc39d..8546be7 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/IRadioModem.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/IRadioModem.aidl
@@ -36,6 +36,9 @@
interface IRadioModem {
oneway void enableModem(in int serial, in boolean on);
oneway void getBasebandVersion(in int serial);
+ /**
+ * @deprecated use getImei(int serial)
+ */
oneway void getDeviceIdentity(in int serial);
oneway void getHardwareConfig(in int serial);
oneway void getModemActivityInfo(in int serial);
@@ -60,4 +63,5 @@
oneway void setRadioCapability(in int serial, in android.hardware.radio.modem.RadioCapability rc);
oneway void setRadioPower(in int serial, in boolean powerOn, in boolean forEmergencyCall, in boolean preferredForEmergencyCall);
oneway void setResponseFunctions(in android.hardware.radio.modem.IRadioModemResponse radioModemResponse, in android.hardware.radio.modem.IRadioModemIndication radioModemIndication);
+ oneway void getImei(in int serial);
}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/IRadioModemResponse.aidl b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/IRadioModemResponse.aidl
index af8bbe1..5955439 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/IRadioModemResponse.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/IRadioModemResponse.aidl
@@ -37,6 +37,9 @@
oneway void acknowledgeRequest(in int serial);
oneway void enableModemResponse(in android.hardware.radio.RadioResponseInfo info);
oneway void getBasebandVersionResponse(in android.hardware.radio.RadioResponseInfo info, in String version);
+ /**
+ * @deprecated use getImeiResponse(RadioResponseInfo responseInfo, ImeiInfo imeiInfo)
+ */
oneway void getDeviceIdentityResponse(in android.hardware.radio.RadioResponseInfo info, in String imei, in String imeisv, in String esn, in String meid);
oneway void getHardwareConfigResponse(in android.hardware.radio.RadioResponseInfo info, in android.hardware.radio.modem.HardwareConfig[] config);
oneway void getModemActivityInfoResponse(in android.hardware.radio.RadioResponseInfo info, in android.hardware.radio.modem.ActivityStatsInfo activityInfo);
@@ -59,4 +62,5 @@
oneway void sendDeviceStateResponse(in android.hardware.radio.RadioResponseInfo info);
oneway void setRadioCapabilityResponse(in android.hardware.radio.RadioResponseInfo info, in android.hardware.radio.modem.RadioCapability rc);
oneway void setRadioPowerResponse(in android.hardware.radio.RadioResponseInfo info);
+ oneway void getImeiResponse(in android.hardware.radio.RadioResponseInfo responseInfo, in @nullable android.hardware.radio.modem.ImeiInfo imeiInfo);
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/ImeiInfo.aidl
similarity index 75%
copy from audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
copy to radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/ImeiInfo.aidl
index 8ad4848..dda7062 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/ImeiInfo.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;
+package android.hardware.radio.modem;
+@JavaDerive(toString=true) @VintfStability
+parcelable ImeiInfo {
+ @Backing(type="int") @VintfStability
+ enum ImeiType {
+ PRIMARY = 1,
+ SECONDARY = 2,
}
- @VintfStability
- parcelable Capability {
- android.hardware.audio.effect.VendorExtension extension;
- int maxDecayTimeMs;
- }
-}
+ ImeiType type;
+ String imei;
+ String svn;
+}
\ No newline at end of file
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.network/current/android/hardware/radio/network/NrSignalStrength.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/NrSignalStrength.aidl
index 98bbe6b..2055024 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/NrSignalStrength.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/NrSignalStrength.aidl
@@ -42,4 +42,5 @@
int csiSinr;
int csiCqiTableIndex;
byte[] csiCqiReport;
+ int timingAdvance;
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/ISap.aidl
similarity index 71%
copy from audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
copy to radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/ISap.aidl
index 8ad4848..37391e9 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/ISap.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.radio.sap;
@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 ISap {
+ oneway void apduReq(in int serial, in android.hardware.radio.sap.SapApduType type, in byte[] command);
+ oneway void connectReq(in int serial, in int maxMsgSizeBytes);
+ oneway void disconnectReq(in int serial);
+ oneway void powerReq(in int serial, in boolean powerOn);
+ oneway void resetSimReq(in int serial);
+ oneway void setCallback(in android.hardware.radio.sap.ISapCallback sapCallback);
+ oneway void setTransferProtocolReq(in int serial, in android.hardware.radio.sap.SapTransferProtocol transferProtocol);
+ oneway void transferAtrReq(in int serial);
+ oneway void transferCardReaderStatusReq(in int serial);
}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/ISapCallback.aidl b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/ISapCallback.aidl
new file mode 100644
index 0000000..d507709
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/ISapCallback.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.radio.sap;
+@VintfStability
+interface ISapCallback {
+ oneway void apduResponse(in int serial, in android.hardware.radio.sap.SapResultCode resultCode, in byte[] apduRsp);
+ oneway void connectResponse(in int serial, in android.hardware.radio.sap.SapConnectRsp sapConnectRsp, in int maxMsgSizeBytes);
+ oneway void disconnectIndication(in int serial, in android.hardware.radio.sap.SapDisconnectType disconnectType);
+ oneway void disconnectResponse(in int serial);
+ oneway void errorResponse(in int serial);
+ oneway void powerResponse(in int serial, in android.hardware.radio.sap.SapResultCode resultCode);
+ oneway void resetSimResponse(in int serial, in android.hardware.radio.sap.SapResultCode resultCode);
+ oneway void statusIndication(in int serial, in android.hardware.radio.sap.SapStatus status);
+ oneway void transferAtrResponse(in int serial, in android.hardware.radio.sap.SapResultCode resultCode, in byte[] atr);
+ oneway void transferCardReaderStatusResponse(in int serial, in android.hardware.radio.sap.SapResultCode resultCode, in int cardReaderStatus);
+ oneway void transferProtocolResponse(in int serial, in android.hardware.radio.sap.SapResultCode resultCode);
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapApduType.aidl
similarity index 75%
copy from audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
copy to radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapApduType.aidl
index 8ad4848..e0e2a03 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapApduType.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;
-@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.radio.sap;
+@Backing(type="int") @VintfStability
+enum SapApduType {
+ APDU = 0,
+ APDU7816 = 1,
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapConnectRsp.aidl
similarity index 75%
copy from audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
copy to radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapConnectRsp.aidl
index 8ad4848..aceac37 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapConnectRsp.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;
-@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.radio.sap;
+@Backing(type="int") @VintfStability
+enum SapConnectRsp {
+ SUCCESS = 0,
+ CONNECT_FAILURE = 1,
+ MSG_SIZE_TOO_LARGE = 2,
+ MSG_SIZE_TOO_SMALL = 3,
+ CONNECT_OK_CALL_ONGOING = 4,
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapDisconnectType.aidl
similarity index 75%
copy from audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
copy to radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapDisconnectType.aidl
index 8ad4848..0447f9b 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapDisconnectType.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;
-@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.radio.sap;
+@Backing(type="int") @VintfStability
+enum SapDisconnectType {
+ GRACEFUL = 0,
+ IMMEDIATE = 1,
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapResultCode.aidl
similarity index 75%
copy from audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
copy to radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapResultCode.aidl
index 8ad4848..1db226b 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapResultCode.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.radio.sap;
+@Backing(type="int") @VintfStability
+enum SapResultCode {
+ SUCCESS = 0,
+ GENERIC_FAILURE = 1,
+ CARD_NOT_ACCESSSIBLE = 2,
+ CARD_ALREADY_POWERED_OFF = 3,
+ CARD_REMOVED = 4,
+ CARD_ALREADY_POWERED_ON = 5,
+ DATA_NOT_AVAILABLE = 6,
+ NOT_SUPPORTED = 7,
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapStatus.aidl
similarity index 75%
copy from audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
copy to radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapStatus.aidl
index 8ad4848..32f71c2 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapStatus.aidl
@@ -31,27 +31,13 @@
// with such a backward incompatible 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.radio.sap;
+@Backing(type="int") @VintfStability
+enum SapStatus {
+ UNKNOWN_ERROR = 0,
+ CARD_RESET = 1,
+ CARD_NOT_ACCESSIBLE = 2,
+ CARD_REMOVED = 3,
+ CARD_INSERTED = 4,
+ RECOVERED = 5,
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapTransferProtocol.aidl
similarity index 75%
copy from audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
copy to radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapTransferProtocol.aidl
index 8ad4848..e3ffdb0 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapTransferProtocol.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;
-@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.radio.sap;
+@Backing(type="int") @VintfStability
+enum SapTransferProtocol {
+ T0 = 0,
+ T1 = 1,
}
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/CarrierRestrictions.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/CarrierRestrictions.aidl
index 944f1ca..8a61dca 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/CarrierRestrictions.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/CarrierRestrictions.aidl
@@ -34,7 +34,15 @@
package android.hardware.radio.sim;
@JavaDerive(toString=true) @VintfStability
parcelable CarrierRestrictions {
- android.hardware.radio.sim.Carrier[] allowedCarriers;
- android.hardware.radio.sim.Carrier[] excludedCarriers;
- boolean allowedCarriersPrioritized;
+ @Backing(type="int") @VintfStability
+ enum CarrierRestrictionStatus {
+ UNKNOWN = 0,
+ NOT_RESTRICTED = 1,
+ RESTRICTED = 2,
+ }
+ android.hardware.radio.sim.Carrier[] allowedCarriers;
+ android.hardware.radio.sim.Carrier[] excludedCarriers;
+ boolean allowedCarriersPrioritized;
+ CarrierRestrictionStatus status;
+ int carrierId;
}
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/modem/IRadioModem.aidl b/radio/aidl/android/hardware/radio/modem/IRadioModem.aidl
index a5d98d3..2011c53 100644
--- a/radio/aidl/android/hardware/radio/modem/IRadioModem.aidl
+++ b/radio/aidl/android/hardware/radio/modem/IRadioModem.aidl
@@ -67,6 +67,7 @@
* @param serial Serial number of request.
*
* Response function is IRadioModemResponse.getDeviceIdentityResponse()
+ * @deprecated use getImei(int serial)
*/
void getDeviceIdentity(in int serial);
@@ -235,4 +236,13 @@
*/
void setResponseFunctions(in IRadioModemResponse radioModemResponse,
in IRadioModemIndication radioModemIndication);
+
+ /**
+ * Request the IMEI associated with the radio.
+ *
+ * @param serial : Serial number of request.
+ *
+ * Response function is IRadioModemResponse.getImeiResponse()
+ */
+ void getImei(in int serial);
}
diff --git a/radio/aidl/android/hardware/radio/modem/IRadioModemResponse.aidl b/radio/aidl/android/hardware/radio/modem/IRadioModemResponse.aidl
index eca3192..fd4bffb 100644
--- a/radio/aidl/android/hardware/radio/modem/IRadioModemResponse.aidl
+++ b/radio/aidl/android/hardware/radio/modem/IRadioModemResponse.aidl
@@ -20,6 +20,7 @@
import android.hardware.radio.modem.ActivityStatsInfo;
import android.hardware.radio.modem.HardwareConfig;
import android.hardware.radio.modem.RadioCapability;
+import android.hardware.radio.modem.ImeiInfo;
/**
* Interface declaring response functions to solicited radio requests for modem APIs.
@@ -87,6 +88,8 @@
* RadioError:NOT_PROVISIONED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
+ * RadioError:REQUEST_NOT_SUPPORTED
+ * @deprecated use getImeiResponse(RadioResponseInfo responseInfo, ImeiInfo imeiInfo)
*/
void getDeviceIdentityResponse(in RadioResponseInfo info, in String imei, in String imeisv,
in String esn, in String meid);
@@ -250,4 +253,20 @@
* RadioError:NO_RF_CALIBRATION_INFO
*/
void setRadioPowerResponse(in RadioResponseInfo info);
+
+ /**
+ * ImeiInfo to encapsulate the IMEI information from modem. When the return error code
+ * is {@code RadioError:NONE}, {@code imeiInfo} must be non-null, and a valid IMEITYPE,
+ * IMEI and SVN must be filled in {@code imeiInfo}. When the error code is not
+ * {@code RadioError:NONE}, {@code imeiInfo} must be {@code null}.
+ *
+ * @param responseInfo Response info struct containing response type, serial no. and error
+ * @param imeiInfo IMEI information
+ *
+ * Valid errors returned:
+ * RadioError:NONE
+ * RadioError:RADIO_NOT_AVAILABLE
+ * RadioError:MODEM_ERR
+ */
+ void getImeiResponse(in RadioResponseInfo responseInfo, in @nullable ImeiInfo imeiInfo);
}
diff --git a/radio/aidl/android/hardware/radio/modem/ImeiInfo.aidl b/radio/aidl/android/hardware/radio/modem/ImeiInfo.aidl
new file mode 100644
index 0000000..2d25bb7
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/modem/ImeiInfo.aidl
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.radio.modem;
+
+/**
+ * ImeiInfo to encapsulate the IMEI information from modem
+ */
+
+@VintfStability
+@JavaDerive(toString=true)
+parcelable ImeiInfo {
+
+ @VintfStability
+ @Backing(type="int")
+ /**
+ * ImeiType enum is used identify the IMEI as primary or secondary as mentioned in GSMA TS.37
+ */
+ enum ImeiType {
+ /**
+ * This is the primary IMEI of the device as mentioned in the GSMA TS.37. In a multi-SIM
+ * device the modem must set one IMEI with this type as mentioned in GSMA TS37_2.2_REQ_8.
+ * A single SIM with one IMEI must by default set that IMEI with this type.
+ */
+ PRIMARY = 1,
+ /** This is not the primary IMEI of the device */
+ SECONDARY = 2,
+ }
+
+ /** Primary or secondary IMEI as mentioned in GSMA spec TS.37 */
+ ImeiType type;
+ /**
+ * IMEI value, see 3gpp spec 23.003 section 6. Note: This primary IMEI mapping must be
+ * permanent throughout the lifetime of the device irrespective of the factory data reset,
+ * SIM activations or swaps.
+ */
+ String imei;
+ /**
+ * IMEI software version, see 3gpp spec 23.003 section 6.
+ */
+ String svn;
+}
\ No newline at end of file
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/network/NrSignalStrength.aidl b/radio/aidl/android/hardware/radio/network/NrSignalStrength.aidl
index 1bb569a..2314562 100644
--- a/radio/aidl/android/hardware/radio/network/NrSignalStrength.aidl
+++ b/radio/aidl/android/hardware/radio/network/NrSignalStrength.aidl
@@ -71,4 +71,11 @@
* Range [0, 15], 0xFF means invalid/unreported.
*/
byte[] csiCqiReport;
+ /**
+ * Timing advance in micro seconds for a one way trip from cell to device. Approximate distance
+ * is calculated using 300m/us * timingAdvance. Range: 0 to 1282 inclusive.
+ * INT_MAX: 0x7FFFFFFF denotes invalid/unreported value.
+ * Reference: 3GPP 36.213 section 4.2.3
+ */
+ int timingAdvance;
}
diff --git a/radio/aidl/android/hardware/radio/sap/ISap.aidl b/radio/aidl/android/hardware/radio/sap/ISap.aidl
new file mode 100644
index 0000000..552e602
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/sap/ISap.aidl
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.radio.sap;
+
+import android.hardware.radio.sap.ISapCallback;
+import android.hardware.radio.sap.SapApduType;
+import android.hardware.radio.sap.SapTransferProtocol;
+
+@VintfStability
+oneway interface ISap {
+ /**
+ * TRANSFER_APDU_REQ from SAP 1.1 spec 5.1.6
+ *
+ * @param serial Id to match req-resp. Resp must include same serial.
+ * @param type APDU command type
+ * @param command CommandAPDU/CommandAPDU7816 parameter depending on type
+ */
+ void apduReq(in int serial, in SapApduType type, in byte[] command);
+
+ /**
+ * CONNECT_REQ from SAP 1.1 spec 5.1.1
+ *
+ * @param serial Id to match req-resp. Resp must include same serial.
+ * @param maxMsgSizeBytes MaxMsgSize to be used for SIM Access Profile connection
+ */
+ void connectReq(in int serial, in int maxMsgSizeBytes);
+
+ /**
+ * DISCONNECT_REQ from SAP 1.1 spec 5.1.3
+ *
+ * @param serial Id to match req-resp. Resp must include same serial.
+ */
+ void disconnectReq(in int serial);
+
+ /**
+ * POWER_SIM_OFF_REQ and POWER_SIM_ON_REQ from SAP 1.1 spec 5.1.10 + 5.1.12
+ *
+ * @param serial Id to match req-resp. Resp must include same serial.
+ * @param powerOn true for on, false for off
+ */
+ void powerReq(in int serial, in boolean powerOn);
+
+ /**
+ * RESET_SIM_REQ from SAP 1.1 spec 5.1.14
+ *
+ * @param serial Id to match req-resp. Resp must include same serial.
+ */
+ void resetSimReq(in int serial);
+
+ /**
+ * Set callback that has response and unsolicited indication functions
+ *
+ * @param sapCallback Object containing response and unosolicited indication callbacks
+ */
+ void setCallback(in ISapCallback sapCallback);
+
+ /**
+ * SET_TRANSPORT_PROTOCOL_REQ from SAP 1.1 spec 5.1.20
+ *
+ * @param serial Id to match req-resp. Resp must include same serial.
+ * @param transferProtocol Transport Protocol
+ */
+ void setTransferProtocolReq(in int serial, in SapTransferProtocol transferProtocol);
+
+ /**
+ * TRANSFER_ATR_REQ from SAP 1.1 spec 5.1.8
+ *
+ * @param serial Id to match req-resp. Resp must include same serial.
+ */
+ void transferAtrReq(in int serial);
+
+ /**
+ * TRANSFER_CARD_READER_STATUS_REQ from SAP 1.1 spec 5.1.17
+ *
+ * @param serial Id to match req-resp. Resp must include same serial.
+ */
+ void transferCardReaderStatusReq(in int serial);
+}
diff --git a/radio/aidl/android/hardware/radio/sap/ISapCallback.aidl b/radio/aidl/android/hardware/radio/sap/ISapCallback.aidl
new file mode 100644
index 0000000..34111eb
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/sap/ISapCallback.aidl
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.radio.sap;
+
+import android.hardware.radio.sap.SapConnectRsp;
+import android.hardware.radio.sap.SapDisconnectType;
+import android.hardware.radio.sap.SapResultCode;
+import android.hardware.radio.sap.SapStatus;
+
+@VintfStability
+oneway interface ISapCallback {
+ /**
+ * TRANSFER_APDU_RESP from SAP 1.1 spec 5.1.7
+ *
+ * @param serial Id to match req-resp. Value must match the one in req.
+ * @param resultCode ResultCode to indicate if command was processed correctly
+ * Possible values:
+ * SapResultCode:SUCCESS,
+ * SapResultCode:GENERIC_FAILURE,
+ * SapResultCode:CARD_NOT_ACCESSSIBLE,
+ * SapResultCode:CARD_ALREADY_POWERED_OFF,
+ * SapResultCode:CARD_REMOVED
+ * @param apduRsp APDU Response. Valid only if command was processed correctly and no error
+ * occurred.
+ */
+ void apduResponse(in int serial, in SapResultCode resultCode, in byte[] apduRsp);
+
+ /**
+ * CONNECT_RESP from SAP 1.1 spec 5.1.2
+ *
+ * @param serial Id to match req-resp. Value must match the one in req.
+ * @param sapConnectRsp Connection Status
+ * @param maxMsgSizeBytes MaxMsgSize supported by server if request cannot be fulfilled.
+ * Valid only if connectResponse is SapConnectResponse:MSG_SIZE_TOO_LARGE.
+ */
+ void connectResponse(in int serial, in SapConnectRsp sapConnectRsp, in int maxMsgSizeBytes);
+
+ /**
+ * DISCONNECT_IND from SAP 1.1 spec 5.1.5
+ *
+ * @param serial Id to match req-resp. Value must match the one in req.
+ * @param disconnectType Disconnect Type to indicate if shutdown is graceful or immediate
+ */
+ void disconnectIndication(in int serial, in SapDisconnectType disconnectType);
+
+ /**
+ * DISCONNECT_RESP from SAP 1.1 spec 5.1.4
+ *
+ * @param serial Id to match req-resp. Value must match the one in req.
+ */
+ void disconnectResponse(in int serial);
+
+ /**
+ * ERROR_RESP from SAP 1.1 spec 5.1.19
+ *
+ * @param serial Id to match req-resp. Value must match the one in req.
+ */
+ void errorResponse(in int serial);
+
+ /**
+ * POWER_SIM_OFF_RESP and POWER_SIM_ON_RESP from SAP 1.1 spec 5.1.11 + 5.1.13
+ *
+ * @param serial Id to match req-resp. Value must match the one in req.
+ * @param resultCode ResultCode to indicate if command was processed correctly
+ * Possible values:
+ * SapResultCode:SUCCESS,
+ * SapResultCode:GENERIC_FAILURE,
+ * SapResultCode:CARD_NOT_ACCESSSIBLE, (possible only for power on req)
+ * SapResultCode:CARD_ALREADY_POWERED_OFF, (possible only for power off req)
+ * SapResultCode:CARD_REMOVED,
+ * SapResultCode:CARD_ALREADY_POWERED_ON (possible only for power on req)
+ */
+ void powerResponse(in int serial, in SapResultCode resultCode);
+
+ /**
+ * RESET_SIM_RESP from SAP 1.1 spec 5.1.15
+ *
+ * @param serial Id to match req-resp. Value must match the one in req.
+ * @param resultCode ResultCode to indicate if command was processed correctly
+ * Possible values:
+ * SapResultCode:SUCCESS,
+ * SapResultCode:GENERIC_FAILURE,
+ * SapResultCode:CARD_NOT_ACCESSSIBLE,
+ * SapResultCode:CARD_ALREADY_POWERED_OFF,
+ * SapResultCode:CARD_REMOVED
+ */
+ void resetSimResponse(in int serial, in SapResultCode resultCode);
+
+ /**
+ * STATUS_IND from SAP 1.1 spec 5.1.16
+ *
+ * @param serial Id to match req-resp. Value must match the one in req.
+ * @param status Parameter to indicate reason for the status change.
+ */
+ void statusIndication(in int serial, in SapStatus status);
+
+ /**
+ * TRANSFER_ATR_RESP from SAP 1.1 spec 5.1.9
+ *
+ * @param serial Id to match req-resp. Value must match the one in req.
+ * @param resultCode ResultCode to indicate if command was processed correctly
+ * Possible values:
+ * SapResultCode:SUCCESS,
+ * SapResultCode:GENERIC_FAILURE,
+ * SapResultCode:CARD_ALREADY_POWERED_OFF,
+ * SapResultCode:CARD_REMOVED,
+ * SapResultCode:DATA_NOT_AVAILABLE
+ * @param atr Answer to Reset from the subscription module. Included only if no error occurred,
+ * otherwise empty.
+ */
+ void transferAtrResponse(in int serial, in SapResultCode resultCode, in byte[] atr);
+
+ /**
+ * TRANSFER_CARD_READER_STATUS_REQ from SAP 1.1 spec 5.1.18
+ *
+ * @param serial Id to match req-resp. Value must match the one in req.
+ * @param resultCode ResultCode to indicate if command was processed correctly
+ * Possible values:
+ * SapResultCode:SUCCESS,
+ * SapResultCode:GENERIC_FAILURE
+ * SapResultCode:DATA_NOT_AVAILABLE
+ * @param cardReaderStatus Card Reader Status coded as described in 3GPP TS 11.14 Section 12.33
+ * and TS 31.111 Section 8.33
+ */
+ void transferCardReaderStatusResponse(
+ in int serial, in SapResultCode resultCode, in int cardReaderStatus);
+
+ /**
+ * SET_TRANSPORT_PROTOCOL_RESP from SAP 1.1 spec 5.1.21
+ *
+ * @param serial Id to match req-resp. Value must match the one in req.
+ * @param resultCode ResultCode to indicate if command was processed correctly
+ * Possible values:
+ * SapResultCode:SUCCESS
+ * SapResultCode:NOT_SUPPORTED
+ */
+ void transferProtocolResponse(in int serial, in SapResultCode resultCode);
+}
diff --git a/radio/aidl/android/hardware/radio/sap/SapApduType.aidl b/radio/aidl/android/hardware/radio/sap/SapApduType.aidl
new file mode 100644
index 0000000..ab8ffb9
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/sap/SapApduType.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.radio.sap;
+
+@VintfStability
+@Backing(type="int")
+enum SapApduType {
+ APDU,
+ APDU7816,
+}
diff --git a/radio/aidl/android/hardware/radio/sap/SapConnectRsp.aidl b/radio/aidl/android/hardware/radio/sap/SapConnectRsp.aidl
new file mode 100644
index 0000000..0e1d528
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/sap/SapConnectRsp.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.radio.sap;
+
+@VintfStability
+@Backing(type="int")
+enum SapConnectRsp {
+ SUCCESS,
+ CONNECT_FAILURE,
+ MSG_SIZE_TOO_LARGE,
+ MSG_SIZE_TOO_SMALL,
+ CONNECT_OK_CALL_ONGOING,
+}
diff --git a/radio/aidl/android/hardware/radio/sap/SapDisconnectType.aidl b/radio/aidl/android/hardware/radio/sap/SapDisconnectType.aidl
new file mode 100644
index 0000000..16d7cc6
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/sap/SapDisconnectType.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.radio.sap;
+
+@VintfStability
+@Backing(type="int")
+enum SapDisconnectType {
+ GRACEFUL,
+ IMMEDIATE,
+}
diff --git a/radio/aidl/android/hardware/radio/sap/SapResultCode.aidl b/radio/aidl/android/hardware/radio/sap/SapResultCode.aidl
new file mode 100644
index 0000000..4728ebe
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/sap/SapResultCode.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.radio.sap;
+
+@VintfStability
+@Backing(type="int")
+enum SapResultCode {
+ SUCCESS,
+ GENERIC_FAILURE,
+ CARD_NOT_ACCESSSIBLE,
+ CARD_ALREADY_POWERED_OFF,
+ CARD_REMOVED,
+ CARD_ALREADY_POWERED_ON,
+ DATA_NOT_AVAILABLE,
+ NOT_SUPPORTED,
+}
diff --git a/radio/aidl/android/hardware/radio/sap/SapStatus.aidl b/radio/aidl/android/hardware/radio/sap/SapStatus.aidl
new file mode 100644
index 0000000..309352d
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/sap/SapStatus.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.radio.sap;
+
+@VintfStability
+@Backing(type="int")
+enum SapStatus {
+ UNKNOWN_ERROR,
+ CARD_RESET,
+ CARD_NOT_ACCESSIBLE,
+ CARD_REMOVED,
+ CARD_INSERTED,
+ RECOVERED,
+}
diff --git a/radio/aidl/android/hardware/radio/sap/SapTransferProtocol.aidl b/radio/aidl/android/hardware/radio/sap/SapTransferProtocol.aidl
new file mode 100644
index 0000000..823c5f2
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/sap/SapTransferProtocol.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.radio.sap;
+
+@VintfStability
+@Backing(type="int")
+enum SapTransferProtocol {
+ T0,
+ T1,
+}
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/CarrierRestrictions.aidl b/radio/aidl/android/hardware/radio/sim/CarrierRestrictions.aidl
index 3dce907..5a79f0f 100644
--- a/radio/aidl/android/hardware/radio/sim/CarrierRestrictions.aidl
+++ b/radio/aidl/android/hardware/radio/sim/CarrierRestrictions.aidl
@@ -21,6 +21,22 @@
@VintfStability
@JavaDerive(toString=true)
parcelable CarrierRestrictions {
+ @VintfStability
+ @Backing(type="int")
+ /** This enum defines the carrier restriction status values */
+ enum CarrierRestrictionStatus {
+ /**
+ * Carrier restriction status value is unknown, used in cases where modem is dependent on
+ * external module to know about the lock status and the module hasn’t yet provided the lock
+ * status. For example, when the lock status is maintained on a cloud server and device has
+ * just booted after out of box and not yet connected to the internet.
+ */
+ UNKNOWN = 0,
+ /** There is no carrier restriction on the device */
+ NOT_RESTRICTED = 1,
+ /** The device is restricted to a carrier */
+ RESTRICTED = 2,
+ }
/**
* Allowed carriers
*/
@@ -40,4 +56,11 @@
* and not in the allowed list.
*/
boolean allowedCarriersPrioritized;
+ /** Current restriction status as defined in CarrierRestrictionStatus enum */
+ CarrierRestrictionStatus status;
+ /**
+ * Android carrier ID of the locked carrier.
+ * see https://source.android.com/docs/core/connect/carrierid
+ */
+ int carrierId;
}
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/Android.bp b/radio/aidl/compat/libradiocompat/Android.bp
index c40ca30..95953ac 100644
--- a/radio/aidl/compat/libradiocompat/Android.bp
+++ b/radio/aidl/compat/libradiocompat/Android.bp
@@ -41,6 +41,7 @@
"android.hardware.radio.messaging-V2-ndk",
"android.hardware.radio.modem-V2-ndk",
"android.hardware.radio.network-V2-ndk",
+ "android.hardware.radio.sap-V1-ndk",
"android.hardware.radio.sim-V2-ndk",
"android.hardware.radio.voice-V2-ndk",
"android.hardware.radio@1.0",
@@ -86,6 +87,9 @@
"network/RadioResponse-network.cpp",
"network/structs.cpp",
"network/utils.cpp",
+ "sap/Sap.cpp",
+ "sap/SapCallback.cpp",
+ "sap/structs.cpp",
"sim/RadioIndication-sim.cpp",
"sim/RadioResponse-sim.cpp",
"sim/RadioSim.cpp",
diff --git a/radio/aidl/compat/libradiocompat/commonStructs.cpp b/radio/aidl/compat/libradiocompat/commonStructs.cpp
index 6e4c873..d65ed1a 100644
--- a/radio/aidl/compat/libradiocompat/commonStructs.cpp
+++ b/radio/aidl/compat/libradiocompat/commonStructs.cpp
@@ -48,6 +48,10 @@
return v;
}
+uint8_t toHidl(int8_t v) {
+ return v;
+}
+
aidl::RadioIndicationType toAidl(V1_0::RadioIndicationType type) {
return aidl::RadioIndicationType(type);
}
diff --git a/radio/aidl/compat/libradiocompat/commonStructs.h b/radio/aidl/compat/libradiocompat/commonStructs.h
index a4a4869..f43a599 100644
--- a/radio/aidl/compat/libradiocompat/commonStructs.h
+++ b/radio/aidl/compat/libradiocompat/commonStructs.h
@@ -28,6 +28,7 @@
uint8_t toAidl(int8_t v);
int8_t toAidl(uint8_t v);
int32_t toAidl(uint32_t v);
+uint8_t toHidl(int8_t v);
aidl::android::hardware::radio::RadioIndicationType toAidl(V1_0::RadioIndicationType type);
aidl::android::hardware::radio::RadioResponseType toAidl(V1_0::RadioResponseType type);
diff --git a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioModem.h b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioModem.h
index beb1fb0..54bedd8 100644
--- a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioModem.h
+++ b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioModem.h
@@ -26,6 +26,7 @@
::ndk::ScopedAStatus enableModem(int32_t serial, bool on) override;
::ndk::ScopedAStatus getBasebandVersion(int32_t serial) override;
::ndk::ScopedAStatus getDeviceIdentity(int32_t serial) override;
+ ::ndk::ScopedAStatus getImei(int32_t serial) override;
::ndk::ScopedAStatus getHardwareConfig(int32_t serial) override;
::ndk::ScopedAStatus getModemActivityInfo(int32_t serial) override;
::ndk::ScopedAStatus getModemStackStatus(int32_t serial) override;
diff --git a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioNetwork.h b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioNetwork.h
index b446103..7dbb27b 100644
--- a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioNetwork.h
+++ b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioNetwork.h
@@ -18,6 +18,9 @@
#include "RadioCompatBase.h"
#include <aidl/android/hardware/radio/network/BnRadioNetwork.h>
+#include <aidl/android/hardware/radio/network/IRadioNetwork.h>
+
+// using namespace aidl::android::hardware::radio::network;
namespace android::hardware::radio::compat {
@@ -103,6 +106,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/include/libradiocompat/Sap.h b/radio/aidl/compat/libradiocompat/include/libradiocompat/Sap.h
new file mode 100644
index 0000000..a293d11
--- /dev/null
+++ b/radio/aidl/compat/libradiocompat/include/libradiocompat/Sap.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 "RadioCompatBase.h"
+#include "SapCallback.h"
+
+#include <aidl/android/hardware/radio/sap/BnSap.h>
+#include <android/hardware/radio/1.0/ISap.h>
+#include <android/hardware/radio/1.0/ISapCallback.h>
+
+namespace android::hardware::radio::compat {
+
+/**
+ * HAL translator from HIDL ISap to AIDL ISap
+ *
+ * This class wraps existing HIDL implementation (either a binder stub or real
+ * class implementing the HAL) and implements AIDL HAL. It's up to the caller to
+ * fetch source implementation and publish resulting HAL instance.
+ */
+class Sap : public aidl::android::hardware::radio::sap::BnSap {
+ const sp<radio::V1_0::ISap> mHal;
+
+ const sp<SapCallback> mSapCallback;
+
+ ::ndk::ScopedAStatus apduReq(int32_t serial,
+ aidl::android::hardware::radio::sap::SapApduType type,
+ const std::vector<uint8_t>& command) override;
+ ::ndk::ScopedAStatus connectReq(int32_t serial, int32_t maxMsgSize) override;
+ ::ndk::ScopedAStatus disconnectReq(int32_t serial) override;
+ ::ndk::ScopedAStatus powerReq(int32_t serial, bool state) override;
+ ::ndk::ScopedAStatus resetSimReq(int32_t serial) override;
+ ::ndk::ScopedAStatus setCallback(
+ const std::shared_ptr<::aidl::android::hardware::radio::sap::ISapCallback>& sapCallback)
+ override;
+ ::ndk::ScopedAStatus setTransferProtocolReq(
+ int32_t serial,
+ aidl::android::hardware::radio::sap::SapTransferProtocol transferProtocol) override;
+ ::ndk::ScopedAStatus transferAtrReq(int32_t serial) override;
+ ::ndk::ScopedAStatus transferCardReaderStatusReq(int32_t serial) override;
+
+ public:
+ /**
+ * Constructs AIDL ISap instance wrapping existing HIDL ISap instance.
+ *
+ * \param hidlHal existing HIDL ISap HAL instance
+ */
+ Sap(sp<V1_0::ISap> hidlHal);
+};
+
+} // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/libradiocompat/include/libradiocompat/SapCallback.h b/radio/aidl/compat/libradiocompat/include/libradiocompat/SapCallback.h
new file mode 100644
index 0000000..7e72106
--- /dev/null
+++ b/radio/aidl/compat/libradiocompat/include/libradiocompat/SapCallback.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 "GuaranteedCallback.h"
+
+#include <aidl/android/hardware/radio/sap/ISapCallback.h>
+#include <android/hardware/radio/1.0/ISapCallback.h>
+
+namespace android::hardware::radio::compat {
+
+class SapCallback : public V1_0::ISapCallback {
+ GuaranteedCallback<aidl::android::hardware::radio::sap::ISapCallback,
+ aidl::android::hardware::radio::sap::ISapCallbackDefault>
+ mCallback;
+
+ Return<void> apduResponse(int32_t serial, V1_0::SapResultCode resultCode,
+ const ::android::hardware::hidl_vec<uint8_t>& apduRsp) override;
+ Return<void> connectResponse(int32_t serial, V1_0::SapConnectRsp sapConnectRsp,
+ int32_t maxMsgSize) override;
+ Return<void> disconnectIndication(int32_t serial,
+ V1_0::SapDisconnectType disconnectType) override;
+ Return<void> disconnectResponse(int32_t serial) override;
+ Return<void> errorResponse(int32_t serial) override;
+ Return<void> powerResponse(int32_t serial, V1_0::SapResultCode resultCode) override;
+ Return<void> resetSimResponse(int32_t serial, V1_0::SapResultCode resultCode) override;
+ Return<void> statusIndication(int32_t serial, V1_0::SapStatus status) override;
+ Return<void> transferAtrResponse(int32_t serial, V1_0::SapResultCode resultCode,
+ const ::android::hardware::hidl_vec<uint8_t>& atr) override;
+ Return<void> transferCardReaderStatusResponse(int32_t serial, V1_0::SapResultCode resultCode,
+ int32_t cardReaderStatus) override;
+ Return<void> transferProtocolResponse(int32_t serial, V1_0::SapResultCode resultCode) override;
+
+ public:
+ void setResponseFunction(
+ const std::shared_ptr<aidl::android::hardware::radio::sap::ISapCallback>& callback);
+
+ std::shared_ptr<aidl::android::hardware::radio::sap::ISapCallback> respond();
+};
+
+} // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/libradiocompat/modem/RadioModem.cpp b/radio/aidl/compat/libradiocompat/modem/RadioModem.cpp
index d28b940..f088b10 100644
--- a/radio/aidl/compat/libradiocompat/modem/RadioModem.cpp
+++ b/radio/aidl/compat/libradiocompat/modem/RadioModem.cpp
@@ -15,7 +15,7 @@
*/
#include <libradiocompat/RadioModem.h>
-
+#include "commonStructs.h"
#include "debug.h"
#include "structs.h"
@@ -49,6 +49,13 @@
return ok();
}
+ScopedAStatus RadioModem::getImei(int32_t serial) {
+ LOG_CALL << serial;
+ LOG(ERROR) << " getImei is unsupported by HIDL HALs";
+ respond()->getImeiResponse(notSupported(serial), {});
+ return ok();
+}
+
ScopedAStatus RadioModem::getHardwareConfig(int32_t serial) {
LOG_CALL << serial;
mHal1_5->getHardwareConfig(serial);
diff --git a/radio/aidl/compat/libradiocompat/network/RadioNetwork.cpp b/radio/aidl/compat/libradiocompat/network/RadioNetwork.cpp
index 730b5dd..e6a44d1 100644
--- a/radio/aidl/compat/libradiocompat/network/RadioNetwork.cpp
+++ b/radio/aidl/compat/libradiocompat/network/RadioNetwork.cpp
@@ -261,6 +261,11 @@
if (infos.size() > 1) {
LOG(WARNING) << "Multi-element reporting criteria are not supported with HIDL HAL";
}
+ if (infos[0].signalMeasurement == aidl::SignalThresholdInfo::SIGNAL_MEASUREMENT_TYPE_ECNO) {
+ LOG(WARNING) << "SIGNAL_MEASUREMENT_TYPE_ECNO are not supported with HIDL HAL";
+ respond()->setSignalStrengthReportingCriteriaResponse(notSupported(serial));
+ return ok();
+ }
mHal1_5->setSignalStrengthReportingCriteria_1_5(serial, toHidl(infos[0]),
V1_5::AccessNetwork(infos[0].ran));
return ok();
@@ -347,6 +352,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/compat/libradiocompat/sap/Sap.cpp b/radio/aidl/compat/libradiocompat/sap/Sap.cpp
new file mode 100644
index 0000000..1a77169
--- /dev/null
+++ b/radio/aidl/compat/libradiocompat/sap/Sap.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <libradiocompat/Sap.h>
+
+#include "commonStructs.h"
+#include "debug.h"
+#include "structs.h"
+
+#include "collections.h"
+
+#define RADIO_MODULE "Sap"
+
+namespace android::hardware::radio::compat {
+
+using ::ndk::ScopedAStatus;
+namespace aidl = ::aidl::android::hardware::radio::sap;
+constexpr auto ok = &ScopedAStatus::ok;
+
+Sap::Sap(sp<V1_0::ISap> hidlHal) : mHal(hidlHal), mSapCallback(sp<SapCallback>::make()) {}
+
+ScopedAStatus Sap::apduReq(int32_t serial, aidl::SapApduType type,
+ const std::vector<uint8_t>& command) {
+ LOG_CALL << serial;
+ mHal->apduReq(serial, toHidl(type), toHidl(command));
+ return ok();
+}
+
+ScopedAStatus Sap::connectReq(int32_t serial, int32_t maxMsgSize) {
+ LOG_CALL << serial;
+ mHal->connectReq(serial, maxMsgSize);
+ return ok();
+}
+
+ScopedAStatus Sap::disconnectReq(int32_t serial) {
+ LOG_CALL << serial;
+ mHal->disconnectReq(serial);
+ return ok();
+}
+
+ScopedAStatus Sap::powerReq(int32_t serial, bool state) {
+ LOG_CALL << serial;
+ mHal->powerReq(serial, state);
+ return ok();
+}
+
+ScopedAStatus Sap::resetSimReq(int32_t serial) {
+ LOG_CALL << serial;
+ mHal->resetSimReq(serial);
+ return ok();
+}
+
+ScopedAStatus Sap::setCallback(
+ const std::shared_ptr<::aidl::android::hardware::radio::sap::ISapCallback>& sapCallback) {
+ LOG_CALL << sapCallback;
+
+ CHECK(sapCallback);
+
+ mSapCallback->setResponseFunction(sapCallback);
+ mHal->setCallback(mSapCallback).assertOk();
+ return ok();
+}
+ScopedAStatus Sap::setTransferProtocolReq(int32_t serial,
+ aidl::SapTransferProtocol transferProtocol) {
+ LOG_CALL << serial;
+ mHal->setTransferProtocolReq(serial, toHidl(transferProtocol));
+ return ok();
+}
+
+ScopedAStatus Sap::transferAtrReq(int32_t serial) {
+ LOG_CALL << serial;
+ mHal->transferAtrReq(serial);
+ return ok();
+}
+ScopedAStatus Sap::transferCardReaderStatusReq(int32_t serial) {
+ LOG_CALL << serial;
+ mHal->transferCardReaderStatusReq(serial);
+ return ok();
+}
+
+} // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/libradiocompat/sap/SapCallback.cpp b/radio/aidl/compat/libradiocompat/sap/SapCallback.cpp
new file mode 100644
index 0000000..a40dff8
--- /dev/null
+++ b/radio/aidl/compat/libradiocompat/sap/SapCallback.cpp
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <libradiocompat/SapCallback.h>
+
+#include "commonStructs.h"
+#include "debug.h"
+#include "structs.h"
+
+#include "collections.h"
+
+#define RADIO_MODULE "SapCallback"
+
+namespace android::hardware::radio::compat {
+
+namespace aidl = ::aidl::android::hardware::radio::sap;
+
+void SapCallback::setResponseFunction(const std::shared_ptr<aidl::ISapCallback>& callback) {
+ mCallback = callback;
+}
+
+std::shared_ptr<aidl::ISapCallback> SapCallback::respond() {
+ return mCallback.get();
+}
+
+Return<void> SapCallback::apduResponse(int32_t serial, V1_0::SapResultCode resultCode,
+ const hidl_vec<uint8_t>& apduRsp) {
+ LOG_CALL << serial;
+ respond()->apduResponse(serial, toAidl(resultCode), apduRsp);
+ return {};
+}
+
+Return<void> SapCallback::connectResponse(int32_t serial, V1_0::SapConnectRsp sapConnectRsp,
+ int32_t maxMsgSize) {
+ LOG_CALL << serial;
+ respond()->connectResponse(serial, toAidl(sapConnectRsp), maxMsgSize);
+ return {};
+}
+
+Return<void> SapCallback::disconnectIndication(int32_t serial,
+ V1_0::SapDisconnectType disconnectType) {
+ LOG_CALL << serial;
+ respond()->disconnectIndication(serial, toAidl(disconnectType));
+ return {};
+}
+
+Return<void> SapCallback::disconnectResponse(int32_t serial) {
+ LOG_CALL << serial;
+ respond()->disconnectResponse(serial);
+ return {};
+}
+
+Return<void> SapCallback::errorResponse(int32_t serial) {
+ LOG_CALL << serial;
+ respond()->errorResponse(serial);
+ return {};
+}
+
+Return<void> SapCallback::powerResponse(int32_t serial, V1_0::SapResultCode resultCode) {
+ LOG_CALL << serial;
+ respond()->powerResponse(serial, toAidl(resultCode));
+ return {};
+}
+
+Return<void> SapCallback::resetSimResponse(int32_t serial, V1_0::SapResultCode resultCode) {
+ LOG_CALL << serial;
+ respond()->resetSimResponse(serial, toAidl(resultCode));
+ return {};
+}
+
+Return<void> SapCallback::statusIndication(int32_t serial, V1_0::SapStatus status) {
+ LOG_CALL << serial;
+ respond()->statusIndication(serial, toAidl(status));
+ return {};
+}
+
+Return<void> SapCallback::transferAtrResponse(int32_t serial, V1_0::SapResultCode resultCode,
+ const hidl_vec<uint8_t>& atr) {
+ LOG_CALL << serial;
+ respond()->transferAtrResponse(serial, toAidl(resultCode), atr);
+ return {};
+}
+
+Return<void> SapCallback::transferCardReaderStatusResponse(int32_t serial,
+ V1_0::SapResultCode resultCode,
+ int32_t cardReaderStatus) {
+ LOG_CALL << serial;
+ respond()->transferCardReaderStatusResponse(serial, toAidl(resultCode), cardReaderStatus);
+ return {};
+}
+
+Return<void> SapCallback::transferProtocolResponse(int32_t serial, V1_0::SapResultCode resultCode) {
+ LOG_CALL << serial;
+ respond()->transferProtocolResponse(serial, toAidl(resultCode));
+ return {};
+}
+
+} // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/libradiocompat/sap/structs.cpp b/radio/aidl/compat/libradiocompat/sap/structs.cpp
new file mode 100644
index 0000000..522056b
--- /dev/null
+++ b/radio/aidl/compat/libradiocompat/sap/structs.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "structs.h"
+
+namespace android::hardware::radio::compat {
+
+namespace aidl = ::aidl::android::hardware::radio::sap;
+
+V1_0::SapApduType toHidl(const aidl::SapApduType sapApduType) {
+ return V1_0::SapApduType(sapApduType);
+}
+
+V1_0::SapTransferProtocol toHidl(const aidl::SapTransferProtocol sapTransferProtocol) {
+ return V1_0::SapTransferProtocol(sapTransferProtocol);
+}
+
+aidl::SapResultCode toAidl(const V1_0::SapResultCode sapResultCode) {
+ return aidl::SapResultCode(sapResultCode);
+}
+
+aidl::SapConnectRsp toAidl(const V1_0::SapConnectRsp sapConnectRsp) {
+ return aidl::SapConnectRsp(sapConnectRsp);
+}
+
+aidl::SapDisconnectType toAidl(const V1_0::SapDisconnectType sapDisconnectType) {
+ return aidl::SapDisconnectType(sapDisconnectType);
+}
+
+aidl::SapStatus toAidl(const V1_0::SapStatus sapStatus) {
+ return aidl::SapStatus(sapStatus);
+}
+
+} // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/libradiocompat/sap/structs.h b/radio/aidl/compat/libradiocompat/sap/structs.h
new file mode 100644
index 0000000..d88120d
--- /dev/null
+++ b/radio/aidl/compat/libradiocompat/sap/structs.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, eithe r express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <aidl/android/hardware/radio/sap/ISap.h>
+#include <android/hardware/radio/1.0/types.h>
+
+namespace android::hardware::radio::compat {
+
+V1_0::SapApduType toHidl(aidl::android::hardware::radio::sap::SapApduType sapAdpuType);
+V1_0::SapTransferProtocol toHidl(
+ aidl::android::hardware::radio::sap::SapTransferProtocol sapTransferProtocol);
+
+aidl::android::hardware::radio::sap::SapResultCode toAidl(V1_0::SapResultCode sapResultCode);
+aidl::android::hardware::radio::sap::SapConnectRsp toAidl(V1_0::SapConnectRsp sapConnectRsp);
+aidl::android::hardware::radio::sap::SapDisconnectType toAidl(
+ V1_0::SapDisconnectType sapDisconnectType);
+aidl::android::hardware::radio::sap::SapStatus toAidl(V1_0::SapStatus sapStatus);
+
+} // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/service/Android.bp b/radio/aidl/compat/service/Android.bp
index 7a48da2..56674c1 100644
--- a/radio/aidl/compat/service/Android.bp
+++ b/radio/aidl/compat/service/Android.bp
@@ -44,6 +44,7 @@
"android.hardware.radio.messaging-V2-ndk",
"android.hardware.radio.modem-V2-ndk",
"android.hardware.radio.network-V2-ndk",
+ "android.hardware.radio.sap-V1-ndk",
"android.hardware.radio.sim-V2-ndk",
"android.hardware.radio.voice-V2-ndk",
"android.hardware.radio@1.0",
diff --git a/radio/aidl/vts/Android.bp b/radio/aidl/vts/Android.bp
index 5a0dbd0..99c3d71 100644
--- a/radio/aidl/vts/Android.bp
+++ b/radio/aidl/vts/Android.bp
@@ -53,6 +53,8 @@
"radio_network_indication.cpp",
"radio_network_response.cpp",
"radio_network_test.cpp",
+ "radio_sap_callback.cpp",
+ "radio_sap_test.cpp",
"radio_sim_indication.cpp",
"radio_sim_response.cpp",
"radio_sim_test.cpp",
@@ -73,6 +75,7 @@
"android.hardware.radio.messaging-V2-ndk",
"android.hardware.radio.modem-V2-ndk",
"android.hardware.radio.network-V2-ndk",
+ "android.hardware.radio.sap-V1-ndk",
"android.hardware.radio.sim-V2-ndk",
"android.hardware.radio.voice-V2-ndk",
],
diff --git a/radio/aidl/vts/VtsHalRadioTargetTest.cpp b/radio/aidl/vts/VtsHalRadioTargetTest.cpp
index 67a2672..c25f930 100644
--- a/radio/aidl/vts/VtsHalRadioTargetTest.cpp
+++ b/radio/aidl/vts/VtsHalRadioTargetTest.cpp
@@ -22,6 +22,7 @@
#include "radio_messaging_utils.h"
#include "radio_modem_utils.h"
#include "radio_network_utils.h"
+#include "radio_sap_utils.h"
#include "radio_sim_utils.h"
#include "radio_voice_utils.h"
@@ -55,6 +56,11 @@
testing::ValuesIn(android::getAidlHalInstanceNames(IRadioNetwork::descriptor)),
android::PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(RadioSapTest);
+INSTANTIATE_TEST_SUITE_P(PerInstance, SapTest,
+ testing::ValuesIn(android::getAidlHalInstanceNames(ISap::descriptor)),
+ android::PrintInstanceNameToString);
+
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(RadioSimTest);
INSTANTIATE_TEST_SUITE_P(PerInstance, RadioSimTest,
testing::ValuesIn(android::getAidlHalInstanceNames(IRadioSim::descriptor)),
diff --git a/radio/aidl/vts/radio_modem_response.cpp b/radio/aidl/vts/radio_modem_response.cpp
index 20b44c5..050b2c8 100644
--- a/radio/aidl/vts/radio_modem_response.cpp
+++ b/radio/aidl/vts/radio_modem_response.cpp
@@ -46,6 +46,13 @@
return ndk::ScopedAStatus::ok();
}
+ndk::ScopedAStatus RadioModemResponse::getImeiResponse(const RadioResponseInfo& info,
+ const std::optional<ImeiInfo>& /*imeiInfo*/) {
+ rspInfo = info;
+ parent_modem.notify(info.serial);
+ return ndk::ScopedAStatus::ok();
+}
+
ndk::ScopedAStatus RadioModemResponse::getHardwareConfigResponse(
const RadioResponseInfo& info, const std::vector<HardwareConfig>& /*config*/) {
rspInfo = info;
diff --git a/radio/aidl/vts/radio_modem_test.cpp b/radio/aidl/vts/radio_modem_test.cpp
index f88da13..c00b238 100644
--- a/radio/aidl/vts/radio_modem_test.cpp
+++ b/radio/aidl/vts/radio_modem_test.cpp
@@ -188,6 +188,25 @@
}
/*
+ * Test IRadioModem.getImei() for the response returned.
+ */
+TEST_P(RadioModemTest, getImei) {
+ LOG(DEBUG) << "getImei";
+ serial = GetRandomSerialNumber();
+
+ radio_modem->getImei(serial);
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_modem->rspInfo.type);
+ EXPECT_EQ(serial, radioRsp_modem->rspInfo.serial);
+
+ if (cardStatus.cardState == CardStatus::STATE_ABSENT) {
+ ASSERT_TRUE(CheckAnyOfErrors(radioRsp_modem->rspInfo.error,
+ {RadioError::NONE, RadioError::EMPTY_RECORD}));
+ }
+ LOG(DEBUG) << "getImei finished";
+}
+
+/*
* Test IRadioModem.nvReadItem() for the response returned.
*/
TEST_P(RadioModemTest, nvReadItem) {
diff --git a/radio/aidl/vts/radio_modem_utils.h b/radio/aidl/vts/radio_modem_utils.h
index 49e1891..d2f5a10 100644
--- a/radio/aidl/vts/radio_modem_utils.h
+++ b/radio/aidl/vts/radio_modem_utils.h
@@ -19,6 +19,7 @@
#include <aidl/android/hardware/radio/modem/BnRadioModemIndication.h>
#include <aidl/android/hardware/radio/modem/BnRadioModemResponse.h>
#include <aidl/android/hardware/radio/modem/IRadioModem.h>
+#include <aidl/android/hardware/radio/modem/ImeiInfo.h>
#include "radio_aidl_hal_utils.h"
@@ -52,6 +53,9 @@
const std::string& esn,
const std::string& meid) override;
+ virtual ndk::ScopedAStatus getImeiResponse(const RadioResponseInfo& info,
+ const std::optional<ImeiInfo>& config) override;
+
virtual ndk::ScopedAStatus getHardwareConfigResponse(
const RadioResponseInfo& info, const std::vector<HardwareConfig>& config) override;
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..03127cd 100644
--- a/radio/aidl/vts/radio_network_test.cpp
+++ b/radio/aidl/vts/radio_network_test.cpp
@@ -356,7 +356,7 @@
/*
* Test IRadioNetwork.setSignalStrengthReportingCriteria() for UTRAN
*/
-TEST_P(RadioNetworkTest, setSignalStrengthReportingCriteria_Utran) {
+TEST_P(RadioNetworkTest, setSignalStrengthReportingCriteria_Utran_Rscp) {
serial = GetRandomSerialNumber();
SignalThresholdInfo signalThresholdInfo;
@@ -380,6 +380,33 @@
}
/*
+ * Test IRadioNetwork.setSignalStrengthReportingCriteria() for UTRAN
+ */
+TEST_P(RadioNetworkTest, setSignalStrengthReportingCriteria_Utran_Ecno) {
+ serial = GetRandomSerialNumber();
+
+ SignalThresholdInfo signalThresholdInfo;
+ signalThresholdInfo.signalMeasurement = SignalThresholdInfo::SIGNAL_MEASUREMENT_TYPE_ECNO;
+ signalThresholdInfo.hysteresisMs = 5000;
+ signalThresholdInfo.hysteresisDb = 2;
+ signalThresholdInfo.thresholds = {-22, -18, 0};
+ signalThresholdInfo.isEnabled = true;
+ signalThresholdInfo.ran = AccessNetwork::UTRAN;
+
+ ndk::ScopedAStatus res =
+ radio_network->setSignalStrengthReportingCriteria(serial, {signalThresholdInfo});
+ 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);
+
+ ALOGI("setSignalStrengthReportingCriteria_Utran, rspInfo.error = %s\n",
+ toString(radioRsp_network->rspInfo.error).c_str());
+ ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
+ {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED}));
+}
+
+/*
* Test IRadioNetwork.setSignalStrengthReportingCriteria() for EUTRAN
*/
TEST_P(RadioNetworkTest, setSignalStrengthReportingCriteria_Eutran_RSRP) {
@@ -1979,3 +2006,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/radio/aidl/vts/radio_sap_callback.cpp b/radio/aidl/vts/radio_sap_callback.cpp
new file mode 100644
index 0000000..3b21ede
--- /dev/null
+++ b/radio/aidl/vts/radio_sap_callback.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "radio_sap_utils.h"
+
+#include <android-base/logging.h>
+
+SapCallback::SapCallback(SapTest& parent) : parent_sap(parent) {}
+
+::ndk::ScopedAStatus SapCallback::apduResponse(int32_t serialNumber, SapResultCode resultCode,
+ const std::vector<uint8_t>& /*apduRsp*/) {
+ sapResponseSerial = serialNumber;
+ sapResultCode = resultCode;
+ parent_sap.notify(serialNumber);
+ return ndk::ScopedAStatus::ok();
+}
+::ndk::ScopedAStatus SapCallback::connectResponse(int32_t serialNumber,
+ SapConnectRsp /*sapConnectRsp*/,
+ int32_t /*maxMsgSize*/) {
+ sapResponseSerial = serialNumber;
+ parent_sap.notify(serialNumber);
+ return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus SapCallback::disconnectIndication(int32_t /*serialNumber*/,
+ SapDisconnectType /*sapDisconnectType*/) {
+ return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus SapCallback::disconnectResponse(int32_t serialNumber) {
+ sapResponseSerial = serialNumber;
+ parent_sap.notify(serialNumber);
+ return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus SapCallback::errorResponse(int32_t /*serialNumber*/) {
+ return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus SapCallback::powerResponse(int32_t serialNumber, SapResultCode resultCode) {
+ sapResponseSerial = serialNumber;
+ sapResultCode = resultCode;
+ parent_sap.notify(serialNumber);
+ return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus SapCallback::resetSimResponse(int32_t serialNumber, SapResultCode resultCode) {
+ sapResponseSerial = serialNumber;
+ sapResultCode = resultCode;
+ parent_sap.notify(serialNumber);
+ return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus SapCallback::statusIndication(int32_t /*serialNumber*/,
+ SapStatus /*sapStatus*/) {
+ return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus SapCallback::transferAtrResponse(int32_t serialNumber,
+ SapResultCode resultCode,
+ const std::vector<uint8_t>& /*atr*/) {
+ sapResponseSerial = serialNumber;
+ sapResultCode = resultCode;
+ parent_sap.notify(serialNumber);
+ return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus SapCallback::transferCardReaderStatusResponse(int32_t serialNumber,
+ SapResultCode resultCode,
+ int32_t /*cardReaderStatus*/) {
+ sapResponseSerial = serialNumber;
+ sapResultCode = resultCode;
+ parent_sap.notify(serialNumber);
+ return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus SapCallback::transferProtocolResponse(int32_t serialNumber,
+ SapResultCode resultCode) {
+ sapResponseSerial = serialNumber;
+ sapResultCode = resultCode;
+ parent_sap.notify(serialNumber);
+ return ndk::ScopedAStatus::ok();
+}
diff --git a/radio/aidl/vts/radio_sap_test.cpp b/radio/aidl/vts/radio_sap_test.cpp
new file mode 100644
index 0000000..c94379c
--- /dev/null
+++ b/radio/aidl/vts/radio_sap_test.cpp
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+
+#include "radio_sap_utils.h"
+
+#define ASSERT_OK(ret) ASSERT_TRUE((ret).isOk())
+#define TIMEOUT_PERIOD 40
+
+void SapTest::SetUp() {
+ std::string serviceName = GetParam();
+ if (!isServiceValidForDeviceConfiguration(serviceName)) {
+ LOG(DEBUG) << "Skipped the test due to device configuration.";
+ GTEST_SKIP();
+ }
+ sap = ISap::fromBinder(ndk::SpAIBinder(AServiceManager_waitForService(serviceName.c_str())));
+ ASSERT_NE(sap.get(), nullptr);
+
+ sapCb = ndk::SharedRefBase::make<SapCallback>(*this);
+ ASSERT_NE(sapCb.get(), nullptr);
+
+ count = 0;
+
+ ndk::ScopedAStatus res = sap->setCallback(sapCb);
+ ASSERT_OK(res) << res;
+}
+
+void SapTest::TearDown() {}
+
+::testing::AssertionResult SapTest::CheckAnyOfErrors(SapResultCode err,
+ std::vector<SapResultCode> errors) {
+ for (size_t i = 0; i < errors.size(); i++) {
+ if (err == errors[i]) {
+ return testing::AssertionSuccess();
+ }
+ }
+ return testing::AssertionFailure() << "SapError:" + toString(err) + " is returned";
+}
+
+void SapTest::notify(int receivedSerial) {
+ std::unique_lock<std::mutex> lock(mtx);
+ count++;
+ if (serial == receivedSerial) {
+ cv.notify_one();
+ }
+}
+
+std::cv_status SapTest::wait() {
+ std::unique_lock<std::mutex> lock(mtx);
+
+ std::cv_status status = std::cv_status::no_timeout;
+ auto now = std::chrono::system_clock::now();
+ while (count == 0) {
+ status = cv.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD));
+ if (status == std::cv_status::timeout) {
+ return status;
+ }
+ }
+ count--;
+ return status;
+}
+
+/*
+ * Test ISap.connectReq() for the response returned.
+ */
+TEST_P(SapTest, connectReq) {
+ LOG(DEBUG) << "connectReq";
+ serial = GetRandomSerialNumber();
+ int32_t maxMsgSize = 100;
+
+ ndk::ScopedAStatus res = sap->connectReq(serial, maxMsgSize);
+ ASSERT_OK(res) << res;
+
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(sapCb->sapResponseSerial, serial);
+
+ // Modem side need time for connect to finish. Adding a waiting time to prevent
+ // disconnect being requested right after connect request.
+ sleep(1);
+}
+
+/*
+ * Test ISap.disconnectReq() for the response returned
+ */
+TEST_P(SapTest, disconnectReq) {
+ LOG(DEBUG) << "disconnectReq";
+ serial = GetRandomSerialNumber();
+
+ ndk::ScopedAStatus res = sap->disconnectReq(serial);
+ ASSERT_OK(res) << res;
+
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(sapCb->sapResponseSerial, serial);
+ LOG(DEBUG) << "disconnectReq finished";
+}
+
+/*
+ * Test ISap.apduReq() for the response returned.
+ */
+TEST_P(SapTest, apduReq) {
+ LOG(DEBUG) << "apduReq";
+ serial = GetRandomSerialNumber();
+ SapApduType sapApduType = SapApduType::APDU;
+ std::vector<uint8_t> command = {};
+
+ ndk::ScopedAStatus res = sap->apduReq(serial, sapApduType, command);
+ ASSERT_OK(res) << res;
+
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(sapCb->sapResponseSerial, serial);
+
+ ASSERT_TRUE(CheckAnyOfErrors(
+ sapCb->sapResultCode,
+ {SapResultCode::GENERIC_FAILURE, SapResultCode::CARD_ALREADY_POWERED_OFF,
+ SapResultCode::CARD_NOT_ACCESSSIBLE, SapResultCode::CARD_REMOVED,
+ SapResultCode::SUCCESS}));
+ LOG(DEBUG) << "apduReq finished";
+}
+
+/*
+ * Test ISap.transferAtrReq() for the response returned.
+ */
+TEST_P(SapTest, transferAtrReq) {
+ LOG(DEBUG) << "transferAtrReq";
+ serial = GetRandomSerialNumber();
+
+ ndk::ScopedAStatus res = sap->transferAtrReq(serial);
+ ASSERT_OK(res) << res;
+
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(sapCb->sapResponseSerial, serial);
+
+ ASSERT_TRUE(CheckAnyOfErrors(sapCb->sapResultCode,
+ {SapResultCode::GENERIC_FAILURE, SapResultCode::DATA_NOT_AVAILABLE,
+ SapResultCode::CARD_ALREADY_POWERED_OFF,
+ SapResultCode::CARD_REMOVED, SapResultCode::SUCCESS}));
+ LOG(DEBUG) << "transferAtrReq finished";
+}
+
+/*
+ * Test ISap.powerReq() for the response returned.
+ */
+TEST_P(SapTest, powerReq) {
+ LOG(DEBUG) << "powerReq";
+ serial = GetRandomSerialNumber();
+ bool state = true;
+
+ ndk::ScopedAStatus res = sap->powerReq(serial, state);
+ ASSERT_OK(res) << res;
+
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(sapCb->sapResponseSerial, serial);
+
+ ASSERT_TRUE(
+ CheckAnyOfErrors(sapCb->sapResultCode,
+ {SapResultCode::GENERIC_FAILURE, SapResultCode::CARD_NOT_ACCESSSIBLE,
+ SapResultCode::CARD_ALREADY_POWERED_OFF, SapResultCode::CARD_REMOVED,
+ SapResultCode::CARD_ALREADY_POWERED_ON, SapResultCode::SUCCESS}));
+ LOG(DEBUG) << "powerReq finished";
+}
+
+/*
+ * Test ISap.resetSimReq() for the response returned.
+ */
+TEST_P(SapTest, resetSimReq) {
+ LOG(DEBUG) << "resetSimReq";
+ serial = GetRandomSerialNumber();
+
+ ndk::ScopedAStatus res = sap->resetSimReq(serial);
+ ASSERT_OK(res) << res;
+
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(sapCb->sapResponseSerial, serial);
+
+ ASSERT_TRUE(
+ CheckAnyOfErrors(sapCb->sapResultCode,
+ {SapResultCode::GENERIC_FAILURE, SapResultCode::CARD_NOT_ACCESSSIBLE,
+ SapResultCode::CARD_ALREADY_POWERED_OFF, SapResultCode::CARD_REMOVED,
+ SapResultCode::SUCCESS}));
+ LOG(DEBUG) << "resetSimReq finished";
+}
+
+/*
+ * Test ISap.transferCardReaderStatusReq() for the response returned.
+ */
+TEST_P(SapTest, transferCardReaderStatusReq) {
+ LOG(DEBUG) << "transferCardReaderStatusReq";
+ serial = GetRandomSerialNumber();
+
+ ndk::ScopedAStatus res = sap->transferCardReaderStatusReq(serial);
+ ASSERT_OK(res) << res;
+
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(sapCb->sapResponseSerial, serial);
+
+ ASSERT_TRUE(CheckAnyOfErrors(sapCb->sapResultCode,
+ {SapResultCode::GENERIC_FAILURE, SapResultCode::DATA_NOT_AVAILABLE,
+ SapResultCode::SUCCESS}));
+ LOG(DEBUG) << "transferCardReaderStatusReq finished";
+}
+
+/*
+ * Test ISap.setTransferProtocolReq() for the response returned.
+ */
+TEST_P(SapTest, setTransferProtocolReq) {
+ LOG(DEBUG) << "setTransferProtocolReq";
+ serial = GetRandomSerialNumber();
+ SapTransferProtocol sapTransferProtocol = SapTransferProtocol::T0;
+
+ ndk::ScopedAStatus res = sap->setTransferProtocolReq(serial, sapTransferProtocol);
+ ASSERT_OK(res) << res;
+
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(sapCb->sapResponseSerial, serial);
+
+ ASSERT_TRUE(CheckAnyOfErrors(sapCb->sapResultCode,
+ {SapResultCode::NOT_SUPPORTED, SapResultCode::SUCCESS}));
+ LOG(DEBUG) << "setTransferProtocolReq finished";
+}
diff --git a/radio/aidl/vts/radio_sap_utils.h b/radio/aidl/vts/radio_sap_utils.h
new file mode 100644
index 0000000..bf17006
--- /dev/null
+++ b/radio/aidl/vts/radio_sap_utils.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <aidl/Gtest.h>
+#include <aidl/android/hardware/radio/sap/BnSapCallback.h>
+#include <aidl/android/hardware/radio/sap/ISap.h>
+
+#include "radio_aidl_hal_utils.h"
+
+using namespace aidl::android::hardware::radio::sap;
+
+class SapTest;
+
+/* Callback class for radio sap response */
+class SapCallback : public BnSapCallback {
+ protected:
+ SapTest& parent_sap;
+
+ public:
+ SapCallback(SapTest& parent_config);
+ virtual ~SapCallback() = default;
+
+ int32_t sapResponseSerial;
+ SapResultCode sapResultCode;
+
+ virtual ::ndk::ScopedAStatus apduResponse(int32_t serial, SapResultCode resultCode,
+ const std::vector<uint8_t>& adpuRsp) override;
+
+ virtual ::ndk::ScopedAStatus connectResponse(int32_t serial, SapConnectRsp sapConnectRsp,
+ int32_t maxMsgSize) override;
+
+ virtual ::ndk::ScopedAStatus disconnectIndication(int32_t serial,
+ SapDisconnectType sapDisconnectType) override;
+
+ virtual ::ndk::ScopedAStatus disconnectResponse(int32_t serial) override;
+
+ virtual ::ndk::ScopedAStatus errorResponse(int32_t serial) override;
+
+ virtual ::ndk::ScopedAStatus powerResponse(int32_t serial, SapResultCode resultCode) override;
+
+ virtual ::ndk::ScopedAStatus resetSimResponse(int32_t serial,
+ SapResultCode resultCode) override;
+
+ virtual ::ndk::ScopedAStatus statusIndication(int32_t serial, SapStatus sapStatus) override;
+
+ virtual ::ndk::ScopedAStatus transferAtrResponse(int32_t serial, SapResultCode resultCode,
+ const std::vector<uint8_t>& atr) override;
+
+ virtual ::ndk::ScopedAStatus transferCardReaderStatusResponse(
+ int32_t serial, SapResultCode resultCode, int32_t cardReaderStatus) override;
+
+ virtual ::ndk::ScopedAStatus transferProtocolResponse(int32_t serial,
+ SapResultCode resultCode) override;
+};
+
+// The main test class for AIDL SAP.
+class SapTest : public ::testing::TestWithParam<std::string> {
+ private:
+ std::mutex mtx;
+ std::condition_variable cv;
+ int count;
+
+ public:
+ virtual void SetUp() override;
+
+ virtual void TearDown() override;
+
+ ::testing::AssertionResult CheckAnyOfErrors(SapResultCode err,
+ std::vector<SapResultCode> errors);
+
+ /* Used as a mechanism to inform the test about data/event callback */
+ void notify(int receivedSerial);
+
+ /* Test code calls this function to wait for response */
+ std::cv_status wait();
+
+ /* Sap service */
+ std::shared_ptr<ISap> sap;
+
+ /* Sap Callback object */
+ std::shared_ptr<SapCallback> sapCb;
+
+ /* Serial for sap request */
+ int32_t serial;
+};
diff --git a/secure_element/aidl/Android.bp b/secure_element/aidl/Android.bp
index 5a529a4..6450eb4 100644
--- a/secure_element/aidl/Android.bp
+++ b/secure_element/aidl/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
aidl_interface {
name: "android.hardware.secure_element",
vendor_available: true,
diff --git a/secure_element/aidl/default/Android.bp b/secure_element/aidl/default/Android.bp
index c604b68..d1bb393 100644
--- a/secure_element/aidl/default/Android.bp
+++ b/secure_element/aidl/default/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
cc_binary {
name: "android.hardware.secure_element-service.example",
relative_install_path: "hw",
diff --git a/security/keymint/aidl/Android.bp b/security/keymint/aidl/Android.bp
index 5a76a21..4753afb 100644
--- a/security/keymint/aidl/Android.bp
+++ b/security/keymint/aidl/Android.bp
@@ -71,6 +71,13 @@
],
}
+cc_defaults {
+ name: "keymint_use_latest_hal_aidl_cpp_shared",
+ shared_libs: [
+ "android.hardware.security.keymint-V3-cpp",
+ ],
+}
+
// A rust_defaults that includes the latest KeyMint AIDL library.
// Modules that depend on KeyMint directly can include this cc_defaults to avoid
// managing dependency versions explicitly.
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/security/keymint/aidl/vts/functional/Android.bp b/security/keymint/aidl/vts/functional/Android.bp
index 13143bf..e7f5a0f 100644
--- a/security/keymint/aidl/vts/functional/Android.bp
+++ b/security/keymint/aidl/vts/functional/Android.bp
@@ -90,24 +90,3 @@
"libgmock_ndk",
],
}
-
-cc_test {
- name: "VtsHalRemotelyProvisionedComponentTargetTest",
- defaults: [
- "keymint_vts_defaults",
- ],
- srcs: [
- "VtsRemotelyProvisionedComponentTests.cpp",
- ],
- static_libs: [
- "libgmock_ndk",
- "libkeymaster_portable",
- "libkeymint_vts_test_utils",
- "libpuresoftkeymasterdevice",
- ],
- test_config: "VtsRemotelyProvisionedComponentTests.xml",
- test_suites: [
- "general-tests",
- "vts",
- ],
-}
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index b8d0c20..5a86283 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -1027,7 +1027,7 @@
* without providing NOT_BEFORE and NOT_AFTER parameters.
*/
TEST_P(NewKeyGenerationTest, RsaWithMissingValidity) {
- if (AidlVersion() < 2) {
+ if (AidlVersion() < 3) {
/*
* The KeyMint V1 spec required that CERTIFICATE_NOT_{BEFORE,AFTER} be
* specified for asymmetric key generation. However, this was not
@@ -1130,16 +1130,16 @@
}
/*
- * NewKeyGenerationTest.RsaWithRpkAttestation
+ * NewKeyGenerationTest.RsaWithRkpAttestation
*
- * Verifies that keymint can generate all required RSA key sizes, using an attestation key
+ * Verifies that keymint can generate all required RSA key sizes using an attestation key
* that has been generated using an associate IRemotelyProvisionedComponent.
- *
- * This test is disabled because the KeyMint specification does not require that implementations
- * of the first version of KeyMint have to also implement IRemotelyProvisionedComponent.
- * However, the test is kept in the code because KeyMint v2 will impose this requirement.
*/
-TEST_P(NewKeyGenerationTest, DISABLED_RsaWithRpkAttestation) {
+TEST_P(NewKeyGenerationTest, RsaWithRkpAttestation) {
+ if (AidlVersion() < 2) {
+ GTEST_SKIP() << "Only required starting with KeyMint v2";
+ }
+
// There should be an IRemotelyProvisionedComponent instance associated with the KeyMint
// instance.
std::shared_ptr<IRemotelyProvisionedComponent> rp;
@@ -1208,6 +1208,81 @@
}
/*
+ * NewKeyGenerationTest.EcdsaWithRkpAttestation
+ *
+ * Verifies that keymint can generate all required ECDSA key sizes using an attestation key
+ * that has been generated using an associate IRemotelyProvisionedComponent.
+ */
+TEST_P(NewKeyGenerationTest, EcdsaWithRkpAttestation) {
+ if (AidlVersion() < 2) {
+ GTEST_SKIP() << "Only required starting with KeyMint v2";
+ }
+
+ // There should be an IRemotelyProvisionedComponent instance associated with the KeyMint
+ // instance.
+ std::shared_ptr<IRemotelyProvisionedComponent> rp;
+ ASSERT_TRUE(matching_rp_instance(GetParam(), &rp))
+ << "No IRemotelyProvisionedComponent found that matches KeyMint device " << GetParam();
+
+ // Generate a P-256 keypair to use as an attestation key.
+ MacedPublicKey macedPubKey;
+ std::vector<uint8_t> privateKeyBlob;
+ auto status =
+ rp->generateEcdsaP256KeyPair(/* testMode= */ false, &macedPubKey, &privateKeyBlob);
+ ASSERT_TRUE(status.isOk());
+ vector<uint8_t> coseKeyData;
+ check_maced_pubkey(macedPubKey, /* testMode= */ false, &coseKeyData);
+
+ AttestationKey attestation_key;
+ attestation_key.keyBlob = std::move(privateKeyBlob);
+ attestation_key.issuerSubjectName = make_name_from_str("Android Keystore Key");
+
+ for (auto curve : ValidCurves()) {
+ SCOPED_TRACE(testing::Message() << "Curve::" << curve);
+ auto challenge = "hello";
+ auto app_id = "foo";
+
+ vector<uint8_t> key_blob;
+ vector<KeyCharacteristics> key_characteristics;
+ ASSERT_EQ(ErrorCode::OK,
+ GenerateKey(AuthorizationSetBuilder()
+ .EcdsaSigningKey(curve)
+ .Digest(Digest::NONE)
+ .AttestationChallenge(challenge)
+ .AttestationApplicationId(app_id)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .SetDefaultValidity(),
+ attestation_key, &key_blob, &key_characteristics, &cert_chain_));
+
+ ASSERT_GT(key_blob.size(), 0U);
+ CheckBaseParams(key_characteristics);
+ CheckCharacteristics(key_blob, key_characteristics);
+
+ AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
+
+ EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::EC));
+ EXPECT_TRUE(crypto_params.Contains(TAG_EC_CURVE, curve)) << "Curve " << curve << "missing";
+
+ // Attestation by itself is not valid (last entry is not self-signed).
+ EXPECT_FALSE(ChainSignaturesAreValid(cert_chain_));
+
+ // The signature over the attested key should correspond to the P256 public key.
+ ASSERT_GT(cert_chain_.size(), 0);
+ X509_Ptr key_cert(parse_cert_blob(cert_chain_[0].encodedCertificate));
+ ASSERT_TRUE(key_cert.get());
+ EVP_PKEY_Ptr signing_pubkey;
+ p256_pub_key(coseKeyData, &signing_pubkey);
+ ASSERT_TRUE(signing_pubkey.get());
+
+ ASSERT_TRUE(X509_verify(key_cert.get(), signing_pubkey.get()))
+ << "Verification of attested certificate failed "
+ << "OpenSSL error string: " << ERR_error_string(ERR_get_error(), NULL);
+
+ CheckedDeleteKey(&key_blob);
+ }
+}
+
+/*
* NewKeyGenerationTest.RsaEncryptionWithAttestation
*
* Verifies that keymint attestation for RSA encryption keys with challenge and
diff --git a/security/rkp/CHANGELOG.md b/security/rkp/CHANGELOG.md
index c3e3609..715cf28 100644
--- a/security/rkp/CHANGELOG.md
+++ b/security/rkp/CHANGELOG.md
@@ -30,7 +30,8 @@
* `version` has moved to a top-level field within the CSR generated by the HAL.
* IRemotelyProvisionedComponent
* The need for an EEK has been removed. There is no longer an encrypted portion of the CSR.
- * Test mode has been removed.
+ * Keys for new CSR format must be generated with test mode set to false, effectively removing test
+ mode in the new CSR flow. Old behavior is kept unchanged for backwards compatibility.
* The schema for the CSR itself has been significantly simplified, please see
IRemotelyProvisionedComponent.aidl for more details. Notably,
* the chain of signing, MACing, and encryption operations has been replaced with a single
diff --git a/security/rkp/OWNERS b/security/rkp/OWNERS
new file mode 100644
index 0000000..d25977f
--- /dev/null
+++ b/security/rkp/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 1084908
+
+jbires@google.com
+sethmo@google.com
+trong@google.com
diff --git a/security/rkp/TEST_MAPPING b/security/rkp/TEST_MAPPING
new file mode 100644
index 0000000..9ce5e9b
--- /dev/null
+++ b/security/rkp/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "VtsHalRemotelyProvisionedComponentTargetTest"
+ }
+ ]
+}
diff --git a/security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl b/security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
index 2fc780c..5485db3 100644
--- a/security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
+++ b/security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
@@ -132,11 +132,7 @@
* generateKeyPair generates a new ECDSA P-256 key pair that can be attested by the remote
* server.
*
- * @param in boolean testMode this field is now deprecated. It is ignored by the implementation
- * in v3, but retained to simplify backwards compatibility support. V1 and V2
- * implementations must still respect the testMode flag.
- *
- * testMode indicates whether the generated key is for testing only. Test keys
+ * @param in boolean testMode indicates whether the generated key is for testing only. Test keys
* are marked (see the definition of PublicKey in the MacedPublicKey structure) to
* prevent them from being confused with production keys.
*
@@ -150,8 +146,8 @@
byte[] generateEcdsaP256KeyPair(in boolean testMode, out MacedPublicKey macedPublicKey);
/**
- * This method has been removed in version 3 of the HAL. The header is kept around for
- * backwards compatibility purposes. From v3, this method should raise a
+ * This method can be removed in version 3 of the HAL. The header is kept around for
+ * backwards compatibility purposes. From v3, this method is allowed to raise a
* ServiceSpecificException with an error code of STATUS_REMOVED.
*
* For v1 and v2 implementations:
@@ -306,7 +302,9 @@
*
* @param in MacedPublicKey[] keysToSign contains the set of keys to certify. The
* IRemotelyProvisionedComponent must validate the MACs on each key. If any entry in the
- * array lacks a valid MAC, the method must return STATUS_INVALID_MAC.
+ * array lacks a valid MAC, the method must return STATUS_INVALID_MAC. This method must
+ * not accept test keys. If any entry in the array is a test key, the method must return
+ * STATUS_TEST_KEY_IN_PRODUCTION_REQUEST.
*
* @param in challenge contains a byte string from the provisioning server which will be
* included in the signed data of the CSR structure. Different provisioned backends may
diff --git a/security/rkp/aidl/vts/functional/Android.bp b/security/rkp/aidl/vts/functional/Android.bp
new file mode 100644
index 0000000..9c2b6e1
--- /dev/null
+++ b/security/rkp/aidl/vts/functional/Android.bp
@@ -0,0 +1,44 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_test {
+ name: "VtsHalRemotelyProvisionedComponentTargetTest",
+ defaults: [
+ "keymint_vts_defaults",
+ ],
+ srcs: [
+ "VtsRemotelyProvisionedComponentTests.cpp",
+ ],
+ shared_libs: [
+ "libbinder_ndk",
+ "libcrypto",
+ ],
+ static_libs: [
+ "libcppbor_external",
+ "libgmock_ndk",
+ "libkeymint_vts_test_utils",
+ ],
+ test_config: "VtsRemotelyProvisionedComponentTests.xml",
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+}
diff --git a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.xml b/security/rkp/aidl/vts/functional/AndroidTest.xml
similarity index 100%
copy from security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.xml
copy to security/rkp/aidl/vts/functional/AndroidTest.xml
diff --git a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp b/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
similarity index 94%
rename from security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
rename to security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
index 97fe08a..aebcf67 100644
--- a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
+++ b/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
@@ -18,7 +18,7 @@
#include <string>
#define LOG_TAG "VtsRemotelyProvisionableComponentTests"
-#include <AndroidRemotelyProvisionedComponentDevice.h>
+#include <aidl/android/hardware/security/keymint/BnRemotelyProvisionedComponent.h>
#include <aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.h>
#include <aidl/android/hardware/security/keymint/SecurityLevel.h>
#include <android/binder_manager.h>
@@ -181,15 +181,6 @@
return params;
}
- void checkMacedPubkeyVersioned(const MacedPublicKey& macedPubKey, bool testMode,
- vector<uint8_t>* payload_value) {
- if (rpcHardwareInfo.versionNumber >= VERSION_WITHOUT_TEST_MODE) {
- check_maced_pubkey(macedPubKey, false, payload_value);
- } else {
- check_maced_pubkey(macedPubKey, testMode, payload_value);
- }
- }
-
protected:
std::shared_ptr<IRemotelyProvisionedComponent> provisionable_;
RpcHardwareInfo rpcHardwareInfo;
@@ -279,7 +270,7 @@
auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &macedPubKey, &privateKeyBlob);
ASSERT_TRUE(status.isOk());
vector<uint8_t> coseKeyData;
- checkMacedPubkeyVersioned(macedPubKey, testMode, &coseKeyData);
+ check_maced_pubkey(macedPubKey, testMode, &coseKeyData);
}
/**
@@ -302,7 +293,7 @@
auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &macedPubKey, &privateKeyBlob);
ASSERT_TRUE(status.isOk());
vector<uint8_t> coseKeyData;
- checkMacedPubkeyVersioned(macedPubKey, testMode, &coseKeyData);
+ check_maced_pubkey(macedPubKey, testMode, &coseKeyData);
AttestationKey attestKey;
attestKey.keyBlob = std::move(privateKeyBlob);
@@ -357,7 +348,7 @@
bool testMode = true;
auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &macedPubKey, &privateKeyBlob);
ASSERT_TRUE(status.isOk());
- checkMacedPubkeyVersioned(macedPubKey, testMode, nullptr);
+ check_maced_pubkey(macedPubKey, testMode, nullptr);
}
class CertificateRequestTestBase : public VtsRemotelyProvisionedComponentTests {
@@ -382,7 +373,7 @@
ASSERT_TRUE(status.isOk()) << status.getMessage();
vector<uint8_t> payload_value;
- checkMacedPubkeyVersioned(key, testMode, &payload_value);
+ check_maced_pubkey(key, testMode, &payload_value);
cborKeysToSign_.add(cppbor::EncodedItem(payload_value));
}
}
@@ -401,8 +392,16 @@
CertificateRequestTestBase::SetUp();
if (rpcHardwareInfo.versionNumber >= VERSION_WITHOUT_TEST_MODE) {
- GTEST_SKIP() << "This test case only applies to RKP v1 and v2. "
- << "RKP version discovered: " << rpcHardwareInfo.versionNumber;
+ bytevec keysToSignMac;
+ DeviceInfo deviceInfo;
+ ProtectedData protectedData;
+ auto status = provisionable_->generateCertificateRequest(
+ false, {}, {}, {}, &deviceInfo, &protectedData, &keysToSignMac);
+ if (!status.isOk() && (status.getServiceSpecificError() ==
+ BnRemotelyProvisionedComponent::STATUS_REMOVED)) {
+ GTEST_SKIP() << "This test case applies to RKP v3+ only if "
+ << "generateCertificateRequest() is implemented.";
+ }
}
}
};
@@ -769,32 +768,35 @@
}
/**
- * Generate a non-empty certificate request in prod mode, with test keys. Test mode must be
- * ignored, i.e. test must pass.
+ * Generate a non-empty certificate request in prod mode, with test keys. Must fail with
+ * STATUS_TEST_KEY_IN_PRODUCTION_REQUEST.
*/
TEST_P(CertificateRequestV2Test, NonEmptyRequest_testKeyInProdCert) {
generateKeys(true /* testMode */, 1 /* numKeys */);
bytevec csr;
auto status = provisionable_->generateCertificateRequestV2(keysToSign_, challenge_, &csr);
- ASSERT_TRUE(status.isOk()) << status.getMessage();
-}
-
-/**
- * Call generateCertificateRequest(). Make sure it's removed.
- */
-TEST_P(CertificateRequestV2Test, CertificateRequestV1Removed) {
- generateTestEekChain(2);
- bytevec keysToSignMac;
- DeviceInfo deviceInfo;
- ProtectedData protectedData;
- auto status = provisionable_->generateCertificateRequest(
- true /* testMode */, {} /* keysToSign */, testEekChain_.chain, challenge_, &deviceInfo,
- &protectedData, &keysToSignMac);
ASSERT_FALSE(status.isOk()) << status.getMessage();
- EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_REMOVED);
+ ASSERT_EQ(status.getServiceSpecificError(),
+ BnRemotelyProvisionedComponent::STATUS_TEST_KEY_IN_PRODUCTION_REQUEST);
}
INSTANTIATE_REM_PROV_AIDL_TEST(CertificateRequestV2Test);
+using VsrRequirementTest = VtsRemotelyProvisionedComponentTests;
+
+INSTANTIATE_REM_PROV_AIDL_TEST(VsrRequirementTest);
+
+TEST_P(VsrRequirementTest, VsrEnforcementTest) {
+ RpcHardwareInfo hwInfo;
+ ASSERT_TRUE(provisionable_->getHardwareInfo(&hwInfo).isOk());
+ int vsr_api_level = get_vsr_api_level();
+ if (vsr_api_level < 34) {
+ GTEST_SKIP() << "Applies only to VSR API level 34 or newer, this device is: "
+ << vsr_api_level;
+ }
+ EXPECT_GE(hwInfo.versionNumber, 3)
+ << "VSR 14+ requires IRemotelyProvisionedComponent v3 or newer.";
+}
+
} // namespace aidl::android::hardware::security::keymint::test
diff --git a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.xml b/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.xml
similarity index 100%
rename from security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.xml
rename to security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.xml
diff --git a/sensors/1.0/default/Android.bp b/sensors/1.0/default/Android.bp
index 2e4e1b0..bb31050 100644
--- a/sensors/1.0/default/Android.bp
+++ b/sensors/1.0/default/Android.bp
@@ -44,6 +44,12 @@
"libhidlbase",
"android.hardware.sensors@1.0",
],
+ whole_static_libs: [
+ "sensors_common_convert",
+ ],
+ export_static_lib_headers: [
+ "sensors_common_convert",
+ ],
local_include_dirs: ["include/sensors"],
export_shared_lib_headers: [
"libhardware",
diff --git a/sensors/1.0/default/convert.cpp b/sensors/1.0/default/convert.cpp
index 43ee327..ae71a97 100644
--- a/sensors/1.0/default/convert.cpp
+++ b/sensors/1.0/default/convert.cpp
@@ -196,6 +196,11 @@
}
}
+void convertFromASensorEvent(const ASensorEvent& src, Event* dst) {
+ convertFromSensorEvent(
+ android::hardware::sensors::implementation::common::convertASensorEvent(src), dst);
+}
+
void convertToSensorEvent(const Event &src, sensors_event_t *dst) {
*dst = {.version = sizeof(sensors_event_t),
.sensor = src.sensorHandle,
diff --git a/sensors/1.0/default/include/sensors/convert.h b/sensors/1.0/default/include/sensors/convert.h
index c3a0125..ae773df 100644
--- a/sensors/1.0/default/include/sensors/convert.h
+++ b/sensors/1.0/default/include/sensors/convert.h
@@ -20,6 +20,7 @@
#include <android/hardware/sensors/1.0/ISensors.h>
#include <hardware/sensors.h>
+#include <sensors/common_convert.h>
namespace android {
namespace hardware {
@@ -31,6 +32,7 @@
void convertToSensor(const SensorInfo &src, sensor_t *dst);
void convertFromSensorEvent(const sensors_event_t &src, Event *dst);
+void convertFromASensorEvent(const ASensorEvent& src, Event* dst);
void convertToSensorEvent(const Event &src, sensors_event_t *dst);
bool convertFromSharedMemInfo(const SharedMemInfo& memIn, sensors_direct_mem_t *memOut);
diff --git a/sensors/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 d47de8e..53060b9 100644
--- a/sensors/aidl/convert/Android.bp
+++ b/sensors/aidl/convert/Android.bp
@@ -35,7 +35,13 @@
"libhardware",
"libbase",
"libutils",
- "android.hardware.sensors-V1-ndk",
+ "android.hardware.sensors-V2-ndk",
+ ],
+ whole_static_libs: [
+ "sensors_common_convert",
+ ],
+ export_static_lib_headers: [
+ "sensors_common_convert",
],
local_include_dirs: ["include/aidl/sensors"],
export_shared_lib_headers: [
diff --git a/sensors/aidl/convert/convert.cpp b/sensors/aidl/convert/convert.cpp
index 415f435..abd4d55 100644
--- a/sensors/aidl/convert/convert.cpp
+++ b/sensors/aidl/convert/convert.cpp
@@ -490,6 +490,10 @@
}
}
+void convertFromASensorEvent(const ASensorEvent& src, Event* dst) {
+ convertFromSensorEvent(common::convertASensorEvent(src), dst);
+}
+
} // namespace implementation
} // namespace sensors
} // namespace hardware
diff --git a/sensors/aidl/convert/include/aidl/sensors/convert.h b/sensors/aidl/convert/include/aidl/sensors/convert.h
index 702b226..44504fe 100644
--- a/sensors/aidl/convert/include/aidl/sensors/convert.h
+++ b/sensors/aidl/convert/include/aidl/sensors/convert.h
@@ -18,6 +18,7 @@
#include <aidl/android/hardware/sensors/ISensors.h>
#include <hardware/sensors.h>
+#include <sensors/common_convert.h>
namespace android {
namespace hardware {
@@ -29,6 +30,7 @@
void convertToSensorEvent(const aidl::android::hardware::sensors::Event& src, sensors_event_t* dst);
void convertFromSensorEvent(const sensors_event_t& src,
aidl::android::hardware::sensors::Event* dst);
+void convertFromASensorEvent(const ASensorEvent& src, aidl::android::hardware::sensors::Event* dst);
} // namespace implementation
} // namespace sensors
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/sensors/common/convert/Android.bp b/sensors/common/convert/Android.bp
new file mode 100644
index 0000000..230665e
--- /dev/null
+++ b/sensors/common/convert/Android.bp
@@ -0,0 +1,42 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_library {
+ name: "sensors_common_convert",
+ srcs: [
+ "convert.cpp",
+ ],
+ vendor_available: true,
+ host_supported: true,
+ local_include_dirs: ["include"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ shared_libs: [
+ "libhardware",
+ ],
+ header_libs: [
+ "libandroid_sensor_headers",
+ ],
+
+ export_include_dirs: ["include"],
+ export_header_lib_headers: [
+ "libandroid_sensor_headers",
+ ],
+}
diff --git a/sensors/common/convert/convert.cpp b/sensors/common/convert/convert.cpp
new file mode 100644
index 0000000..27de32c
--- /dev/null
+++ b/sensors/common/convert/convert.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sensors/common_convert.h>
+#include <cstring>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace implementation {
+namespace common {
+
+sensors_event_t convertASensorEvent(const ASensorEvent& src) {
+ // Attempt to ensure these types are compatible.
+ static_assert(sizeof(sensors_event_t) == sizeof(ASensorEvent));
+ static_assert(offsetof(sensors_event_t, timestamp) == offsetof(ASensorEvent, timestamp));
+ static_assert(offsetof(sensors_event_t, flags) == offsetof(ASensorEvent, flags));
+
+ // TODO(b/259711109) Follow up work to handle this in a safer way.
+ return *reinterpret_cast<const sensors_event_t*>(&src);
+}
+
+} // namespace common
+} // namespace implementation
+} // namespace sensors
+} // namespace hardware
+} // namespace android
diff --git a/sensors/common/convert/include/sensors/common_convert.h b/sensors/common/convert/include/sensors/common_convert.h
new file mode 100644
index 0000000..a281369
--- /dev/null
+++ b/sensors/common/convert/include/sensors/common_convert.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/sensor.h>
+#include <hardware/sensors.h>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace implementation {
+namespace common {
+
+sensors_event_t convertASensorEvent(const ASensorEvent& aEvent);
+
+} // namespace common
+} // namespace implementation
+} // namespace sensors
+} // namespace hardware
+} // namespace android
diff --git a/sensors/common/default/2.X/multihal/HalProxy.cpp b/sensors/common/default/2.X/multihal/HalProxy.cpp
index 31a17db..305383e 100644
--- a/sensors/common/default/2.X/multihal/HalProxy.cpp
+++ b/sensors/common/default/2.X/multihal/HalProxy.cpp
@@ -351,7 +351,7 @@
return Return<void>();
}
-Return<void> HalProxy::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& /*args*/) {
+Return<void> HalProxy::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) {
if (fd.getNativeHandle() == nullptr || fd->numFds < 1) {
ALOGE("%s: missing fd for writing", __FUNCTION__);
return Void();
@@ -385,7 +385,7 @@
stream << " Name: " << subHal->getName() << std::endl;
stream << " Debug dump: " << std::endl;
android::base::WriteStringToFd(stream.str(), writeFd);
- subHal->debug(fd, {});
+ subHal->debug(fd, args);
stream.str("");
stream << std::endl;
}
diff --git a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/CoolingDevice.aidl b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/CoolingDevice.aidl
index 50be508..dfd8686 100644
--- a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/CoolingDevice.aidl
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/CoolingDevice.aidl
@@ -32,6 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.thermal;
+/* @hide */
@VintfStability
parcelable CoolingDevice {
android.hardware.thermal.CoolingType type;
diff --git a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/CoolingType.aidl b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/CoolingType.aidl
index 57c8939..d2eb389 100644
--- a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/CoolingType.aidl
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/CoolingType.aidl
@@ -32,6 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.thermal;
+/* @hide */
@Backing(type="int") @VintfStability
enum CoolingType {
FAN = 0,
diff --git a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/IThermal.aidl b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/IThermal.aidl
index 0aed5ec..c9b6cab 100644
--- a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/IThermal.aidl
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/IThermal.aidl
@@ -32,6 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.thermal;
+/* @hide */
@VintfStability
interface IThermal {
android.hardware.thermal.CoolingDevice[] getCoolingDevices();
diff --git a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/IThermalChangedCallback.aidl b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/IThermalChangedCallback.aidl
index 6b3f922..5e1d753 100644
--- a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/IThermalChangedCallback.aidl
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/IThermalChangedCallback.aidl
@@ -32,6 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.thermal;
+/* @hide */
@VintfStability
interface IThermalChangedCallback {
oneway void notifyThrottling(in android.hardware.thermal.Temperature temperature);
diff --git a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/Temperature.aidl b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/Temperature.aidl
index 7156415..3bf08bf 100644
--- a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/Temperature.aidl
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/Temperature.aidl
@@ -32,6 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.thermal;
+/* @hide */
@VintfStability
parcelable Temperature {
android.hardware.thermal.TemperatureType type;
diff --git a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/TemperatureThreshold.aidl b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/TemperatureThreshold.aidl
index 6da561f..c5ca4b9 100644
--- a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/TemperatureThreshold.aidl
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/TemperatureThreshold.aidl
@@ -32,6 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.thermal;
+/* @hide */
@VintfStability
parcelable TemperatureThreshold {
android.hardware.thermal.TemperatureType type;
diff --git a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/TemperatureType.aidl b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/TemperatureType.aidl
index c6a08c1..0a9efdd 100644
--- a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/TemperatureType.aidl
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/TemperatureType.aidl
@@ -32,6 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.thermal;
+/* @hide */
@Backing(type="int") @VintfStability
enum TemperatureType {
UNKNOWN = -1,
diff --git a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/ThrottlingSeverity.aidl b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/ThrottlingSeverity.aidl
index e86b581..8fe3df6 100644
--- a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/ThrottlingSeverity.aidl
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/ThrottlingSeverity.aidl
@@ -32,6 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.thermal;
+/* @hide */
@Backing(type="int") @VintfStability
enum ThrottlingSeverity {
NONE = 0,
diff --git a/thermal/aidl/android/hardware/thermal/CoolingDevice.aidl b/thermal/aidl/android/hardware/thermal/CoolingDevice.aidl
index 6d974a5..1f2360d 100644
--- a/thermal/aidl/android/hardware/thermal/CoolingDevice.aidl
+++ b/thermal/aidl/android/hardware/thermal/CoolingDevice.aidl
@@ -18,6 +18,7 @@
import android.hardware.thermal.CoolingType;
+/* @hide */
@VintfStability
parcelable CoolingDevice {
/**
diff --git a/thermal/aidl/android/hardware/thermal/CoolingType.aidl b/thermal/aidl/android/hardware/thermal/CoolingType.aidl
index 1b430d2..08beb55 100644
--- a/thermal/aidl/android/hardware/thermal/CoolingType.aidl
+++ b/thermal/aidl/android/hardware/thermal/CoolingType.aidl
@@ -18,6 +18,7 @@
/**
* Device cooling device types
+ * @hide
*/
@VintfStability
@Backing(type="int")
diff --git a/thermal/aidl/android/hardware/thermal/IThermal.aidl b/thermal/aidl/android/hardware/thermal/IThermal.aidl
index 8b79cb4..dd87b3a 100644
--- a/thermal/aidl/android/hardware/thermal/IThermal.aidl
+++ b/thermal/aidl/android/hardware/thermal/IThermal.aidl
@@ -23,6 +23,7 @@
import android.hardware.thermal.TemperatureThreshold;
import android.hardware.thermal.TemperatureType;
+/* @hide */
@VintfStability
interface IThermal {
/**
diff --git a/thermal/aidl/android/hardware/thermal/IThermalChangedCallback.aidl b/thermal/aidl/android/hardware/thermal/IThermalChangedCallback.aidl
index 6fe2dac..105f085 100644
--- a/thermal/aidl/android/hardware/thermal/IThermalChangedCallback.aidl
+++ b/thermal/aidl/android/hardware/thermal/IThermalChangedCallback.aidl
@@ -20,6 +20,7 @@
/**
* IThermalChangedCallback send throttling notification to clients.
+ * @hide
*/
@VintfStability
interface IThermalChangedCallback {
diff --git a/thermal/aidl/android/hardware/thermal/Temperature.aidl b/thermal/aidl/android/hardware/thermal/Temperature.aidl
index f0041ed..281d68d 100644
--- a/thermal/aidl/android/hardware/thermal/Temperature.aidl
+++ b/thermal/aidl/android/hardware/thermal/Temperature.aidl
@@ -19,6 +19,7 @@
import android.hardware.thermal.TemperatureType;
import android.hardware.thermal.ThrottlingSeverity;
+/* @hide */
@VintfStability
parcelable Temperature {
/**
diff --git a/thermal/aidl/android/hardware/thermal/TemperatureThreshold.aidl b/thermal/aidl/android/hardware/thermal/TemperatureThreshold.aidl
index 9ecdab3..8065f76 100644
--- a/thermal/aidl/android/hardware/thermal/TemperatureThreshold.aidl
+++ b/thermal/aidl/android/hardware/thermal/TemperatureThreshold.aidl
@@ -18,6 +18,7 @@
import android.hardware.thermal.TemperatureType;
+/* @hide */
@VintfStability
parcelable TemperatureThreshold {
/**
diff --git a/thermal/aidl/android/hardware/thermal/TemperatureType.aidl b/thermal/aidl/android/hardware/thermal/TemperatureType.aidl
index aebe7ce..467d096 100644
--- a/thermal/aidl/android/hardware/thermal/TemperatureType.aidl
+++ b/thermal/aidl/android/hardware/thermal/TemperatureType.aidl
@@ -18,6 +18,7 @@
/**
* Device temperature types
+ * @hide
*/
@VintfStability
@Backing(type="int")
diff --git a/thermal/aidl/android/hardware/thermal/ThrottlingSeverity.aidl b/thermal/aidl/android/hardware/thermal/ThrottlingSeverity.aidl
index 29f0724..c66e6c2 100644
--- a/thermal/aidl/android/hardware/thermal/ThrottlingSeverity.aidl
+++ b/thermal/aidl/android/hardware/thermal/ThrottlingSeverity.aidl
@@ -18,6 +18,7 @@
/**
* Device throttling severity
+ * @hide
*/
@VintfStability
@Backing(type="int")
diff --git a/threadnetwork/OWNERS b/threadnetwork/OWNERS
new file mode 100644
index 0000000..54fd66d
--- /dev/null
+++ b/threadnetwork/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 1288834
+
+include platform/packages/modules/ThreadNetwork:/OWNERS
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterScIndexMask.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterScIndexMask.aidl
index 371e075..8dfc60e 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterScIndexMask.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterScIndexMask.aidl
@@ -38,4 +38,5 @@
int scIndex;
int scAvc;
int scHevc;
+ int scVvc;
}
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxRecordScIndexType.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxRecordScIndexType.aidl
index 30ec29a..fb4430b 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxRecordScIndexType.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxRecordScIndexType.aidl
@@ -39,4 +39,5 @@
SC = 1,
SC_HEVC = 2,
SC_AVC = 3,
+ SC_VVC = 4,
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxScVvcIndex.aidl
similarity index 72%
copy from audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
copy to tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxScVvcIndex.aidl
index 8ad4848..3e08d26 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxScVvcIndex.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * 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.
@@ -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;
-@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.tv.tuner;
+/* @hide */
+@Backing(type="int") @VintfStability
+enum DemuxScVvcIndex {
+ UNDEFINED = 0,
+ SLICE_IDR_W_RADL = 1,
+ SLICE_IDR_N_LP = 2,
+ SLICE_CRA = 4,
+ SLICE_GDR = 8,
+ VPS = 16,
+ SPS = 32,
+ AUD = 64,
}
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/VideoStreamType.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/VideoStreamType.aidl
index 9dfd686..dbb6033 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/VideoStreamType.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/VideoStreamType.aidl
@@ -48,4 +48,5 @@
AV1 = 10,
AVS = 11,
AVS2 = 12,
+ VVC = 13,
}
diff --git a/tv/tuner/aidl/android/hardware/tv/tuner/DemuxFilterScIndexMask.aidl b/tv/tuner/aidl/android/hardware/tv/tuner/DemuxFilterScIndexMask.aidl
index 4036b06..d53bc5b 100644
--- a/tv/tuner/aidl/android/hardware/tv/tuner/DemuxFilterScIndexMask.aidl
+++ b/tv/tuner/aidl/android/hardware/tv/tuner/DemuxFilterScIndexMask.aidl
@@ -39,4 +39,9 @@
* Indexes defined by DemuxScHevcIndex.
*/
int scHevc;
+
+ /**
+ * Indexes defined by DemuxScVvcIndex.
+ */
+ int scVvc;
}
diff --git a/tv/tuner/aidl/android/hardware/tv/tuner/DemuxRecordScIndexType.aidl b/tv/tuner/aidl/android/hardware/tv/tuner/DemuxRecordScIndexType.aidl
index 98427f7..265b978 100644
--- a/tv/tuner/aidl/android/hardware/tv/tuner/DemuxRecordScIndexType.aidl
+++ b/tv/tuner/aidl/android/hardware/tv/tuner/DemuxRecordScIndexType.aidl
@@ -42,4 +42,9 @@
* Use Start Code index for AVC
*/
SC_AVC,
+
+ /**
+ * Use Start Code index for VVC
+ */
+ SC_VVC,
}
diff --git a/tv/tuner/aidl/android/hardware/tv/tuner/DemuxScVvcIndex.aidl b/tv/tuner/aidl/android/hardware/tv/tuner/DemuxScVvcIndex.aidl
new file mode 100644
index 0000000..8b47f62
--- /dev/null
+++ b/tv/tuner/aidl/android/hardware/tv/tuner/DemuxScVvcIndex.aidl
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tv.tuner;
+
+/**
+ * Indexes can be tagged by start point of slice groups according to ISO/IEC 23090-3.
+ * @hide
+ */
+@VintfStability
+@Backing(type="int")
+enum DemuxScVvcIndex {
+ UNDEFINED = 0,
+
+ /**
+ * Coded slice of an IDR picture or subpicture with RADL pictures.
+ */
+ SLICE_IDR_W_RADL = 1 << 0,
+
+ /**
+ * Coded slice of an IDR picture or subpicture without leading pictures.
+ */
+ SLICE_IDR_N_LP = 1 << 1,
+
+ /**
+ * Coded slice of a CRA (clean random access) picture or subpicture.
+ */
+ SLICE_CRA = 1 << 2,
+
+ /**
+ * Coded slice of a GDR (gradual decoder refresh) picture or subpicture.
+ */
+ SLICE_GDR = 1 << 3,
+
+ /**
+ * Video parameter set (non-VCL NALU).
+ */
+ VPS = 1 << 4,
+
+ /**
+ * Sequence parameter set (non-VCL NALU).
+ */
+ SPS = 1 << 5,
+
+ /**
+ * Access unit delimiter (non-VCL NALU).
+ */
+ AUD = 1 << 6,
+}
diff --git a/tv/tuner/aidl/android/hardware/tv/tuner/VideoStreamType.aidl b/tv/tuner/aidl/android/hardware/tv/tuner/VideoStreamType.aidl
index 108d986..bd000d2 100644
--- a/tv/tuner/aidl/android/hardware/tv/tuner/VideoStreamType.aidl
+++ b/tv/tuner/aidl/android/hardware/tv/tuner/VideoStreamType.aidl
@@ -84,4 +84,9 @@
* New Chinese Standard
*/
AVS2,
+
+ /*
+ * ITU-T Rec. H.266 and ISO/IEC 23090-3
+ */
+ VVC,
}
diff --git a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
index 6ec8d57..b9ac7b9 100644
--- a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
+++ b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
@@ -43,10 +43,12 @@
CCC_SUPPORTED_UWB_CONFIGS = 165,
CCC_SUPPORTED_PULSE_SHAPE_COMBOS = 166,
CCC_SUPPORTED_RAN_MULTIPLIER = 167,
+ CCC_SUPPORTED_MAX_RANGING_SESSION_NUMBER = 168,
SUPPORTED_AOA_RESULT_REQ_ANTENNA_INTERLEAVING = 227,
SUPPORTED_MIN_RANGING_INTERVAL_MS = 228,
SUPPORTED_RANGE_DATA_NTF_CONFIG = 229,
SUPPORTED_RSSI_REPORTING = 230,
SUPPORTED_DIAGNOSTICS = 231,
SUPPORTED_MIN_SLOT_DURATION = 232,
+ SUPPORTED_MAX_RANGING_SESSION_NUMBER = 233,
}
diff --git a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
index b182f9d..a3bb7a6 100644
--- a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
+++ b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
@@ -139,6 +139,11 @@
/** Int value for indicating supported ran multiplier */
CCC_SUPPORTED_RAN_MULTIPLIER = 0xA7,
+ /**
+ * Int value to indicate supported max number of ccc ranging sessions
+ */
+ CCC_SUPPORTED_MAX_RANGING_SESSION_NUMBER = 0xA8,
+
/*********************************************
* FIRA specific
********************************************/
@@ -184,4 +189,9 @@
* 4 byte value to indicate supported min slot duration in ms.
*/
SUPPORTED_MIN_SLOT_DURATION = 0xE8,
+
+ /**
+ * Int value to indicate supported max number of fira ranging sessions
+ */
+ SUPPORTED_MAX_RANGING_SESSION_NUMBER = 0xE9,
}
diff --git a/vibrator/aidl/default/main.cpp b/vibrator/aidl/default/main.cpp
index feba2c7..7375889 100644
--- a/vibrator/aidl/default/main.cpp
+++ b/vibrator/aidl/default/main.cpp
@@ -29,15 +29,15 @@
// make a default vibrator service
auto vib = ndk::SharedRefBase::make<Vibrator>();
- const std::string vibName = std::string() + Vibrator::descriptor + "/default";
- binder_status_t status = AServiceManager_addService(vib->asBinder().get(), vibName.c_str());
+ binder_status_t status = AServiceManager_addService(
+ vib->asBinder().get(), Vibrator::makeServiceName("default").c_str());
CHECK_EQ(status, STATUS_OK);
// make the vibrator manager service with a different vibrator
auto managedVib = ndk::SharedRefBase::make<Vibrator>();
auto vibManager = ndk::SharedRefBase::make<VibratorManager>(std::move(managedVib));
- const std::string vibManagerName = std::string() + VibratorManager::descriptor + "/default";
- status = AServiceManager_addService(vibManager->asBinder().get(), vibManagerName.c_str());
+ status = AServiceManager_addService(vibManager->asBinder().get(),
+ VibratorManager::makeServiceName("default").c_str());
CHECK_EQ(status, STATUS_OK);
ABinderProcess_joinThreadPool();
diff --git a/weaver/aidl/Android.bp b/weaver/aidl/Android.bp
index caa92aa..74cec99 100644
--- a/weaver/aidl/Android.bp
+++ b/weaver/aidl/Android.bp
@@ -17,5 +17,10 @@
platform_apis: true,
},
},
- versions: ["1"],
+ versions_with_info: [
+ {
+ version: "1",
+ imports: [],
+ },
+ ],
}
diff --git a/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/WeaverReadResponse.aidl b/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/WeaverReadResponse.aidl
index 47ee4c8..96e528f 100644
--- a/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/WeaverReadResponse.aidl
+++ b/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/WeaverReadResponse.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 The Android Open Source Project
+ * 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.
@@ -36,4 +36,5 @@
parcelable WeaverReadResponse {
long timeout;
byte[] value;
+ android.hardware.weaver.WeaverReadStatus status = android.hardware.weaver.WeaverReadStatus.FAILED;
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl b/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/WeaverReadStatus.aidl
similarity index 75%
copy from audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
copy to weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/WeaverReadStatus.aidl
index 8ad4848..fce9758 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
+++ b/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/WeaverReadStatus.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.weaver;
+@Backing(type="int") @VintfStability
+enum WeaverReadStatus {
+ OK = 0,
+ FAILED = 1,
+ INCORRECT_KEY = 2,
+ THROTTLE = 3,
}
diff --git a/weaver/aidl/android/hardware/weaver/WeaverReadResponse.aidl b/weaver/aidl/android/hardware/weaver/WeaverReadResponse.aidl
index ec006e8..17ea718 100644
--- a/weaver/aidl/android/hardware/weaver/WeaverReadResponse.aidl
+++ b/weaver/aidl/android/hardware/weaver/WeaverReadResponse.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 The Android Open Source Project
+ * 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.
@@ -16,15 +16,22 @@
package android.hardware.weaver;
+import android.hardware.weaver.WeaverReadStatus;
+
@VintfStability
parcelable WeaverReadResponse {
/**
- * The time to wait, in milliseconds, before making the next request.
+ * The time to wait, in milliseconds, before making the next request,
+ * must be greater than or equal to zero and less than INT_MAX.
*/
long timeout;
/**
* The value read from the slot or empty if the value was not read.
*/
byte[] value;
+ /**
+ * Status from WeaverReadStatus
+ */
+ WeaverReadStatus status = WeaverReadStatus.FAILED;
}
diff --git a/weaver/aidl/android/hardware/weaver/WeaverReadStatus.aidl b/weaver/aidl/android/hardware/weaver/WeaverReadStatus.aidl
new file mode 100644
index 0000000..36e731f
--- /dev/null
+++ b/weaver/aidl/android/hardware/weaver/WeaverReadStatus.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.weaver;
+
+@VintfStability
+@Backing(type="int")
+enum WeaverReadStatus {
+ OK,
+ FAILED,
+ INCORRECT_KEY,
+ THROTTLE,
+}
diff --git a/weaver/aidl/default/Android.bp b/weaver/aidl/default/Android.bp
index 70d9171..494cb1b 100644
--- a/weaver/aidl/default/Android.bp
+++ b/weaver/aidl/default/Android.bp
@@ -34,7 +34,7 @@
"Weaver.cpp",
],
shared_libs: [
- "android.hardware.weaver-V1-ndk",
+ "android.hardware.weaver-V2-ndk",
"libbase",
"libbinder_ndk",
],
diff --git a/weaver/aidl/default/Weaver.cpp b/weaver/aidl/default/Weaver.cpp
index 6b77924..c9ffe85 100644
--- a/weaver/aidl/default/Weaver.cpp
+++ b/weaver/aidl/default/Weaver.cpp
@@ -37,18 +37,19 @@
}
::ndk::ScopedAStatus Weaver::read(int32_t in_slotId, const std::vector<uint8_t>& in_key, WeaverReadResponse* out_response) {
+ using ::aidl::android::hardware::weaver::WeaverReadStatus;
if (in_slotId > 15 || in_key.size() > 16) {
- *out_response = {0, {}};
- return ndk::ScopedAStatus(AStatus_fromServiceSpecificError(Weaver::STATUS_FAILED));
+ *out_response = {0, {}, WeaverReadStatus::FAILED};
+ return ndk::ScopedAStatus::ok();
}
if (slot_array[in_slotId].key != in_key) {
- *out_response = {0, {}};
- return ndk::ScopedAStatus(AStatus_fromServiceSpecificError(Weaver::STATUS_INCORRECT_KEY));
+ *out_response = {0, {}, WeaverReadStatus::INCORRECT_KEY};
+ return ndk::ScopedAStatus::ok();
}
- *out_response = {0, slot_array[in_slotId].value};
+ *out_response = {0, slot_array[in_slotId].value, WeaverReadStatus::OK};
return ::ndk::ScopedAStatus::ok();
}
diff --git a/weaver/aidl/default/android.hardware.weaver-service.example.xml b/weaver/aidl/default/android.hardware.weaver-service.example.xml
index ed291cd..bfe4396 100644
--- a/weaver/aidl/default/android.hardware.weaver-service.example.xml
+++ b/weaver/aidl/default/android.hardware.weaver-service.example.xml
@@ -1,7 +1,7 @@
<manifest version="1.0" type="device">
<hal format="aidl">
<name>android.hardware.weaver</name>
- <version>1</version>
+ <version>2</version>
<interface>
<name>IWeaver</name>
<instance>default</instance>
diff --git a/weaver/aidl/vts/Android.bp b/weaver/aidl/vts/Android.bp
index cf1661c..557fe47 100644
--- a/weaver/aidl/vts/Android.bp
+++ b/weaver/aidl/vts/Android.bp
@@ -34,7 +34,7 @@
"libbinder_ndk",
"libbase",
],
- static_libs: ["android.hardware.weaver-V1-ndk"],
+ static_libs: ["android.hardware.weaver-V2-ndk"],
test_suites: [
"general-tests",
"vts",
diff --git a/weaver/aidl/vts/VtsHalWeaverTargetTest.cpp b/weaver/aidl/vts/VtsHalWeaverTargetTest.cpp
index 878c762..f016515 100644
--- a/weaver/aidl/vts/VtsHalWeaverTargetTest.cpp
+++ b/weaver/aidl/vts/VtsHalWeaverTargetTest.cpp
@@ -25,6 +25,7 @@
using ::aidl::android::hardware::weaver::IWeaver;
using ::aidl::android::hardware::weaver::WeaverConfig;
using ::aidl::android::hardware::weaver::WeaverReadResponse;
+using ::aidl::android::hardware::weaver::WeaverReadStatus;
using ::ndk::SpAIBinder;
@@ -102,14 +103,17 @@
WeaverReadResponse response;
std::vector<uint8_t> readValue;
uint32_t timeout;
+ WeaverReadStatus status;
const auto readRet = weaver->read(slotId, KEY, &response);
readValue = response.value;
timeout = response.timeout;
+ status = response.status;
ASSERT_TRUE(readRet.isOk());
EXPECT_EQ(readValue, VALUE);
EXPECT_EQ(timeout, 0u);
+ EXPECT_EQ(status, WeaverReadStatus::OK);
}
/*
@@ -128,14 +132,17 @@
WeaverReadResponse response;
std::vector<uint8_t> readValue;
uint32_t timeout;
+ WeaverReadStatus status;
const auto readRet = weaver->read(slotId, KEY, &response);
readValue = response.value;
timeout = response.timeout;
+ status = response.status;
ASSERT_TRUE(readRet.isOk());
EXPECT_EQ(readValue, OTHER_VALUE);
EXPECT_EQ(timeout, 0u);
+ EXPECT_EQ(status, WeaverReadStatus::OK);
}
/*
@@ -149,15 +156,16 @@
WeaverReadResponse response;
std::vector<uint8_t> readValue;
+ WeaverReadStatus status;
const auto readRet =
weaver->read(slotId, WRONG_KEY, &response);
readValue = response.value;
+ status = response.status;
- ASSERT_FALSE(readRet.isOk());
- ASSERT_EQ(EX_SERVICE_SPECIFIC, readRet.getExceptionCode());
- ASSERT_EQ(IWeaver::STATUS_INCORRECT_KEY, readRet.getServiceSpecificError());
+ ASSERT_TRUE(readRet.isOk());
EXPECT_TRUE(readValue.empty());
+ EXPECT_EQ(status, WeaverReadStatus::INCORRECT_KEY);
}
/*
@@ -193,17 +201,18 @@
WeaverReadResponse response;
std::vector<uint8_t> readValue;
uint32_t timeout;
+ WeaverReadStatus status;
const auto readRet =
weaver->read(config.slots, KEY, &response);
readValue = response.value;
timeout = response.timeout;
+ status = response.status;
- ASSERT_FALSE(readRet.isOk());
- ASSERT_EQ(EX_SERVICE_SPECIFIC, readRet.getExceptionCode());
- ASSERT_EQ(IWeaver::STATUS_FAILED, readRet.getServiceSpecificError());
+ ASSERT_TRUE(readRet.isOk());
EXPECT_TRUE(readValue.empty());
EXPECT_EQ(timeout, 0u);
+ EXPECT_EQ(status, WeaverReadStatus::FAILED);
}
/*
@@ -250,17 +259,18 @@
WeaverReadResponse response;
std::vector<uint8_t> readValue;
uint32_t timeout;
+ WeaverReadStatus status;
const auto readRet =
weaver->read(slotId, bigKey, &response);
readValue = response.value;
timeout = response.timeout;
+ status = response.status;
- ASSERT_FALSE(readRet.isOk());
- ASSERT_EQ(EX_SERVICE_SPECIFIC, readRet.getExceptionCode());
- ASSERT_EQ(IWeaver::STATUS_FAILED, readRet.getServiceSpecificError());
+ ASSERT_TRUE(readRet.isOk());
EXPECT_TRUE(readValue.empty());
EXPECT_EQ(timeout, 0u);
+ EXPECT_EQ(status, WeaverReadStatus::FAILED);
}
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WeaverAidlTest);
diff --git a/wifi/1.6/default/Android.bp b/wifi/1.6/default/Android.bp
new file mode 100644
index 0000000..0f98e71
--- /dev/null
+++ b/wifi/1.6/default/Android.bp
@@ -0,0 +1,238 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+soong_config_module_type {
+ name: "wifi_hal_cc_defaults",
+ module_type: "cc_defaults",
+ config_namespace: "wifi",
+ bool_variables: [
+ "hidl_feature_aware", // WIFI_HIDL_FEATURE_AWARE
+ "hidl_feature_dual_interface", // WIFI_HIDL_FEATURE_DUAL_INTERFACE
+ "hidl_feature_disable_ap", // WIFI_HIDL_FEATURE_DISABLE_AP
+ "hidl_feature_disable_ap_mac_randomization", // WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION
+ "avoid_iface_reset_mac_change", // WIFI_AVOID_IFACE_RESET_MAC_CHANGE
+ ],
+ value_variables: [
+ "hal_interface_combinations", // WIFI_HAL_INTERFACE_COMBINATIONS
+ ],
+ properties: [
+ "cppflags",
+ ],
+}
+
+wifi_hal_cc_defaults {
+ name: "android.hardware.wifi@1.0-service-cppflags-defaults",
+ soong_config_variables: {
+ hidl_feature_aware: {
+ cppflags: ["-DWIFI_HIDL_FEATURE_AWARE"],
+ },
+ hidl_feature_dual_interface: {
+ cppflags: ["-DWIFI_HIDL_FEATURE_DUAL_INTERFACE"],
+ },
+ hidl_feature_disable_ap: {
+ cppflags: ["-DWIFI_HIDL_FEATURE_DISABLE_AP"],
+ },
+ hidl_feature_disable_ap_mac_randomization: {
+ cppflags: ["-DWIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION"],
+ },
+ avoid_iface_reset_mac_change: {
+ cppflags: ["-DWIFI_AVOID_IFACE_RESET_MAC_CHANGE"],
+ },
+ hal_interface_combinations: {
+ cppflags: ["-DWIFI_HAL_INTERFACE_COMBINATIONS=%s"],
+ },
+ },
+}
+
+cc_library_static {
+ name: "android.hardware.wifi@1.0-service-lib",
+ defaults: ["android.hardware.wifi@1.0-service-cppflags-defaults"],
+ proprietary: true,
+ compile_multilib: "first",
+ cppflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ ],
+ // Allow implicit fallthroughs in wifi_legacy_hal.cpp until they are fixed.
+ cflags: ["-Wno-error=implicit-fallthrough"],
+ srcs: [
+ "hidl_struct_util.cpp",
+ "hidl_sync_util.cpp",
+ "ringbuffer.cpp",
+ "wifi.cpp",
+ "wifi_ap_iface.cpp",
+ "wifi_chip.cpp",
+ "wifi_feature_flags.cpp",
+ "wifi_iface_util.cpp",
+ "wifi_legacy_hal.cpp",
+ "wifi_legacy_hal_factory.cpp",
+ "wifi_legacy_hal_stubs.cpp",
+ "wifi_mode_controller.cpp",
+ "wifi_nan_iface.cpp",
+ "wifi_p2p_iface.cpp",
+ "wifi_rtt_controller.cpp",
+ "wifi_sta_iface.cpp",
+ "wifi_status_util.cpp",
+ ],
+
+ shared_libs: [
+ "libbase",
+ "libcutils",
+ "libhidlbase",
+ "liblog",
+ "libnl",
+ "libutils",
+ "libwifi-hal",
+ "libwifi-system-iface",
+ "libxml2",
+ "android.hardware.wifi@1.0",
+ "android.hardware.wifi@1.1",
+ "android.hardware.wifi@1.2",
+ "android.hardware.wifi@1.3",
+ "android.hardware.wifi@1.4",
+ "android.hardware.wifi@1.5",
+ "android.hardware.wifi@1.6",
+ ],
+
+ export_include_dirs: ["."],
+}
+
+cc_binary {
+ name: "android.hardware.wifi@1.0-service",
+ vintf_fragments: ["android.hardware.wifi@1.0-service.xml"],
+ relative_install_path: "hw",
+ proprietary: true,
+ cppflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ ],
+ srcs: ["service.cpp"],
+ shared_libs: [
+ "libbase",
+ "libcutils",
+ "libhidlbase",
+ "liblog",
+ "libnl",
+ "libutils",
+ "libwifi-hal",
+ "libwifi-system-iface",
+ "libxml2",
+ "android.hardware.wifi@1.0",
+ "android.hardware.wifi@1.1",
+ "android.hardware.wifi@1.2",
+ "android.hardware.wifi@1.3",
+ "android.hardware.wifi@1.4",
+ "android.hardware.wifi@1.5",
+ "android.hardware.wifi@1.6",
+ ],
+ static_libs: ["android.hardware.wifi@1.0-service-lib"],
+ init_rc: ["android.hardware.wifi@1.0-service.rc"],
+}
+
+cc_binary {
+ name: "android.hardware.wifi@1.0-service-lazy",
+ vintf_fragments: ["android.hardware.wifi@1.0-service.xml"],
+ overrides: ["android.hardware.wifi@1.0-service"],
+ cflags: ["-DLAZY_SERVICE"],
+ relative_install_path: "hw",
+ proprietary: true,
+ cppflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ ],
+ srcs: ["service.cpp"],
+ shared_libs: [
+ "libbase",
+ "libcutils",
+ "libhidlbase",
+ "liblog",
+ "libnl",
+ "libutils",
+ "libwifi-hal",
+ "libwifi-system-iface",
+ "libxml2",
+ "android.hardware.wifi@1.0",
+ "android.hardware.wifi@1.1",
+ "android.hardware.wifi@1.2",
+ "android.hardware.wifi@1.3",
+ "android.hardware.wifi@1.4",
+ "android.hardware.wifi@1.5",
+ "android.hardware.wifi@1.6",
+ ],
+ static_libs: ["android.hardware.wifi@1.0-service-lib"],
+ init_rc: ["android.hardware.wifi@1.0-service-lazy.rc"],
+}
+
+cc_test {
+ name: "android.hardware.wifi@1.0-service-tests",
+ proprietary: true,
+ compile_multilib: "first",
+ cppflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ ],
+ srcs: [
+ "tests/hidl_struct_util_unit_tests.cpp",
+ "tests/main.cpp",
+ "tests/mock_interface_tool.cpp",
+ "tests/mock_wifi_feature_flags.cpp",
+ "tests/mock_wifi_iface_util.cpp",
+ "tests/mock_wifi_legacy_hal.cpp",
+ "tests/mock_wifi_mode_controller.cpp",
+ "tests/ringbuffer_unit_tests.cpp",
+ "tests/wifi_nan_iface_unit_tests.cpp",
+ "tests/wifi_chip_unit_tests.cpp",
+ "tests/wifi_iface_util_unit_tests.cpp",
+ ],
+ static_libs: [
+ "libgmock",
+ "libgtest",
+ "android.hardware.wifi@1.0",
+ "android.hardware.wifi@1.1",
+ "android.hardware.wifi@1.2",
+ "android.hardware.wifi@1.3",
+ "android.hardware.wifi@1.4",
+ "android.hardware.wifi@1.5",
+ "android.hardware.wifi@1.6",
+ "android.hardware.wifi@1.0-service-lib",
+ ],
+ shared_libs: [
+ "libbase",
+ "libcutils",
+ "libhidlbase",
+ "liblog",
+ "libnl",
+ "libutils",
+ "libwifi-hal",
+ "libwifi-system-iface",
+ ],
+}
+
+filegroup {
+ name: "default-android.hardware.wifi@1.0-service.rc",
+ srcs: ["android.hardware.wifi@1.0-service.rc"],
+}
+
+filegroup {
+ name: "default-android.hardware.wifi@1.0-service.xml",
+ srcs: ["android.hardware.wifi@1.0-service.xml"],
+}
diff --git a/wifi/1.6/default/THREADING.README b/wifi/1.6/default/THREADING.README
new file mode 100644
index 0000000..8366ca0
--- /dev/null
+++ b/wifi/1.6/default/THREADING.README
@@ -0,0 +1,35 @@
+Vendor HAL Threading Model
+==========================
+The vendor HAL service has two threads:
+1. HIDL thread: This is the main thread which processes all the incoming HIDL
+RPC's.
+2. Legacy HAL event loop thread: This is the thread forked off for processing
+the legacy HAL event loop (wifi_event_loop()). This thread is used to process
+any asynchronous netlink events posted by the driver. Any asynchronous
+callbacks passed to the legacy HAL API's are invoked on this thread.
+
+Synchronization Concerns
+========================
+wifi_legacy_hal.cpp has a bunch of global "C" style functions to handle the
+legacy callbacks. Each of these "C" style function invokes a corresponding
+"std::function" version of the callback which does the actual processing.
+The variables holding these "std::function" callbacks are reset from the HIDL
+thread when they are no longer used. For example: stopGscan() will reset the
+corresponding "on_gscan_*" callback variables which were set when startGscan()
+was invoked. This is not thread safe since these callback variables are
+accesed from the legacy hal event loop thread as well.
+
+Synchronization Solution
+========================
+Adding a global lock seems to be the most trivial solution to the problem.
+a) All of the asynchronous "C" style callbacks will acquire the global lock
+before invoking the corresponding "std::function" callback variables.
+b) All of the HIDL methods will also acquire the global lock before processing
+(in hidl_return_util::validateAndCall()).
+
+Note: It's important that we only acquire the global lock for asynchronous
+callbacks, because there is no guarantee (or documentation to clarify) that the
+synchronous callbacks are invoked on the same invocation thread. If that is not
+the case in some implementation, we will end up deadlocking the system since the
+HIDL thread would have acquired the global lock which is needed by the
+synchronous callback executed on the legacy hal event loop thread.
diff --git a/wifi/1.6/default/android.hardware.wifi@1.0-service-lazy.rc b/wifi/1.6/default/android.hardware.wifi@1.0-service-lazy.rc
new file mode 100644
index 0000000..ee8c818
--- /dev/null
+++ b/wifi/1.6/default/android.hardware.wifi@1.0-service-lazy.rc
@@ -0,0 +1,14 @@
+service vendor.wifi_hal_legacy /vendor/bin/hw/android.hardware.wifi@1.0-service-lazy
+ interface android.hardware.wifi@1.0::IWifi default
+ interface android.hardware.wifi@1.1::IWifi default
+ interface android.hardware.wifi@1.2::IWifi default
+ interface android.hardware.wifi@1.3::IWifi default
+ interface android.hardware.wifi@1.4::IWifi default
+ interface android.hardware.wifi@1.5::IWifi default
+ interface android.hardware.wifi@1.6::IWifi default
+ oneshot
+ disabled
+ class hal
+ capabilities NET_ADMIN NET_RAW SYS_MODULE
+ user wifi
+ group wifi gps
diff --git a/wifi/1.6/default/android.hardware.wifi@1.0-service.rc b/wifi/1.6/default/android.hardware.wifi@1.0-service.rc
new file mode 100644
index 0000000..18f40d0
--- /dev/null
+++ b/wifi/1.6/default/android.hardware.wifi@1.0-service.rc
@@ -0,0 +1,12 @@
+service vendor.wifi_hal_legacy /vendor/bin/hw/android.hardware.wifi@1.0-service
+ interface android.hardware.wifi@1.0::IWifi default
+ interface android.hardware.wifi@1.1::IWifi default
+ interface android.hardware.wifi@1.2::IWifi default
+ interface android.hardware.wifi@1.3::IWifi default
+ interface android.hardware.wifi@1.4::IWifi default
+ interface android.hardware.wifi@1.5::IWifi default
+ interface android.hardware.wifi@1.6::IWifi default
+ class hal
+ capabilities NET_ADMIN NET_RAW SYS_MODULE
+ user wifi
+ group wifi gps
diff --git a/wifi/1.6/default/android.hardware.wifi@1.0-service.xml b/wifi/1.6/default/android.hardware.wifi@1.0-service.xml
new file mode 100644
index 0000000..771fbaa
--- /dev/null
+++ b/wifi/1.6/default/android.hardware.wifi@1.0-service.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+ <hal format="hidl">
+ <name>android.hardware.wifi</name>
+ <transport>hwbinder</transport>
+ <version>1.6</version>
+ <interface>
+ <name>IWifi</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/wifi/1.6/default/hal_legacy/AudioHardwareBase.h b/wifi/1.6/default/hal_legacy/AudioHardwareBase.h
new file mode 100644
index 0000000..eb61472
--- /dev/null
+++ b/wifi/1.6/default/hal_legacy/AudioHardwareBase.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIO_HARDWARE_BASE_H
+#define ANDROID_AUDIO_HARDWARE_BASE_H
+
+#include <hardware_legacy/AudioHardwareInterface.h>
+
+#include <system/audio.h>
+
+namespace android_audio_legacy {
+
+// ----------------------------------------------------------------------------
+
+/**
+ * AudioHardwareBase is a convenient base class used for implementing the
+ * AudioHardwareInterface interface.
+ */
+class AudioHardwareBase : public AudioHardwareInterface {
+ public:
+ AudioHardwareBase();
+ virtual ~AudioHardwareBase() {}
+
+ /**
+ * setMode is called when the audio mode changes. NORMAL mode is for
+ * standard audio playback, RINGTONE when a ringtone is playing, IN_CALL
+ * when a telephony call is in progress, IN_COMMUNICATION when a VoIP call is in progress.
+ */
+ virtual status_t setMode(int mode);
+
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
+
+ virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount);
+ virtual status_t getMasterVolume(float* volume);
+
+ /**This method dumps the state of the audio hardware */
+ virtual status_t dumpState(int fd, const Vector<String16>& args);
+
+ protected:
+ /** returns true if the given mode maps to a telephony or VoIP call is in progress */
+ virtual bool isModeInCall(int mode) {
+ return ((mode == AudioSystem::MODE_IN_CALL) ||
+ (mode == AudioSystem::MODE_IN_COMMUNICATION));
+ };
+ /** returns true if a telephony or VoIP call is in progress */
+ virtual bool isInCall() { return isModeInCall(mMode); };
+ int mMode;
+};
+
+}; // namespace android_audio_legacy
+
+#endif // ANDROID_AUDIO_HARDWARE_BASE_H
diff --git a/wifi/1.6/default/hal_legacy/AudioHardwareInterface.h b/wifi/1.6/default/hal_legacy/AudioHardwareInterface.h
new file mode 100644
index 0000000..7befb79
--- /dev/null
+++ b/wifi/1.6/default/hal_legacy/AudioHardwareInterface.h
@@ -0,0 +1,296 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIO_HARDWARE_INTERFACE_H
+#define ANDROID_AUDIO_HARDWARE_INTERFACE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/String16.h>
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
+#include <hardware_legacy/AudioSystemLegacy.h>
+
+#include <hardware/audio.h>
+#include <system/audio.h>
+
+#include <cutils/bitops.h>
+
+namespace android_audio_legacy {
+using android::String16;
+using android::String8;
+using android::Vector;
+
+// ----------------------------------------------------------------------------
+
+/**
+ * AudioStreamOut is the abstraction interface for the audio output hardware.
+ *
+ * It provides information about various properties of the audio output hardware driver.
+ */
+class AudioStreamOut {
+ public:
+ virtual ~AudioStreamOut() = 0;
+
+ /** return audio sampling rate in hz - eg. 44100 */
+ virtual uint32_t sampleRate() const = 0;
+
+ /** returns size of output buffer - eg. 4800 */
+ virtual size_t bufferSize() const = 0;
+
+ /**
+ * returns the output channel mask
+ */
+ virtual uint32_t channels() const = 0;
+
+ /**
+ * return audio format in 8bit or 16bit PCM format -
+ * eg. AudioSystem:PCM_16_BIT
+ */
+ virtual int format() const = 0;
+
+ /**
+ * return the frame size (number of bytes per sample).
+ */
+ uint32_t frameSize() const {
+ return audio_channel_count_from_out_mask(channels()) *
+ ((format() == AUDIO_FORMAT_PCM_16_BIT) ? sizeof(int16_t) : sizeof(int8_t));
+ }
+
+ /**
+ * return the audio hardware driver latency in milli seconds.
+ */
+ virtual uint32_t latency() const = 0;
+
+ /**
+ * Use this method in situations where audio mixing is done in the
+ * hardware. This method serves as a direct interface with hardware,
+ * allowing you to directly set the volume as apposed to via the framework.
+ * This method might produce multiple PCM outputs or hardware accelerated
+ * codecs, such as MP3 or AAC.
+ */
+ virtual status_t setVolume(float left, float right) = 0;
+
+ /** write audio buffer to driver. Returns number of bytes written */
+ virtual ssize_t write(const void* buffer, size_t bytes) = 0;
+
+ /**
+ * Put the audio hardware output into standby mode. Returns
+ * status based on include/utils/Errors.h
+ */
+ virtual status_t standby() = 0;
+
+ /** dump the state of the audio output device */
+ virtual status_t dump(int fd, const Vector<String16>& args) = 0;
+
+ // set/get audio output parameters. The function accepts a list of parameters
+ // key value pairs in the form: key1=value1;key2=value2;...
+ // Some keys are reserved for standard parameters (See AudioParameter class).
+ // If the implementation does not accept a parameter change while the output is
+ // active but the parameter is acceptable otherwise, it must return INVALID_OPERATION.
+ // The audio flinger will put the output in standby and then change the parameter value.
+ virtual status_t setParameters(const String8& keyValuePairs) = 0;
+ virtual String8 getParameters(const String8& keys) = 0;
+
+ // return the number of audio frames written by the audio dsp to DAC since
+ // the output has exited standby
+ virtual status_t getRenderPosition(uint32_t* dspFrames) = 0;
+
+ /**
+ * get the local time at which the next write to the audio driver will be
+ * presented
+ */
+ virtual status_t getNextWriteTimestamp(int64_t* timestamp);
+
+ /**
+ * Return a recent count of the number of audio frames presented to an external observer.
+ */
+ virtual status_t getPresentationPosition(uint64_t* frames, struct timespec* timestamp);
+};
+
+/**
+ * AudioStreamIn is the abstraction interface for the audio input hardware.
+ *
+ * It defines the various properties of the audio hardware input driver.
+ */
+class AudioStreamIn {
+ public:
+ virtual ~AudioStreamIn() = 0;
+
+ /** return audio sampling rate in hz - eg. 44100 */
+ virtual uint32_t sampleRate() const = 0;
+
+ /** return the input buffer size allowed by audio driver */
+ virtual size_t bufferSize() const = 0;
+
+ /** return input channel mask */
+ virtual uint32_t channels() const = 0;
+
+ /**
+ * return audio format in 8bit or 16bit PCM format -
+ * eg. AudioSystem:PCM_16_BIT
+ */
+ virtual int format() const = 0;
+
+ /**
+ * return the frame size (number of bytes per sample).
+ */
+ uint32_t frameSize() const {
+ return audio_channel_count_from_in_mask(channels()) *
+ ((format() == AudioSystem::PCM_16_BIT) ? sizeof(int16_t) : sizeof(int8_t));
+ }
+
+ /** set the input gain for the audio driver. This method is for
+ * for future use */
+ virtual status_t setGain(float gain) = 0;
+
+ /** read audio buffer in from audio driver */
+ virtual ssize_t read(void* buffer, ssize_t bytes) = 0;
+
+ /** dump the state of the audio input device */
+ virtual status_t dump(int fd, const Vector<String16>& args) = 0;
+
+ /**
+ * Put the audio hardware input into standby mode. Returns
+ * status based on include/utils/Errors.h
+ */
+ virtual status_t standby() = 0;
+
+ // set/get audio input parameters. The function accepts a list of parameters
+ // key value pairs in the form: key1=value1;key2=value2;...
+ // Some keys are reserved for standard parameters (See AudioParameter class).
+ // If the implementation does not accept a parameter change while the output is
+ // active but the parameter is acceptable otherwise, it must return INVALID_OPERATION.
+ // The audio flinger will put the input in standby and then change the parameter value.
+ virtual status_t setParameters(const String8& keyValuePairs) = 0;
+ virtual String8 getParameters(const String8& keys) = 0;
+
+ // Return the number of input frames lost in the audio driver since the last call of this
+ // function. Audio driver is expected to reset the value to 0 and restart counting upon
+ // returning the current value by this function call. Such loss typically occurs when the user
+ // space process is blocked longer than the capacity of audio driver buffers. Unit: the number
+ // of input audio frames
+ virtual unsigned int getInputFramesLost() const = 0;
+
+ virtual status_t addAudioEffect(effect_handle_t effect) = 0;
+ virtual status_t removeAudioEffect(effect_handle_t effect) = 0;
+};
+
+/**
+ * AudioHardwareInterface.h defines the interface to the audio hardware abstraction layer.
+ *
+ * The interface supports setting and getting parameters, selecting audio routing
+ * paths, and defining input and output streams.
+ *
+ * AudioFlinger initializes the audio hardware and immediately opens an output stream.
+ * You can set Audio routing to output to handset, speaker, Bluetooth, or a headset.
+ *
+ * The audio input stream is initialized when AudioFlinger is called to carry out
+ * a record operation.
+ */
+class AudioHardwareInterface {
+ public:
+ virtual ~AudioHardwareInterface() {}
+
+ /**
+ * check to see if the audio hardware interface has been initialized.
+ * return status based on values defined in include/utils/Errors.h
+ */
+ virtual status_t initCheck() = 0;
+
+ /** set the audio volume of a voice call. Range is between 0.0 and 1.0 */
+ virtual status_t setVoiceVolume(float volume) = 0;
+
+ /**
+ * set the audio volume for all audio activities other than voice call.
+ * Range between 0.0 and 1.0. If any value other than NO_ERROR is returned,
+ * the software mixer will emulate this capability.
+ */
+ virtual status_t setMasterVolume(float volume) = 0;
+
+ /**
+ * Get the current master volume value for the HAL, if the HAL supports
+ * master volume control. AudioFlinger will query this value from the
+ * primary audio HAL when the service starts and use the value for setting
+ * the initial master volume across all HALs.
+ */
+ virtual status_t getMasterVolume(float* volume) = 0;
+
+ /**
+ * setMode is called when the audio mode changes. NORMAL mode is for
+ * standard audio playback, RINGTONE when a ringtone is playing, and IN_CALL
+ * when a call is in progress.
+ */
+ virtual status_t setMode(int mode) = 0;
+
+ // mic mute
+ virtual status_t setMicMute(bool state) = 0;
+ virtual status_t getMicMute(bool* state) = 0;
+
+ // set/get global audio parameters
+ virtual status_t setParameters(const String8& keyValuePairs) = 0;
+ virtual String8 getParameters(const String8& keys) = 0;
+
+ // Returns audio input buffer size according to parameters passed or 0 if one of the
+ // parameters is not supported
+ virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount) = 0;
+
+ /** This method creates and opens the audio hardware output stream */
+ virtual AudioStreamOut* openOutputStream(uint32_t devices, int* format = 0,
+ uint32_t* channels = 0, uint32_t* sampleRate = 0,
+ status_t* status = 0) = 0;
+ virtual AudioStreamOut* openOutputStreamWithFlags(
+ uint32_t devices, audio_output_flags_t flags = (audio_output_flags_t)0, int* format = 0,
+ uint32_t* channels = 0, uint32_t* sampleRate = 0, status_t* status = 0) = 0;
+ virtual void closeOutputStream(AudioStreamOut* out) = 0;
+
+ /** This method creates and opens the audio hardware input stream */
+ virtual AudioStreamIn* openInputStream(uint32_t devices, int* format, uint32_t* channels,
+ uint32_t* sampleRate, status_t* status,
+ AudioSystem::audio_in_acoustics acoustics) = 0;
+ virtual void closeInputStream(AudioStreamIn* in) = 0;
+
+ /**This method dumps the state of the audio hardware */
+ virtual status_t dumpState(int fd, const Vector<String16>& args) = 0;
+
+ virtual status_t setMasterMute(bool muted) = 0;
+
+ static AudioHardwareInterface* create();
+
+ virtual int createAudioPatch(unsigned int num_sources, const struct audio_port_config* sources,
+ unsigned int num_sinks, const struct audio_port_config* sinks,
+ audio_patch_handle_t* handle) = 0;
+
+ virtual int releaseAudioPatch(audio_patch_handle_t handle) = 0;
+
+ virtual int getAudioPort(struct audio_port* port) = 0;
+
+ virtual int setAudioPortConfig(const struct audio_port_config* config) = 0;
+
+ protected:
+ virtual status_t dump(int fd, const Vector<String16>& args) = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+extern "C" AudioHardwareInterface* createAudioHardware(void);
+
+}; // namespace android_audio_legacy
+
+#endif // ANDROID_AUDIO_HARDWARE_INTERFACE_H
diff --git a/wifi/1.6/default/hal_legacy/AudioPolicyInterface.h b/wifi/1.6/default/hal_legacy/AudioPolicyInterface.h
new file mode 100644
index 0000000..ec9c432
--- /dev/null
+++ b/wifi/1.6/default/hal_legacy/AudioPolicyInterface.h
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIOPOLICYINTERFACE_H
+#define ANDROID_AUDIOPOLICYINTERFACE_H
+
+#include <media/AudioSystem.h>
+#include <media/ToneGenerator.h>
+#include <utils/String8.h>
+
+#include <hardware/audio_policy.h>
+#include <hardware_legacy/AudioSystemLegacy.h>
+
+namespace android_audio_legacy {
+using android::String8;
+using android::ToneGenerator;
+using android::Vector;
+
+// ----------------------------------------------------------------------------
+
+// The AudioPolicyInterface and AudioPolicyClientInterface classes define the communication
+// interfaces between the platform specific audio policy manager and Android generic audio policy
+// manager. The platform specific audio policy manager must implement methods of the
+// AudioPolicyInterface class. This implementation makes use of the AudioPolicyClientInterface to
+// control the activity and configuration of audio input and output streams.
+//
+// The platform specific audio policy manager is in charge of the audio routing and volume control
+// policies for a given platform.
+// The main roles of this module are:
+// - keep track of current system state (removable device connections, phone state, user
+// requests...). System state changes and user actions are notified to audio policy manager with
+// methods of the AudioPolicyInterface.
+// - process getOutput() queries received when AudioTrack objects are created: Those queries
+// return a handler on an output that has been selected, configured and opened by the audio policy
+// manager and that must be used by the AudioTrack when registering to the AudioFlinger with the
+// createTrack() method. When the AudioTrack object is released, a putOutput() query is received
+// and the audio policy manager can decide to close or reconfigure the output depending on other
+// streams using this output and current system state.
+// - similarly process getInput() and putInput() queries received from AudioRecord objects and
+// configure audio inputs.
+// - process volume control requests: the stream volume is converted from an index value (received
+// from UI) to a float value applicable to each output as a function of platform specific settings
+// and current output route (destination device). It also make sure that streams are not muted if
+// not allowed (e.g. camera shutter sound in some countries).
+//
+// The platform specific audio policy manager is provided as a shared library by platform vendors
+// (as for libaudio.so) and is linked with libaudioflinger.so
+
+// Audio Policy Manager Interface
+class AudioPolicyInterface {
+ public:
+ virtual ~AudioPolicyInterface() {}
+ //
+ // configuration functions
+ //
+
+ // indicate a change in device connection status
+ virtual status_t setDeviceConnectionState(audio_devices_t device,
+ AudioSystem::device_connection_state state,
+ const char* device_address) = 0;
+ // retrieve a device connection status
+ virtual AudioSystem::device_connection_state getDeviceConnectionState(
+ audio_devices_t device, const char* device_address) = 0;
+ // indicate a change in phone state. Valid phones states are defined by AudioSystem::audio_mode
+ virtual void setPhoneState(int state) = 0;
+ // force using a specific device category for the specified usage
+ virtual void setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config) = 0;
+ // retrieve current device category forced for a given usage
+ virtual AudioSystem::forced_config getForceUse(AudioSystem::force_use usage) = 0;
+ // set a system property (e.g. camera sound always audible)
+ virtual void setSystemProperty(const char* property, const char* value) = 0;
+ // check proper initialization
+ virtual status_t initCheck() = 0;
+
+ //
+ // Audio routing query functions
+ //
+
+ // request an output appropriate for playback of the supplied stream type and parameters
+ virtual audio_io_handle_t getOutput(AudioSystem::stream_type stream, uint32_t samplingRate,
+ audio_format_t format, audio_channel_mask_t channelMask,
+ AudioSystem::output_flags flags,
+ const audio_offload_info_t* offloadInfo) = 0;
+ // indicates to the audio policy manager that the output starts being used by corresponding
+ // stream.
+ virtual status_t startOutput(audio_io_handle_t output, AudioSystem::stream_type stream,
+ audio_session_t session = AUDIO_SESSION_NONE) = 0;
+ // indicates to the audio policy manager that the output stops being used by corresponding
+ // stream.
+ virtual status_t stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream,
+ audio_session_t session = AUDIO_SESSION_NONE) = 0;
+ // releases the output.
+ virtual void releaseOutput(audio_io_handle_t output) = 0;
+
+ // request an input appropriate for record from the supplied device with supplied parameters.
+ virtual audio_io_handle_t getInput(int inputSource, uint32_t samplingRate,
+ audio_format_t format, audio_channel_mask_t channelMask,
+ AudioSystem::audio_in_acoustics acoustics) = 0;
+ // indicates to the audio policy manager that the input starts being used.
+ virtual status_t startInput(audio_io_handle_t input) = 0;
+ // indicates to the audio policy manager that the input stops being used.
+ virtual status_t stopInput(audio_io_handle_t input) = 0;
+ // releases the input.
+ virtual void releaseInput(audio_io_handle_t input) = 0;
+
+ //
+ // volume control functions
+ //
+
+ // initialises stream volume conversion parameters by specifying volume index range.
+ virtual void initStreamVolume(AudioSystem::stream_type stream, int indexMin, int indexMax) = 0;
+
+ // sets the new stream volume at a level corresponding to the supplied index for the
+ // supplied device. By convention, specifying AUDIO_DEVICE_OUT_DEFAULT means
+ // setting volume for all devices
+ virtual status_t setStreamVolumeIndex(AudioSystem::stream_type stream, int index,
+ audio_devices_t device) = 0;
+
+ // retrieve current volume index for the specified stream and the
+ // specified device. By convention, specifying AUDIO_DEVICE_OUT_DEFAULT means
+ // querying the volume of the active device.
+ virtual status_t getStreamVolumeIndex(AudioSystem::stream_type stream, int* index,
+ audio_devices_t device) = 0;
+
+ // return the strategy corresponding to a given stream type
+ virtual uint32_t getStrategyForStream(AudioSystem::stream_type stream) = 0;
+
+ // return the enabled output devices for the given stream type
+ virtual audio_devices_t getDevicesForStream(AudioSystem::stream_type stream) = 0;
+
+ // Audio effect management
+ virtual audio_io_handle_t getOutputForEffect(const effect_descriptor_t* desc) = 0;
+ virtual status_t registerEffect(const effect_descriptor_t* desc, audio_io_handle_t io,
+ uint32_t strategy, audio_session_t session, int id) = 0;
+ virtual status_t unregisterEffect(int id) = 0;
+ virtual status_t setEffectEnabled(int id, bool enabled) = 0;
+
+ virtual bool isStreamActive(int stream, uint32_t inPastMs = 0) const = 0;
+ virtual bool isStreamActiveRemotely(int stream, uint32_t inPastMs = 0) const = 0;
+ virtual bool isSourceActive(audio_source_t source) const = 0;
+
+ // dump state
+ virtual status_t dump(int fd) = 0;
+
+ virtual bool isOffloadSupported(const audio_offload_info_t& offloadInfo) = 0;
+};
+
+// Audio Policy client Interface
+class AudioPolicyClientInterface {
+ public:
+ virtual ~AudioPolicyClientInterface() {}
+
+ //
+ // Audio HW module functions
+ //
+
+ // loads a HW module.
+ virtual audio_module_handle_t loadHwModule(const char* name) = 0;
+
+ //
+ // Audio output Control functions
+ //
+
+ // opens an audio output with the requested parameters. The parameter values can indicate to use
+ // the default values in case the audio policy manager has no specific requirements for the
+ // output being opened. When the function returns, the parameter values reflect the actual
+ // values used by the audio hardware output stream. The audio policy manager can check if the
+ // proposed parameters are suitable or not and act accordingly.
+ virtual audio_io_handle_t openOutput(audio_module_handle_t module, audio_devices_t* pDevices,
+ uint32_t* pSamplingRate, audio_format_t* pFormat,
+ audio_channel_mask_t* pChannelMask, uint32_t* pLatencyMs,
+ audio_output_flags_t flags,
+ const audio_offload_info_t* offloadInfo = NULL) = 0;
+ // creates a special output that is duplicated to the two outputs passed as arguments. The
+ // duplication is performed by a special mixer thread in the AudioFlinger.
+ virtual audio_io_handle_t openDuplicateOutput(audio_io_handle_t output1,
+ audio_io_handle_t output2) = 0;
+ // closes the output stream
+ virtual status_t closeOutput(audio_io_handle_t output) = 0;
+ // suspends the output. When an output is suspended, the corresponding audio hardware output
+ // stream is placed in standby and the AudioTracks attached to the mixer thread are still
+ // processed but the output mix is discarded.
+ virtual status_t suspendOutput(audio_io_handle_t output) = 0;
+ // restores a suspended output.
+ virtual status_t restoreOutput(audio_io_handle_t output) = 0;
+
+ //
+ // Audio input Control functions
+ //
+
+ // opens an audio input
+ virtual audio_io_handle_t openInput(audio_module_handle_t module, audio_devices_t* pDevices,
+ uint32_t* pSamplingRate, audio_format_t* pFormat,
+ audio_channel_mask_t* pChannelMask) = 0;
+ // closes an audio input
+ virtual status_t closeInput(audio_io_handle_t input) = 0;
+ //
+ // misc control functions
+ //
+
+ // set a stream volume for a particular output. For the same user setting, a given stream type
+ // can have different volumes for each output (destination device) it is attached to.
+ virtual status_t setStreamVolume(AudioSystem::stream_type stream, float volume,
+ audio_io_handle_t output, int delayMs = 0) = 0;
+
+ // invalidate a stream type, causing a reroute to an unspecified new output
+ virtual status_t invalidateStream(AudioSystem::stream_type stream) = 0;
+
+ // function enabling to send proprietary informations directly from audio policy manager to
+ // audio hardware interface.
+ virtual void setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs,
+ int delayMs = 0) = 0;
+ // function enabling to receive proprietary informations directly from audio hardware interface
+ // to audio policy manager.
+ virtual String8 getParameters(audio_io_handle_t ioHandle, const String8& keys) = 0;
+
+ // request the playback of a tone on the specified stream: used for instance to replace
+ // notification sounds when playing over a telephony device during a phone call.
+ virtual status_t startTone(ToneGenerator::tone_type tone, AudioSystem::stream_type stream) = 0;
+ virtual status_t stopTone() = 0;
+
+ // set down link audio volume.
+ virtual status_t setVoiceVolume(float volume, int delayMs = 0) = 0;
+
+ // move effect to the specified output
+ virtual status_t moveEffects(audio_session_t session, audio_io_handle_t srcOutput,
+ audio_io_handle_t dstOutput) = 0;
+};
+
+extern "C" AudioPolicyInterface* createAudioPolicyManager(
+ AudioPolicyClientInterface* clientInterface);
+extern "C" void destroyAudioPolicyManager(AudioPolicyInterface* interface);
+
+}; // namespace android_audio_legacy
+
+#endif // ANDROID_AUDIOPOLICYINTERFACE_H
diff --git a/wifi/1.6/default/hal_legacy/AudioPolicyManagerBase.h b/wifi/1.6/default/hal_legacy/AudioPolicyManagerBase.h
new file mode 100644
index 0000000..ccc0d32
--- /dev/null
+++ b/wifi/1.6/default/hal_legacy/AudioPolicyManagerBase.h
@@ -0,0 +1,567 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <cutils/config_utils.h>
+#include <cutils/misc.h>
+#include <hardware_legacy/AudioPolicyInterface.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/SortedVector.h>
+#include <utils/Timers.h>
+
+namespace android_audio_legacy {
+using android::DefaultKeyedVector;
+using android::KeyedVector;
+using android::SortedVector;
+
+// ----------------------------------------------------------------------------
+
+#define MAX_DEVICE_ADDRESS_LEN 20
+// Attenuation applied to STRATEGY_SONIFICATION streams when a headset is connected: 6dB
+#define SONIFICATION_HEADSET_VOLUME_FACTOR 0.5
+// Min volume for STRATEGY_SONIFICATION streams when limited by music volume: -36dB
+#define SONIFICATION_HEADSET_VOLUME_MIN 0.016
+// Time in milliseconds during which we consider that music is still active after a music
+// track was stopped - see computeVolume()
+#define SONIFICATION_HEADSET_MUSIC_DELAY 5000
+// Time in milliseconds after media stopped playing during which we consider that the
+// sonification should be as unobtrusive as during the time media was playing.
+#define SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY 5000
+// Time in milliseconds during witch some streams are muted while the audio path
+// is switched
+#define MUTE_TIME_MS 2000
+
+#define NUM_TEST_OUTPUTS 5
+
+#define NUM_VOL_CURVE_KNEES 2
+
+// Default minimum length allowed for offloading a compressed track
+// Can be overridden by the audio.offload.min.duration.secs property
+#define OFFLOAD_DEFAULT_MIN_DURATION_SECS 60
+
+// ----------------------------------------------------------------------------
+// AudioPolicyManagerBase implements audio policy manager behavior common to all platforms.
+// Each platform must implement an AudioPolicyManager class derived from AudioPolicyManagerBase
+// and override methods for which the platform specific behavior differs from the implementation
+// in AudioPolicyManagerBase. Even if no specific behavior is required, the AudioPolicyManager
+// class must be implemented as well as the class factory function createAudioPolicyManager()
+// and provided in a shared library libaudiopolicy.so.
+// ----------------------------------------------------------------------------
+
+class AudioPolicyManagerBase : public AudioPolicyInterface
+#ifdef AUDIO_POLICY_TEST
+ ,
+ public Thread
+#endif // AUDIO_POLICY_TEST
+{
+
+ public:
+ AudioPolicyManagerBase(AudioPolicyClientInterface* clientInterface);
+ virtual ~AudioPolicyManagerBase();
+
+ // AudioPolicyInterface
+ virtual status_t setDeviceConnectionState(audio_devices_t device,
+ AudioSystem::device_connection_state state,
+ const char* device_address);
+ virtual AudioSystem::device_connection_state getDeviceConnectionState(
+ audio_devices_t device, const char* device_address);
+ virtual void setPhoneState(int state);
+ virtual void setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config);
+ virtual AudioSystem::forced_config getForceUse(AudioSystem::force_use usage);
+ virtual void setSystemProperty(const char* property, const char* value);
+ virtual status_t initCheck();
+ virtual audio_io_handle_t getOutput(AudioSystem::stream_type stream, uint32_t samplingRate,
+ audio_format_t format, audio_channel_mask_t channelMask,
+ AudioSystem::output_flags flags,
+ const audio_offload_info_t* offloadInfo);
+ virtual status_t startOutput(audio_io_handle_t output, AudioSystem::stream_type stream,
+ audio_session_t session = AUDIO_SESSION_NONE);
+ virtual status_t stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream,
+ audio_session_t session = AUDIO_SESSION_NONE);
+ virtual void releaseOutput(audio_io_handle_t output);
+ virtual audio_io_handle_t getInput(int inputSource, uint32_t samplingRate,
+ audio_format_t format, audio_channel_mask_t channelMask,
+ AudioSystem::audio_in_acoustics acoustics);
+
+ // indicates to the audio policy manager that the input starts being used.
+ virtual status_t startInput(audio_io_handle_t input);
+
+ // indicates to the audio policy manager that the input stops being used.
+ virtual status_t stopInput(audio_io_handle_t input);
+ virtual void releaseInput(audio_io_handle_t input);
+ virtual void closeAllInputs();
+ virtual void initStreamVolume(AudioSystem::stream_type stream, int indexMin, int indexMax);
+ virtual status_t setStreamVolumeIndex(AudioSystem::stream_type stream, int index,
+ audio_devices_t device);
+ virtual status_t getStreamVolumeIndex(AudioSystem::stream_type stream, int* index,
+ audio_devices_t device);
+
+ // return the strategy corresponding to a given stream type
+ virtual uint32_t getStrategyForStream(AudioSystem::stream_type stream);
+
+ // return the enabled output devices for the given stream type
+ virtual audio_devices_t getDevicesForStream(AudioSystem::stream_type stream);
+
+ virtual audio_io_handle_t getOutputForEffect(const effect_descriptor_t* desc = NULL);
+ virtual status_t registerEffect(const effect_descriptor_t* desc, audio_io_handle_t io,
+ uint32_t strategy, audio_session_t session, int id);
+ virtual status_t unregisterEffect(int id);
+ virtual status_t setEffectEnabled(int id, bool enabled);
+
+ virtual bool isStreamActive(int stream, uint32_t inPastMs = 0) const;
+ // return whether a stream is playing remotely, override to change the definition of
+ // local/remote playback, used for instance by notification manager to not make
+ // media players lose audio focus when not playing locally
+ virtual bool isStreamActiveRemotely(int stream, uint32_t inPastMs = 0) const;
+ virtual bool isSourceActive(audio_source_t source) const;
+
+ virtual status_t dump(int fd);
+
+ virtual bool isOffloadSupported(const audio_offload_info_t& offloadInfo);
+
+ protected:
+ enum routing_strategy {
+ STRATEGY_MEDIA,
+ STRATEGY_PHONE,
+ STRATEGY_SONIFICATION,
+ STRATEGY_SONIFICATION_RESPECTFUL,
+ STRATEGY_DTMF,
+ STRATEGY_ENFORCED_AUDIBLE,
+ NUM_STRATEGIES
+ };
+
+ // 4 points to define the volume attenuation curve, each characterized by the volume
+ // index (from 0 to 100) at which they apply, and the attenuation in dB at that index.
+ // we use 100 steps to avoid rounding errors when computing the volume in volIndexToAmpl()
+
+ enum { VOLMIN = 0, VOLKNEE1 = 1, VOLKNEE2 = 2, VOLMAX = 3, VOLCNT = 4 };
+
+ class VolumeCurvePoint {
+ public:
+ int mIndex;
+ float mDBAttenuation;
+ };
+
+ // device categories used for volume curve management.
+ enum device_category {
+ DEVICE_CATEGORY_HEADSET,
+ DEVICE_CATEGORY_SPEAKER,
+ DEVICE_CATEGORY_EARPIECE,
+ DEVICE_CATEGORY_CNT
+ };
+
+ class IOProfile;
+
+ class HwModule {
+ public:
+ HwModule(const char* name);
+ ~HwModule();
+
+ void dump(int fd);
+
+ const char* const mName; // base name of the audio HW module (primary, a2dp ...)
+ audio_module_handle_t mHandle;
+ Vector<IOProfile*> mOutputProfiles; // output profiles exposed by this module
+ Vector<IOProfile*> mInputProfiles; // input profiles exposed by this module
+ };
+
+ // the IOProfile class describes the capabilities of an output or input stream.
+ // It is currently assumed that all combination of listed parameters are supported.
+ // It is used by the policy manager to determine if an output or input is suitable for
+ // a given use case, open/close it accordingly and connect/disconnect audio tracks
+ // to/from it.
+ class IOProfile {
+ public:
+ IOProfile(HwModule* module);
+ ~IOProfile();
+
+ bool isCompatibleProfile(audio_devices_t device, uint32_t samplingRate,
+ audio_format_t format, audio_channel_mask_t channelMask,
+ audio_output_flags_t flags) const;
+
+ void dump(int fd);
+ void log();
+
+ // by convention, "0' in the first entry in mSamplingRates, mChannelMasks or mFormats
+ // indicates the supported parameters should be read from the output stream
+ // after it is opened for the first time
+ Vector<uint32_t> mSamplingRates; // supported sampling rates
+ Vector<audio_channel_mask_t> mChannelMasks; // supported channel masks
+ Vector<audio_format_t> mFormats; // supported audio formats
+ audio_devices_t mSupportedDevices; // supported devices (devices this output can be
+ // routed to)
+ audio_output_flags_t mFlags; // attribute flags (e.g primary output,
+ // direct output...). For outputs only.
+ HwModule* mModule; // audio HW module exposing this I/O stream
+ };
+
+ // default volume curve
+ static const VolumeCurvePoint sDefaultVolumeCurve[AudioPolicyManagerBase::VOLCNT];
+ // default volume curve for media strategy
+ static const VolumeCurvePoint sDefaultMediaVolumeCurve[AudioPolicyManagerBase::VOLCNT];
+ // volume curve for media strategy on speakers
+ static const VolumeCurvePoint sSpeakerMediaVolumeCurve[AudioPolicyManagerBase::VOLCNT];
+ // volume curve for sonification strategy on speakers
+ static const VolumeCurvePoint sSpeakerSonificationVolumeCurve[AudioPolicyManagerBase::VOLCNT];
+ static const VolumeCurvePoint
+ sSpeakerSonificationVolumeCurveDrc[AudioPolicyManagerBase::VOLCNT];
+ static const VolumeCurvePoint sDefaultSystemVolumeCurve[AudioPolicyManagerBase::VOLCNT];
+ static const VolumeCurvePoint sDefaultSystemVolumeCurveDrc[AudioPolicyManagerBase::VOLCNT];
+ static const VolumeCurvePoint sHeadsetSystemVolumeCurve[AudioPolicyManagerBase::VOLCNT];
+ static const VolumeCurvePoint sDefaultVoiceVolumeCurve[AudioPolicyManagerBase::VOLCNT];
+ static const VolumeCurvePoint sSpeakerVoiceVolumeCurve[AudioPolicyManagerBase::VOLCNT];
+ // default volume curves per stream and device category. See initializeVolumeCurves()
+ static const VolumeCurvePoint* sVolumeProfiles[AudioSystem::NUM_STREAM_TYPES]
+ [DEVICE_CATEGORY_CNT];
+
+ // descriptor for audio outputs. Used to maintain current configuration of each opened audio
+ // output and keep track of the usage of this output by each audio stream type.
+ class AudioOutputDescriptor {
+ public:
+ AudioOutputDescriptor(const IOProfile* profile);
+
+ status_t dump(int fd);
+
+ audio_devices_t device() const;
+ void changeRefCount(AudioSystem::stream_type stream, int delta);
+
+ bool isDuplicated() const { return (mOutput1 != NULL && mOutput2 != NULL); }
+ audio_devices_t supportedDevices();
+ uint32_t latency();
+ bool sharesHwModuleWith(const AudioOutputDescriptor* outputDesc);
+ bool isActive(uint32_t inPastMs = 0) const;
+ bool isStreamActive(AudioSystem::stream_type stream, uint32_t inPastMs = 0,
+ nsecs_t sysTime = 0) const;
+ bool isStrategyActive(routing_strategy strategy, uint32_t inPastMs = 0,
+ nsecs_t sysTime = 0) const;
+
+ audio_io_handle_t mId; // output handle
+ uint32_t mSamplingRate; //
+ audio_format_t mFormat; //
+ audio_channel_mask_t mChannelMask; // output configuration
+ uint32_t mLatency; //
+ audio_output_flags_t mFlags; //
+ audio_devices_t mDevice; // current device this output is routed to
+ uint32_t mRefCount[AudioSystem::NUM_STREAM_TYPES]; // number of streams of each type using
+ // this output
+ nsecs_t mStopTime[AudioSystem::NUM_STREAM_TYPES];
+ AudioOutputDescriptor* mOutput1; // used by duplicated outputs: first output
+ AudioOutputDescriptor* mOutput2; // used by duplicated outputs: second output
+ float mCurVolume[AudioSystem::NUM_STREAM_TYPES]; // current stream volume
+ int mMuteCount[AudioSystem::NUM_STREAM_TYPES]; // mute request counter
+ const IOProfile* mProfile; // I/O profile this output derives from
+ bool mStrategyMutedByDevice[NUM_STRATEGIES]; // strategies muted because of incompatible
+ // device selection. See
+ // checkDeviceMuteStrategies()
+ uint32_t mDirectOpenCount; // number of clients using this output (direct outputs only)
+ bool mForceRouting; // Next routing for this output will be forced as current device routed
+ // is null
+ };
+
+ // descriptor for audio inputs. Used to maintain current configuration of each opened audio
+ // input and keep track of the usage of this input.
+ class AudioInputDescriptor {
+ public:
+ AudioInputDescriptor(const IOProfile* profile);
+
+ status_t dump(int fd);
+
+ audio_io_handle_t mId; // input handle
+ uint32_t mSamplingRate; //
+ audio_format_t mFormat; // input configuration
+ audio_channel_mask_t mChannelMask; //
+ audio_devices_t mDevice; // current device this input is routed to
+ uint32_t mRefCount; // number of AudioRecord clients using this output
+ int mInputSource; // input source selected by application (mediarecorder.h)
+ const IOProfile* mProfile; // I/O profile this output derives from
+ };
+
+ // stream descriptor used for volume control
+ class StreamDescriptor {
+ public:
+ StreamDescriptor();
+
+ int getVolumeIndex(audio_devices_t device);
+ void dump(int fd);
+
+ int mIndexMin; // min volume index
+ int mIndexMax; // max volume index
+ KeyedVector<audio_devices_t, int> mIndexCur; // current volume index per device
+ bool mCanBeMuted; // true is the stream can be muted
+
+ const VolumeCurvePoint* mVolumeCurve[DEVICE_CATEGORY_CNT];
+ };
+
+ // stream descriptor used for volume control
+ class EffectDescriptor {
+ public:
+ status_t dump(int fd);
+
+ int mIo; // io the effect is attached to
+ routing_strategy mStrategy; // routing strategy the effect is associated to
+ audio_session_t mSession; // audio session the effect is on
+ effect_descriptor_t mDesc; // effect descriptor
+ bool mEnabled; // enabled state: CPU load being used or not
+ };
+
+ void addOutput(audio_io_handle_t id, AudioOutputDescriptor* outputDesc);
+ void addInput(audio_io_handle_t id, AudioInputDescriptor* inputDesc);
+
+ // return the strategy corresponding to a given stream type
+ static routing_strategy getStrategy(AudioSystem::stream_type stream);
+
+ // return appropriate device for streams handled by the specified strategy according to current
+ // phone state, connected devices...
+ // if fromCache is true, the device is returned from mDeviceForStrategy[],
+ // otherwise it is determine by current state
+ // (device connected,phone state, force use, a2dp output...)
+ // This allows to:
+ // 1 speed up process when the state is stable (when starting or stopping an output)
+ // 2 access to either current device selection (fromCache == true) or
+ // "future" device selection (fromCache == false) when called from a context
+ // where conditions are changing (setDeviceConnectionState(), setPhoneState()...) AND
+ // before updateDevicesAndOutputs() is called.
+ virtual audio_devices_t getDeviceForStrategy(routing_strategy strategy, bool fromCache);
+
+ // change the route of the specified output. Returns the number of ms we have slept to
+ // allow new routing to take effect in certain cases.
+ uint32_t setOutputDevice(audio_io_handle_t output, audio_devices_t device, bool force = false,
+ int delayMs = 0);
+
+ // select input device corresponding to requested audio source
+ virtual audio_devices_t getDeviceForInputSource(int inputSource);
+
+ // return io handle of active input or 0 if no input is active
+ // Only considers inputs from physical devices (e.g. main mic, headset mic) when
+ // ignoreVirtualInputs is true.
+ audio_io_handle_t getActiveInput(bool ignoreVirtualInputs = true);
+
+ // initialize volume curves for each strategy and device category
+ void initializeVolumeCurves();
+
+ // compute the actual volume for a given stream according to the requested index and a
+ // particular device
+ virtual float computeVolume(int stream, int index, audio_io_handle_t output,
+ audio_devices_t device);
+
+ // check that volume change is permitted, compute and send new volume to audio hardware
+ status_t checkAndSetVolume(int stream, int index, audio_io_handle_t output,
+ audio_devices_t device, int delayMs = 0, bool force = false);
+
+ // apply all stream volumes to the specified output and device
+ void applyStreamVolumes(audio_io_handle_t output, audio_devices_t device, int delayMs = 0,
+ bool force = false);
+
+ // Mute or unmute all streams handled by the specified strategy on the specified output
+ void setStrategyMute(routing_strategy strategy, bool on, audio_io_handle_t output,
+ int delayMs = 0, audio_devices_t device = (audio_devices_t)0);
+
+ // Mute or unmute the stream on the specified output
+ void setStreamMute(int stream, bool on, audio_io_handle_t output, int delayMs = 0,
+ audio_devices_t device = (audio_devices_t)0);
+
+ // handle special cases for sonification strategy while in call: mute streams or replace by
+ // a special tone in the device used for communication
+ void handleIncallSonification(int stream, bool starting, bool stateChange);
+
+ // true if device is in a telephony or VoIP call
+ virtual bool isInCall();
+
+ // true if given state represents a device in a telephony or VoIP call
+ virtual bool isStateInCall(int state);
+
+ // when a device is connected, checks if an open output can be routed
+ // to this device. If none is open, tries to open one of the available outputs.
+ // Returns an output suitable to this device or 0.
+ // when a device is disconnected, checks if an output is not used any more and
+ // returns its handle if any.
+ // transfers the audio tracks and effects from one output thread to another accordingly.
+ status_t checkOutputsForDevice(audio_devices_t device,
+ AudioSystem::device_connection_state state,
+ SortedVector<audio_io_handle_t>& outputs,
+ const String8 paramStr);
+
+ status_t checkInputsForDevice(audio_devices_t device,
+ AudioSystem::device_connection_state state,
+ SortedVector<audio_io_handle_t>& inputs, const String8 paramStr);
+
+ // close an output and its companion duplicating output.
+ void closeOutput(audio_io_handle_t output);
+
+ // checks and if necessary changes outputs used for all strategies.
+ // must be called every time a condition that affects the output choice for a given strategy
+ // changes: connected device, phone state, force use...
+ // Must be called before updateDevicesAndOutputs()
+ void checkOutputForStrategy(routing_strategy strategy);
+
+ // Same as checkOutputForStrategy() but for a all strategies in order of priority
+ void checkOutputForAllStrategies();
+
+ // manages A2DP output suspend/restore according to phone state and BT SCO usage
+ void checkA2dpSuspend();
+
+ // returns the A2DP output handle if it is open or 0 otherwise
+ audio_io_handle_t getA2dpOutput();
+
+ // selects the most appropriate device on output for current state
+ // must be called every time a condition that affects the device choice for a given output is
+ // changed: connected device, phone state, force use, output start, output stop..
+ // see getDeviceForStrategy() for the use of fromCache parameter
+
+ audio_devices_t getNewDevice(audio_io_handle_t output, bool fromCache);
+ // updates cache of device used by all strategies (mDeviceForStrategy[])
+ // must be called every time a condition that affects the device choice for a given strategy is
+ // changed: connected device, phone state, force use...
+ // cached values are used by getDeviceForStrategy() if parameter fromCache is true.
+ // Must be called after checkOutputForAllStrategies()
+
+ void updateDevicesAndOutputs();
+
+ virtual uint32_t getMaxEffectsCpuLoad();
+ virtual uint32_t getMaxEffectsMemory();
+#ifdef AUDIO_POLICY_TEST
+ virtual bool threadLoop();
+ void exit();
+ int testOutputIndex(audio_io_handle_t output);
+#endif // AUDIO_POLICY_TEST
+
+ status_t setEffectEnabled(EffectDescriptor* pDesc, bool enabled);
+
+ // returns the category the device belongs to with regard to volume curve management
+ static device_category getDeviceCategory(audio_devices_t device);
+
+ // extract one device relevant for volume control from multiple device selection
+ static audio_devices_t getDeviceForVolume(audio_devices_t device);
+
+ SortedVector<audio_io_handle_t> getOutputsForDevice(
+ audio_devices_t device,
+ DefaultKeyedVector<audio_io_handle_t, AudioOutputDescriptor*> openOutputs);
+ bool vectorsEqual(SortedVector<audio_io_handle_t>& outputs1,
+ SortedVector<audio_io_handle_t>& outputs2);
+
+ // mute/unmute strategies using an incompatible device combination
+ // if muting, wait for the audio in pcm buffer to be drained before proceeding
+ // if unmuting, unmute only after the specified delay
+ // Returns the number of ms waited
+ uint32_t checkDeviceMuteStrategies(AudioOutputDescriptor* outputDesc,
+ audio_devices_t prevDevice, uint32_t delayMs);
+
+ audio_io_handle_t selectOutput(const SortedVector<audio_io_handle_t>& outputs,
+ AudioSystem::output_flags flags);
+ IOProfile* getInputProfile(audio_devices_t device, uint32_t samplingRate, audio_format_t format,
+ audio_channel_mask_t channelMask);
+ IOProfile* getProfileForDirectOutput(audio_devices_t device, uint32_t samplingRate,
+ audio_format_t format, audio_channel_mask_t channelMask,
+ audio_output_flags_t flags);
+
+ audio_io_handle_t selectOutputForEffects(const SortedVector<audio_io_handle_t>& outputs);
+
+ bool isNonOffloadableEffectEnabled();
+
+ //
+ // Audio policy configuration file parsing (audio_policy.conf)
+ //
+ static uint32_t stringToEnum(const struct StringToEnum* table, size_t size, const char* name);
+ static bool stringToBool(const char* value);
+ static audio_output_flags_t parseFlagNames(char* name);
+ static audio_devices_t parseDeviceNames(char* name);
+ void loadSamplingRates(char* name, IOProfile* profile);
+ void loadFormats(char* name, IOProfile* profile);
+ void loadOutChannels(char* name, IOProfile* profile);
+ void loadInChannels(char* name, IOProfile* profile);
+ status_t loadOutput(cnode* root, HwModule* module);
+ status_t loadInput(cnode* root, HwModule* module);
+ void loadHwModule(cnode* root);
+ void loadHwModules(cnode* root);
+ void loadGlobalConfig(cnode* root);
+ status_t loadAudioPolicyConfig(const char* path);
+ void defaultAudioPolicyConfig(void);
+
+ AudioPolicyClientInterface* mpClientInterface; // audio policy client interface
+ audio_io_handle_t mPrimaryOutput; // primary output handle
+ // list of descriptors for outputs currently opened
+ DefaultKeyedVector<audio_io_handle_t, AudioOutputDescriptor*> mOutputs;
+ // copy of mOutputs before setDeviceConnectionState() opens new outputs
+ // reset to mOutputs when updateDevicesAndOutputs() is called.
+ DefaultKeyedVector<audio_io_handle_t, AudioOutputDescriptor*> mPreviousOutputs;
+
+ // list of input descriptors currently opened
+ DefaultKeyedVector<audio_io_handle_t, AudioInputDescriptor*> mInputs;
+
+ audio_devices_t mAvailableOutputDevices; // bit field of all available output devices
+ audio_devices_t mAvailableInputDevices; // bit field of all available input devices
+ // without AUDIO_DEVICE_BIT_IN to allow direct bit
+ // field comparisons
+ int mPhoneState; // current phone state
+ AudioSystem::forced_config
+ mForceUse[AudioSystem::NUM_FORCE_USE]; // current forced use configuration
+
+ StreamDescriptor
+ mStreams[AudioSystem::NUM_STREAM_TYPES]; // stream descriptors for volume control
+ String8 mA2dpDeviceAddress; // A2DP device MAC address
+ String8 mScoDeviceAddress; // SCO device MAC address
+ String8 mUsbOutCardAndDevice; // USB audio ALSA card and device numbers:
+ // card=<card_number>;device=<><device_number>
+ bool mLimitRingtoneVolume; // limit ringtone volume to music volume if headset connected
+ audio_devices_t mDeviceForStrategy[NUM_STRATEGIES];
+ float mLastVoiceVolume; // last voice volume value sent to audio HAL
+
+ // Maximum CPU load allocated to audio effects in 0.1 MIPS (ARMv5TE, 0 WS memory) units
+ static const uint32_t MAX_EFFECTS_CPU_LOAD = 1000;
+ // Maximum memory allocated to audio effects in KB
+ static const uint32_t MAX_EFFECTS_MEMORY = 512;
+ uint32_t mTotalEffectsCpuLoad; // current CPU load used by effects
+ uint32_t mTotalEffectsMemory; // current memory used by effects
+ KeyedVector<int, EffectDescriptor*> mEffects; // list of registered audio effects
+ bool mA2dpSuspended; // true if A2DP output is suspended
+ bool mHasA2dp; // true on platforms with support for bluetooth A2DP
+ bool mHasUsb; // true on platforms with support for USB audio
+ bool mHasRemoteSubmix; // true on platforms with support for remote presentation of a submix
+ audio_devices_t mAttachedOutputDevices; // output devices always available on the platform
+ audio_devices_t mDefaultOutputDevice; // output device selected by default at boot time
+ // (must be in mAttachedOutputDevices)
+ bool mSpeakerDrcEnabled; // true on devices that use DRC on the DEVICE_CATEGORY_SPEAKER path
+ // to boost soft sounds, used to adjust volume curves accordingly
+
+ Vector<HwModule*> mHwModules;
+
+#ifdef AUDIO_POLICY_TEST
+ Mutex mLock;
+ Condition mWaitWorkCV;
+
+ int mCurOutput;
+ bool mDirectOutput;
+ audio_io_handle_t mTestOutputs[NUM_TEST_OUTPUTS];
+ int mTestInput;
+ uint32_t mTestDevice;
+ uint32_t mTestSamplingRate;
+ uint32_t mTestFormat;
+ uint32_t mTestChannels;
+ uint32_t mTestLatencyMs;
+#endif // AUDIO_POLICY_TEST
+
+ private:
+ static float volIndexToAmpl(audio_devices_t device, const StreamDescriptor& streamDesc,
+ int indexInUi);
+ // updates device caching and output for streams that can influence the
+ // routing of notifications
+ void handleNotificationRoutingForStream(AudioSystem::stream_type stream);
+ static bool isVirtualInputDevice(audio_devices_t device);
+};
+
+}; // namespace android_audio_legacy
diff --git a/wifi/1.6/default/hal_legacy/AudioSystemLegacy.h b/wifi/1.6/default/hal_legacy/AudioSystemLegacy.h
new file mode 100644
index 0000000..943b0db
--- /dev/null
+++ b/wifi/1.6/default/hal_legacy/AudioSystemLegacy.h
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIOSYSTEM_LEGACY_H_
+#define ANDROID_AUDIOSYSTEM_LEGACY_H_
+
+#include <cutils/bitops.h>
+#include <media/AudioParameter.h>
+#include <utils/Errors.h>
+
+#include <system/audio.h>
+#include <system/audio_policy.h>
+
+namespace android_audio_legacy {
+
+using android::AudioParameter;
+using android::status_t;
+
+enum {
+ OK = android::OK,
+ NO_ERROR = android::NO_ERROR,
+
+ UNKNOWN_ERROR = android::UNKNOWN_ERROR,
+
+ NO_MEMORY = android::NO_MEMORY,
+ INVALID_OPERATION = android::INVALID_OPERATION,
+ BAD_VALUE = android::BAD_VALUE,
+ BAD_TYPE = android::BAD_TYPE,
+ NAME_NOT_FOUND = android::NAME_NOT_FOUND,
+ PERMISSION_DENIED = android::PERMISSION_DENIED,
+ NO_INIT = android::NO_INIT,
+ ALREADY_EXISTS = android::ALREADY_EXISTS,
+ DEAD_OBJECT = android::DEAD_OBJECT,
+ FAILED_TRANSACTION = android::FAILED_TRANSACTION,
+ BAD_INDEX = android::BAD_INDEX,
+ NOT_ENOUGH_DATA = android::NOT_ENOUGH_DATA,
+ WOULD_BLOCK = android::WOULD_BLOCK,
+ TIMED_OUT = android::TIMED_OUT,
+ UNKNOWN_TRANSACTION = android::UNKNOWN_TRANSACTION,
+};
+
+enum audio_source {
+ AUDIO_SOURCE_DEFAULT = 0,
+ AUDIO_SOURCE_MIC = 1,
+ AUDIO_SOURCE_VOICE_UPLINK = 2,
+ AUDIO_SOURCE_VOICE_DOWNLINK = 3,
+ AUDIO_SOURCE_VOICE_CALL = 4,
+ AUDIO_SOURCE_CAMCORDER = 5,
+ AUDIO_SOURCE_VOICE_RECOGNITION = 6,
+ AUDIO_SOURCE_VOICE_COMMUNICATION = 7,
+ AUDIO_SOURCE_MAX = AUDIO_SOURCE_VOICE_COMMUNICATION,
+
+ AUDIO_SOURCE_LIST_END // must be last - used to validate audio source type
+};
+
+class AudioSystem {
+ public:
+#if 1
+ enum stream_type {
+ DEFAULT = -1,
+ VOICE_CALL = 0,
+ SYSTEM = 1,
+ RING = 2,
+ MUSIC = 3,
+ ALARM = 4,
+ NOTIFICATION = 5,
+ BLUETOOTH_SCO = 6,
+ ENFORCED_AUDIBLE = 7, // Sounds that cannot be muted by user and must be routed to speaker
+ DTMF = 8,
+ TTS = 9,
+ NUM_STREAM_TYPES
+ };
+
+ // Audio sub formats (see AudioSystem::audio_format).
+ enum pcm_sub_format {
+ PCM_SUB_16_BIT = 0x1, // must be 1 for backward compatibility
+ PCM_SUB_8_BIT = 0x2, // must be 2 for backward compatibility
+ };
+
+ enum audio_sessions {
+ SESSION_OUTPUT_STAGE = AUDIO_SESSION_OUTPUT_STAGE,
+ SESSION_OUTPUT_MIX = AUDIO_SESSION_OUTPUT_MIX,
+ };
+
+ // MP3 sub format field definition : can use 11 LSBs in the same way as MP3 frame header to
+ // specify bit rate, stereo mode, version...
+ enum mp3_sub_format {
+ // TODO
+ };
+
+ // AMR NB/WB sub format field definition: specify frame block interleaving, bandwidth efficient
+ // or octet aligned, encoding mode for recording...
+ enum amr_sub_format {
+ // TODO
+ };
+
+ // AAC sub format field definition: specify profile or bitrate for recording...
+ enum aac_sub_format {
+ // TODO
+ };
+
+ // VORBIS sub format field definition: specify quality for recording...
+ enum vorbis_sub_format {
+ // TODO
+ };
+
+ // Audio format consists in a main format field (upper 8 bits) and a sub format field (lower 24
+ // bits). The main format indicates the main codec type. The sub format field indicates options
+ // and parameters for each format. The sub format is mainly used for record to indicate for
+ // instance the requested bitrate or profile. It can also be used for certain formats to give
+ // informations not present in the encoded audio stream (e.g. octet alignement for AMR).
+ enum audio_format {
+ INVALID_FORMAT = -1,
+ FORMAT_DEFAULT = 0,
+ PCM = 0x00000000, // must be 0 for backward compatibility
+ MP3 = 0x01000000,
+ AMR_NB = 0x02000000,
+ AMR_WB = 0x03000000,
+ AAC = 0x04000000,
+ HE_AAC_V1 = 0x05000000,
+ HE_AAC_V2 = 0x06000000,
+ VORBIS = 0x07000000,
+ MAIN_FORMAT_MASK = 0xFF000000,
+ SUB_FORMAT_MASK = 0x00FFFFFF,
+ // Aliases
+ PCM_16_BIT = (PCM | PCM_SUB_16_BIT),
+ PCM_8_BIT = (PCM | PCM_SUB_8_BIT)
+ };
+
+ enum audio_channels {
+ // output channels
+ CHANNEL_OUT_FRONT_LEFT = 0x1,
+ CHANNEL_OUT_FRONT_RIGHT = 0x2,
+ CHANNEL_OUT_FRONT_CENTER = 0x4,
+ CHANNEL_OUT_LOW_FREQUENCY = 0x8,
+ CHANNEL_OUT_BACK_LEFT = 0x10,
+ CHANNEL_OUT_BACK_RIGHT = 0x20,
+ CHANNEL_OUT_FRONT_LEFT_OF_CENTER = 0x40,
+ CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = 0x80,
+ CHANNEL_OUT_BACK_CENTER = 0x100,
+ CHANNEL_OUT_SIDE_LEFT = 0x200,
+ CHANNEL_OUT_SIDE_RIGHT = 0x400,
+ CHANNEL_OUT_TOP_CENTER = 0x800,
+ CHANNEL_OUT_TOP_FRONT_LEFT = 0x1000,
+ CHANNEL_OUT_TOP_FRONT_CENTER = 0x2000,
+ CHANNEL_OUT_TOP_FRONT_RIGHT = 0x4000,
+ CHANNEL_OUT_TOP_BACK_LEFT = 0x8000,
+ CHANNEL_OUT_TOP_BACK_CENTER = 0x10000,
+ CHANNEL_OUT_TOP_BACK_RIGHT = 0x20000,
+
+ CHANNEL_OUT_MONO = CHANNEL_OUT_FRONT_LEFT,
+ CHANNEL_OUT_STEREO = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT),
+ CHANNEL_OUT_QUAD = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
+ CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT),
+ CHANNEL_OUT_SURROUND = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
+ CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_BACK_CENTER),
+ CHANNEL_OUT_5POINT1 =
+ (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT | CHANNEL_OUT_FRONT_CENTER |
+ CHANNEL_OUT_LOW_FREQUENCY | CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT),
+ // matches the correct AudioFormat.CHANNEL_OUT_7POINT1_SURROUND definition for 7.1
+ CHANNEL_OUT_7POINT1 =
+ (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT | CHANNEL_OUT_FRONT_CENTER |
+ CHANNEL_OUT_LOW_FREQUENCY | CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT |
+ CHANNEL_OUT_SIDE_LEFT | CHANNEL_OUT_SIDE_RIGHT),
+ CHANNEL_OUT_ALL =
+ (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT | CHANNEL_OUT_FRONT_CENTER |
+ CHANNEL_OUT_LOW_FREQUENCY | CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT |
+ CHANNEL_OUT_FRONT_LEFT_OF_CENTER | CHANNEL_OUT_FRONT_RIGHT_OF_CENTER |
+ CHANNEL_OUT_BACK_CENTER | CHANNEL_OUT_SIDE_LEFT | CHANNEL_OUT_SIDE_RIGHT |
+ CHANNEL_OUT_TOP_CENTER | CHANNEL_OUT_TOP_FRONT_LEFT |
+ CHANNEL_OUT_TOP_FRONT_CENTER | CHANNEL_OUT_TOP_FRONT_RIGHT |
+ CHANNEL_OUT_TOP_BACK_LEFT | CHANNEL_OUT_TOP_BACK_CENTER |
+ CHANNEL_OUT_TOP_BACK_RIGHT),
+
+ // input channels
+ CHANNEL_IN_LEFT = 0x4,
+ CHANNEL_IN_RIGHT = 0x8,
+ CHANNEL_IN_FRONT = 0x10,
+ CHANNEL_IN_BACK = 0x20,
+ CHANNEL_IN_LEFT_PROCESSED = 0x40,
+ CHANNEL_IN_RIGHT_PROCESSED = 0x80,
+ CHANNEL_IN_FRONT_PROCESSED = 0x100,
+ CHANNEL_IN_BACK_PROCESSED = 0x200,
+ CHANNEL_IN_PRESSURE = 0x400,
+ CHANNEL_IN_X_AXIS = 0x800,
+ CHANNEL_IN_Y_AXIS = 0x1000,
+ CHANNEL_IN_Z_AXIS = 0x2000,
+ CHANNEL_IN_VOICE_UPLINK = 0x4000,
+ CHANNEL_IN_VOICE_DNLINK = 0x8000,
+ CHANNEL_IN_MONO = CHANNEL_IN_FRONT,
+ CHANNEL_IN_STEREO = (CHANNEL_IN_LEFT | CHANNEL_IN_RIGHT),
+ CHANNEL_IN_ALL = (CHANNEL_IN_LEFT | CHANNEL_IN_RIGHT | CHANNEL_IN_FRONT | CHANNEL_IN_BACK |
+ CHANNEL_IN_LEFT_PROCESSED | CHANNEL_IN_RIGHT_PROCESSED |
+ CHANNEL_IN_FRONT_PROCESSED | CHANNEL_IN_BACK_PROCESSED |
+ CHANNEL_IN_PRESSURE | CHANNEL_IN_X_AXIS | CHANNEL_IN_Y_AXIS |
+ CHANNEL_IN_Z_AXIS | CHANNEL_IN_VOICE_UPLINK | CHANNEL_IN_VOICE_DNLINK)
+ };
+
+ enum audio_mode {
+ MODE_INVALID = -2,
+ MODE_CURRENT = -1,
+ MODE_NORMAL = 0,
+ MODE_RINGTONE,
+ MODE_IN_CALL,
+ MODE_IN_COMMUNICATION,
+ NUM_MODES // not a valid entry, denotes end-of-list
+ };
+
+ enum audio_in_acoustics {
+ AGC_ENABLE = 0x0001,
+ AGC_DISABLE = 0,
+ NS_ENABLE = 0x0002,
+ NS_DISABLE = 0,
+ TX_IIR_ENABLE = 0x0004,
+ TX_DISABLE = 0
+ };
+
+ // DO NOT USE: the "audio_devices" enumeration below is obsolete, use type "audio_devices_t" and
+ // audio device enumeration from system/audio.h instead.
+ enum audio_devices {
+ // output devices
+ DEVICE_OUT_EARPIECE = 0x1,
+ DEVICE_OUT_SPEAKER = 0x2,
+ DEVICE_OUT_WIRED_HEADSET = 0x4,
+ DEVICE_OUT_WIRED_HEADPHONE = 0x8,
+ DEVICE_OUT_BLUETOOTH_SCO = 0x10,
+ DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 0x20,
+ DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 0x40,
+ DEVICE_OUT_BLUETOOTH_A2DP = 0x80,
+ DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100,
+ DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200,
+ DEVICE_OUT_AUX_DIGITAL = 0x400,
+ DEVICE_OUT_ANLG_DOCK_HEADSET = 0x800,
+ DEVICE_OUT_DGTL_DOCK_HEADSET = 0x1000,
+ DEVICE_OUT_DEFAULT = 0x8000,
+ DEVICE_OUT_ALL =
+ (DEVICE_OUT_EARPIECE | DEVICE_OUT_SPEAKER | DEVICE_OUT_WIRED_HEADSET |
+ DEVICE_OUT_WIRED_HEADPHONE | DEVICE_OUT_BLUETOOTH_SCO |
+ DEVICE_OUT_BLUETOOTH_SCO_HEADSET | DEVICE_OUT_BLUETOOTH_SCO_CARKIT |
+ DEVICE_OUT_BLUETOOTH_A2DP | DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
+ DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER | DEVICE_OUT_AUX_DIGITAL |
+ DEVICE_OUT_ANLG_DOCK_HEADSET | DEVICE_OUT_DGTL_DOCK_HEADSET | DEVICE_OUT_DEFAULT),
+ DEVICE_OUT_ALL_A2DP = (DEVICE_OUT_BLUETOOTH_A2DP | DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
+ DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER),
+
+ // input devices
+ DEVICE_IN_COMMUNICATION = 0x10000,
+ DEVICE_IN_AMBIENT = 0x20000,
+ DEVICE_IN_BUILTIN_MIC = 0x40000,
+ DEVICE_IN_BLUETOOTH_SCO_HEADSET = 0x80000,
+ DEVICE_IN_WIRED_HEADSET = 0x100000,
+ DEVICE_IN_AUX_DIGITAL = 0x200000,
+ DEVICE_IN_VOICE_CALL = 0x400000,
+ DEVICE_IN_BACK_MIC = 0x800000,
+ DEVICE_IN_DEFAULT = 0x80000000,
+
+ DEVICE_IN_ALL =
+ (DEVICE_IN_COMMUNICATION | DEVICE_IN_AMBIENT | DEVICE_IN_BUILTIN_MIC |
+ DEVICE_IN_BLUETOOTH_SCO_HEADSET | DEVICE_IN_WIRED_HEADSET | DEVICE_IN_AUX_DIGITAL |
+ DEVICE_IN_VOICE_CALL | DEVICE_IN_BACK_MIC | DEVICE_IN_DEFAULT)
+ };
+
+ // request to open a direct output with getOutput() (by opposition to sharing an output with
+ // other AudioTracks)
+ enum output_flags { OUTPUT_FLAG_INDIRECT = 0x0, OUTPUT_FLAG_DIRECT = 0x1 };
+
+ // device categories used for setForceUse()
+ enum forced_config {
+ FORCE_NONE,
+ FORCE_SPEAKER,
+ FORCE_HEADPHONES,
+ FORCE_BT_SCO,
+ FORCE_BT_A2DP,
+ FORCE_WIRED_ACCESSORY,
+ FORCE_BT_CAR_DOCK,
+ FORCE_BT_DESK_DOCK,
+ FORCE_ANALOG_DOCK,
+ FORCE_DIGITAL_DOCK,
+ FORCE_NO_BT_A2DP,
+ FORCE_SYSTEM_ENFORCED,
+ NUM_FORCE_CONFIG,
+ FORCE_DEFAULT = FORCE_NONE
+ };
+
+ // usages used for setForceUse()
+ enum force_use {
+ FOR_COMMUNICATION,
+ FOR_MEDIA,
+ FOR_RECORD,
+ FOR_DOCK,
+ FOR_SYSTEM,
+ NUM_FORCE_USE
+ };
+
+ //
+ // AudioPolicyService interface
+ //
+
+ // device connection states used for setDeviceConnectionState()
+ enum device_connection_state {
+ DEVICE_STATE_UNAVAILABLE,
+ DEVICE_STATE_AVAILABLE,
+ NUM_DEVICE_STATES
+ };
+
+#endif
+
+ static uint32_t popCount(uint32_t u) { return popcount(u); }
+
+#if 1
+ static bool isOutputDevice(audio_devices device) {
+ if ((popcount(device) == 1) && ((device & ~DEVICE_OUT_ALL) == 0))
+ return true;
+ else
+ return false;
+ }
+ static bool isInputDevice(audio_devices device) {
+ if ((popcount(device) == 1) && ((device & ~DEVICE_IN_ALL) == 0))
+ return true;
+ else
+ return false;
+ }
+ static bool isA2dpDevice(audio_devices device) {
+ return audio_is_a2dp_device((audio_devices_t)device);
+ }
+ static bool isBluetoothScoDevice(audio_devices device) {
+ return audio_is_bluetooth_sco_device((audio_devices_t)device);
+ }
+ static bool isValidFormat(uint32_t format) {
+ return audio_is_valid_format((audio_format_t)format);
+ }
+ static bool isLinearPCM(uint32_t format) { return audio_is_linear_pcm((audio_format_t)format); }
+ static bool isOutputChannel(audio_channel_mask_t channel) {
+ return audio_is_output_channel(channel);
+ }
+ static bool isInputChannel(audio_channel_mask_t channel) {
+ return audio_is_input_channel(channel);
+ }
+
+#endif
+};
+
+}; // namespace android_audio_legacy
+
+#endif // ANDROID_AUDIOSYSTEM_LEGACY_H_
diff --git a/wifi/1.6/default/hal_legacy/IMountService.h b/wifi/1.6/default/hal_legacy/IMountService.h
new file mode 100644
index 0000000..158ff59
--- /dev/null
+++ b/wifi/1.6/default/hal_legacy/IMountService.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+#ifndef ANDROID_HARDWARE_IMOUNTSERVICE_H
+#define ANDROID_HARDWARE_IMOUNTSERVICE_H
+
+#include <binder/IInterface.h>
+#include <utils/String16.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class IMountService : public IInterface {
+ public:
+ static const int OperationSucceeded = 0;
+ static const int OperationFailedInternalError = -1;
+ static const int OperationFailedNoMedia = -2;
+ static const int OperationFailedMediaBlank = -3;
+ static const int OperationFailedMediaCorrupt = -4;
+ static const int OperationFailedVolumeNotMounted = -5;
+
+ public:
+ DECLARE_META_INTERFACE(MountService);
+
+ virtual void getShareMethodList() = 0;
+ virtual bool getShareMethodAvailable(String16 method) = 0;
+ virtual int shareVolume(String16 path, String16 method) = 0;
+ virtual int unshareVolume(String16 path, String16 method) = 0;
+ virtual bool getVolumeShared(String16 path, String16 method) = 0;
+ virtual int mountVolume(String16 path) = 0;
+ virtual int unmountVolume(String16 path) = 0;
+ virtual int formatVolume(String16 path) = 0;
+ virtual String16 getVolumeState(String16 mountPoint) = 0;
+ virtual int createSecureContainer(String16 id, int sizeMb, String16 fstype, String16 key,
+ int ownerUid) = 0;
+ virtual int finalizeSecureContainer(String16 id) = 0;
+ virtual int destroySecureContainer(String16 id) = 0;
+ virtual int mountSecureContainer(String16 id, String16 key, int ownerUid) = 0;
+ virtual int unmountSecureContainer(String16 id) = 0;
+ virtual int renameSecureContainer(String16 oldId, String16 newId) = 0;
+ virtual String16 getSecureContainerPath(String16 id) = 0;
+ virtual void getSecureContainerList() = 0;
+ virtual void shutdown() = 0;
+};
+
+// ----------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_HARDWARE_IMOUNTSERVICE_H
diff --git a/wifi/1.6/default/hal_legacy/audio_policy_conf.h b/wifi/1.6/default/hal_legacy/audio_policy_conf.h
new file mode 100644
index 0000000..13d62f9
--- /dev/null
+++ b/wifi/1.6/default/hal_legacy/audio_policy_conf.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIO_POLICY_CONF_H
+#define ANDROID_AUDIO_POLICY_CONF_H
+
+/////////////////////////////////////////////////
+// Definitions for audio policy configuration file (audio_policy.conf)
+/////////////////////////////////////////////////
+
+#define AUDIO_HARDWARE_MODULE_ID_MAX_LEN 32
+
+#define AUDIO_POLICY_CONFIG_FILE "/system/etc/audio_policy.conf"
+#define AUDIO_POLICY_VENDOR_CONFIG_FILE "/vendor/etc/audio_policy.conf"
+
+// global configuration
+#define GLOBAL_CONFIG_TAG "global_configuration"
+
+#define ATTACHED_OUTPUT_DEVICES_TAG "attached_output_devices"
+#define DEFAULT_OUTPUT_DEVICE_TAG "default_output_device"
+#define ATTACHED_INPUT_DEVICES_TAG "attached_input_devices"
+#define SPEAKER_DRC_ENABLED_TAG "speaker_drc_enabled"
+
+// hw modules descriptions
+#define AUDIO_HW_MODULE_TAG "audio_hw_modules"
+
+#define OUTPUTS_TAG "outputs"
+#define INPUTS_TAG "inputs"
+
+#define SAMPLING_RATES_TAG "sampling_rates"
+#define FORMATS_TAG "formats"
+#define CHANNELS_TAG "channel_masks"
+#define DEVICES_TAG "devices"
+#define FLAGS_TAG "flags"
+
+#define DYNAMIC_VALUE_TAG \
+ "dynamic" // special value for "channel_masks", "sampling_rates" and
+ // "formats" in outputs descriptors indicating that supported
+ // values should be queried after opening the output.
+
+#endif // ANDROID_AUDIO_POLICY_CONF_H
diff --git a/wifi/1.6/default/hal_legacy/gscan.h b/wifi/1.6/default/hal_legacy/gscan.h
new file mode 100644
index 0000000..c6c52c6
--- /dev/null
+++ b/wifi/1.6/default/hal_legacy/gscan.h
@@ -0,0 +1,427 @@
+#include "wifi_hal.h"
+
+#ifndef __WIFI_HAL_GSCAN_H__
+#define __WIFI_HAL_GSCAN_H__
+
+// Define static_assert() unless already defined by compiler.
+#ifndef __has_feature
+#define __has_feature(__x) 0
+#endif
+#if !(__has_feature(cxx_static_assert)) && !defined(static_assert)
+#define static_assert(__b, __m) \
+ extern int compile_time_assert_failed[(__b) ? 1 : -1] __attribute__((unused));
+#endif
+
+/* AP Scans */
+
+typedef enum {
+ WIFI_BAND_UNSPECIFIED,
+ WIFI_BAND_BG = 1, // 2.4 GHz
+ WIFI_BAND_A = 2, // 5 GHz without DFS
+ WIFI_BAND_A_DFS = 4, // 5 GHz DFS only
+ WIFI_BAND_A_WITH_DFS = 6, // 5 GHz with DFS
+ WIFI_BAND_ABG = 3, // 2.4 GHz + 5 GHz; no DFS
+ WIFI_BAND_ABG_WITH_DFS = 7, // 2.4 GHz + 5 GHz with DFS
+} wifi_band;
+
+#define MAX_CHANNELS 16
+#define MAX_BUCKETS 16
+#define MAX_HOTLIST_APS 128
+#define MAX_SIGNIFICANT_CHANGE_APS 64
+#define MAX_EPNO_NETWORKS 64
+#define MAX_HOTLIST_SSID 8
+#define MAX_AP_CACHE_PER_SCAN 32
+
+wifi_error wifi_get_valid_channels(wifi_interface_handle handle, int band, int max_channels,
+ wifi_channel* channels, int* num_channels);
+
+typedef struct {
+ int max_scan_cache_size; // total space allocated for scan (in bytes)
+ int max_scan_buckets; // maximum number of channel buckets
+ int max_ap_cache_per_scan; // maximum number of APs that can be stored per scan
+ int max_rssi_sample_size; // number of RSSI samples used for averaging RSSI
+ int max_scan_reporting_threshold; // max possible report_threshold as described
+ // in wifi_scan_cmd_params
+ int max_hotlist_bssids; // maximum number of entries for hotlist BSSIDs
+ int max_hotlist_ssids; // maximum number of entries for hotlist SSIDs
+ int max_significant_wifi_change_aps; // maximum number of entries for
+ // significant wifi change APs
+ int max_bssid_history_entries; // number of BSSID/RSSI entries that device can hold
+ int max_number_epno_networks; // max number of epno entries
+ int max_number_epno_networks_by_ssid; // max number of epno entries if ssid is specified,
+ // that is, epno entries for which an exact match is
+ // required, or entries corresponding to hidden ssids
+ int max_number_of_white_listed_ssid; // max number of white listed SSIDs, M target is 2 to 4
+} wifi_gscan_capabilities;
+
+wifi_error wifi_get_gscan_capabilities(wifi_interface_handle handle,
+ wifi_gscan_capabilities* capabilities);
+
+typedef enum {
+ WIFI_SCAN_RESULTS_AVAILABLE, // reported when REPORT_EVENTS_EACH_SCAN is set and a scan
+ // completes. WIFI_SCAN_THRESHOLD_NUM_SCANS or
+ // WIFI_SCAN_THRESHOLD_PERCENT can be reported instead if the
+ // reason for the event is available; however, at most one of
+ // these events should be reported per scan. If there are
+ // multiple buckets that were scanned this period and one has the
+ // EACH_SCAN flag set then this event should be prefered.
+ WIFI_SCAN_THRESHOLD_NUM_SCANS, // can be reported when REPORT_EVENTS_EACH_SCAN is not set and
+ // report_threshold_num_scans is reached.
+ WIFI_SCAN_THRESHOLD_PERCENT, // can be reported when REPORT_EVENTS_EACH_SCAN is not set and
+ // report_threshold_percent is reached.
+ WIFI_SCAN_FAILED, // reported when currently executing gscans have failed.
+ // start_gscan will need to be called again in order to continue
+ // scanning. This is intended to indicate abnormal scan
+ // terminations (not those as a result of stop_gscan).
+} wifi_scan_event;
+
+/* Format of information elements found in the beacon */
+typedef struct {
+ byte id; // element identifier
+ byte len; // number of bytes to follow
+ byte data[];
+} wifi_information_element;
+
+typedef struct {
+ wifi_timestamp ts; // time since boot (in microsecond) when the result was
+ // retrieved
+ char ssid[32 + 1]; // null terminated
+ mac_addr bssid;
+ wifi_channel channel; // channel frequency in MHz
+ wifi_rssi rssi; // in db
+ wifi_timespan rtt; // in nanoseconds
+ wifi_timespan rtt_sd; // standard deviation in rtt
+ unsigned short beacon_period; // period advertised in the beacon
+ unsigned short capability; // capabilities advertised in the beacon
+ unsigned int ie_length; // size of the ie_data blob
+ char ie_data[1]; // blob of all the information elements found in the
+ // beacon; this data should be a packed list of
+ // wifi_information_element objects, one after the other.
+ // other fields
+} wifi_scan_result;
+
+static_assert(
+ MAX_BUCKETS <= 8 * sizeof(unsigned),
+ "The buckets_scanned bitset is represented by an unsigned int and cannot support this many "
+ "buckets on this platform.");
+typedef struct {
+ /* reported when each probe response is received, if report_events
+ * enabled in wifi_scan_cmd_params. buckets_scanned is a bitset of the
+ * buckets that are currently being scanned. See the buckets_scanned field
+ * in the wifi_cached_scan_results struct for more details.
+ */
+ void (*on_full_scan_result)(wifi_request_id id, wifi_scan_result* result,
+ unsigned buckets_scanned);
+
+ /* indicates progress of scanning statemachine */
+ void (*on_scan_event)(wifi_request_id id, wifi_scan_event event);
+
+} wifi_scan_result_handler;
+
+typedef struct {
+ wifi_channel channel; // frequency
+ int dwellTimeMs; // dwell time hint
+ int passive; // 0 => active, 1 => passive scan; ignored for DFS
+ /* Add channel class */
+} wifi_scan_channel_spec;
+
+#define REPORT_EVENTS_EACH_SCAN (1 << 0)
+#define REPORT_EVENTS_FULL_RESULTS (1 << 1)
+#define REPORT_EVENTS_NO_BATCH (1 << 2)
+
+typedef struct {
+ int bucket; // bucket index, 0 based
+ wifi_band band; // when UNSPECIFIED, use channel list
+ int period; // desired period, in millisecond; if this is too
+ // low, the firmware should choose to generate results as
+ // fast as it can instead of failing the command.
+ // for exponential backoff bucket this is the min_period
+ /* report_events semantics -
+ * This is a bit field; which defines following bits -
+ * REPORT_EVENTS_EACH_SCAN => report a scan completion event after scan. If this is not set
+ * then scan completion events should be reported if
+ * report_threshold_percent or report_threshold_num_scans is
+ * reached.
+ * REPORT_EVENTS_FULL_RESULTS => forward scan results (beacons/probe responses + IEs)
+ * in real time to HAL, in addition to completion events
+ * Note: To keep backward compatibility, fire completion
+ * events regardless of REPORT_EVENTS_EACH_SCAN.
+ * REPORT_EVENTS_NO_BATCH => controls if scans for this bucket should be placed in the
+ * history buffer
+ */
+ byte report_events;
+ int max_period; // if max_period is non zero or different than period, then this bucket is
+ // an exponential backoff bucket and the scan period will grow exponentially
+ // as per formula: actual_period(N) = period * (base ^ (N/step_count))
+ // to a maximum period of max_period
+ int base; // for exponential back off bucket: multiplier: new_period=old_period*base
+ int step_count; // for exponential back off bucket, number of scans to perform for a given
+ // period
+
+ int num_channels;
+ // channels to scan; these may include DFS channels
+ // Note that a given channel may appear in multiple buckets
+ wifi_scan_channel_spec channels[MAX_CHANNELS];
+} wifi_scan_bucket_spec;
+
+typedef struct {
+ int base_period; // base timer period in ms
+ int max_ap_per_scan; // number of access points to store in each scan entry in
+ // the BSSID/RSSI history buffer (keep the highest RSSI
+ // access points)
+ int report_threshold_percent; // in %, when scan buffer is this much full, wake up apps
+ // processor
+ int report_threshold_num_scans; // in number of scans, wake up AP after these many scans
+ int num_buckets;
+ wifi_scan_bucket_spec buckets[MAX_BUCKETS];
+} wifi_scan_cmd_params;
+
+/*
+ * Start periodic GSCAN
+ * When this is called all requested buckets should be scanned, starting the beginning of the cycle
+ *
+ * For example:
+ * If there are two buckets specified
+ * - Bucket 1: period=10s
+ * - Bucket 2: period=20s
+ * - Bucket 3: period=30s
+ * Then the following scans should occur
+ * - t=0 buckets 1, 2, and 3 are scanned
+ * - t=10 bucket 1 is scanned
+ * - t=20 bucket 1 and 2 are scanned
+ * - t=30 bucket 1 and 3 are scanned
+ * - t=40 bucket 1 and 2 are scanned
+ * - t=50 bucket 1 is scanned
+ * - t=60 buckets 1, 2, and 3 are scanned
+ * - and the patter repeats
+ *
+ * If any scan does not occur or is incomplete (error, interrupted, etc) then a cached scan result
+ * should still be recorded with the WIFI_SCAN_FLAG_INTERRUPTED flag set.
+ */
+wifi_error wifi_start_gscan(wifi_request_id id, wifi_interface_handle iface,
+ wifi_scan_cmd_params params, wifi_scan_result_handler handler);
+
+/* Stop periodic GSCAN */
+wifi_error wifi_stop_gscan(wifi_request_id id, wifi_interface_handle iface);
+
+typedef enum {
+ WIFI_SCAN_FLAG_INTERRUPTED = 1 // Indicates that scan results are not complete because
+ // probes were not sent on some channels
+} wifi_scan_flags;
+
+/* Get the GSCAN cached scan results */
+typedef struct {
+ int scan_id; // a unique identifier for the scan unit
+ int flags; // a bitmask with additional
+ // information about scan.
+ unsigned buckets_scanned; // a bitset of the buckets that were scanned.
+ // for example a value of 13 (0b1101) would
+ // indicate that buckets 0, 2 and 3 were
+ // scanned to produce this list of results.
+ // should be set to 0 if this information is
+ // not available.
+ int num_results; // number of bssids retrieved by the scan
+ wifi_scan_result results[MAX_AP_CACHE_PER_SCAN]; // scan results - one for each bssid
+} wifi_cached_scan_results;
+
+wifi_error wifi_get_cached_gscan_results(wifi_interface_handle iface, byte flush, int max,
+ wifi_cached_scan_results* results, int* num);
+
+/* BSSID Hotlist */
+typedef struct {
+ void (*on_hotlist_ap_found)(wifi_request_id id, unsigned num_results,
+ wifi_scan_result* results);
+ void (*on_hotlist_ap_lost)(wifi_request_id id, unsigned num_results, wifi_scan_result* results);
+} wifi_hotlist_ap_found_handler;
+
+typedef struct {
+ mac_addr bssid; // AP BSSID
+ wifi_rssi low; // low threshold
+ wifi_rssi high; // high threshold
+} ap_threshold_param;
+
+typedef struct {
+ int lost_ap_sample_size;
+ int num_bssid; // number of hotlist APs
+ ap_threshold_param ap[MAX_HOTLIST_APS]; // hotlist APs
+} wifi_bssid_hotlist_params;
+
+/* Set the BSSID Hotlist */
+wifi_error wifi_set_bssid_hotlist(wifi_request_id id, wifi_interface_handle iface,
+ wifi_bssid_hotlist_params params,
+ wifi_hotlist_ap_found_handler handler);
+
+/* Clear the BSSID Hotlist */
+wifi_error wifi_reset_bssid_hotlist(wifi_request_id id, wifi_interface_handle iface);
+
+/* SSID Hotlist */
+typedef struct {
+ void (*on_hotlist_ssid_found)(wifi_request_id id, unsigned num_results,
+ wifi_scan_result* results);
+ void (*on_hotlist_ssid_lost)(wifi_request_id id, unsigned num_results,
+ wifi_scan_result* results);
+} wifi_hotlist_ssid_handler;
+
+typedef struct {
+ char ssid[32 + 1]; // SSID
+ wifi_band band; // band for this set of threshold params
+ wifi_rssi low; // low threshold
+ wifi_rssi high; // high threshold
+} ssid_threshold_param;
+
+typedef struct {
+ int lost_ssid_sample_size;
+ int num_ssid; // number of hotlist SSIDs
+ ssid_threshold_param ssid[MAX_HOTLIST_SSID]; // hotlist SSIDs
+} wifi_ssid_hotlist_params;
+
+/* Significant wifi change */
+typedef struct {
+ mac_addr bssid; // BSSID
+ wifi_channel channel; // channel frequency in MHz
+ int num_rssi; // number of rssi samples
+ wifi_rssi rssi[]; // RSSI history in db
+} wifi_significant_change_result;
+
+typedef struct {
+ void (*on_significant_change)(wifi_request_id id, unsigned num_results,
+ wifi_significant_change_result** results);
+} wifi_significant_change_handler;
+
+// The sample size parameters in the wifi_significant_change_params structure
+// represent the number of occurence of a g-scan where the BSSID was seen and RSSI was
+// collected for that BSSID, or, the BSSID was expected to be seen and didn't.
+// for instance: lost_ap_sample_size : number of time a g-scan was performed on the
+// channel the BSSID was seen last, and the BSSID was not seen during those g-scans
+typedef struct {
+ int rssi_sample_size; // number of samples for averaging RSSI
+ int lost_ap_sample_size; // number of samples to confirm AP loss
+ int min_breaching; // number of APs breaching threshold
+ int num_bssid; // max 64
+ ap_threshold_param ap[MAX_SIGNIFICANT_CHANGE_APS];
+} wifi_significant_change_params;
+
+/* Set the Signifcant AP change list */
+wifi_error wifi_set_significant_change_handler(wifi_request_id id, wifi_interface_handle iface,
+ wifi_significant_change_params params,
+ wifi_significant_change_handler handler);
+
+/* Clear the Signifcant AP change list */
+wifi_error wifi_reset_significant_change_handler(wifi_request_id id, wifi_interface_handle iface);
+
+/* Random MAC OUI for PNO */
+wifi_error wifi_set_scanning_mac_oui(wifi_interface_handle handle, oui scan_oui);
+
+// Enhanced PNO:
+// Enhanced PNO feature is expected to be enabled all of the time (e.g. screen lit) and may thus
+// require firmware to store a large number of networks, covering the whole list of known networks.
+// Therefore, it is acceptable for firmware to store a crc24, crc32 or other short hash of the SSID,
+// such that a low but non-zero probability of collision exist. With that scheme it should be
+// possible for firmware to keep an entry as small as 4 bytes for each pno network.
+// For instance, a firmware pn0 entry can be implemented in the form of:
+// PNO ENTRY = crc24(3 bytes) | flags>>3 (5 bits) | auth flags(3 bits)
+//
+// No scans should be automatically performed by the chip. Instead all scan results from gscan
+// should be scored and the wifi_epno_handler on_network_found callback should be called with
+// the scan results.
+//
+// A PNO network shall be reported once, that is, once a network is reported by firmware
+// its entry shall be marked as "done" until framework calls wifi_set_epno_list again.
+// Calling wifi_set_epno_list shall reset the "done" status of pno networks in firmware.
+//
+// A network should only be considered found if its RSSI is above the minimum RSSI for its
+// frequency range (min5GHz_rssi and min24GHz_rssi for 5GHz and 2.4GHz networks respectively).
+// When disconnected the list of scan results should be returned if any network is found.
+// When connected the scan results shall be reported only if the score of any network in the scan
+// is greater than that of the currently connected BSSID.
+//
+// The FW should calculate the score of all the candidates (including currently connected one)
+// with following equation:
+// RSSI score = (RSSI + 85) * 4;
+// If RSSI score > initial_score_max , RSSI score = initial_score_max;
+// final score = RSSI score
+// + current_connection_bonus (if currently connected BSSID)
+// + same_network_bonus (if network has SAME_NETWORK flag)
+// + secure_bonus (if the network is not open)
+// + band5GHz_bonus (if BSSID is on 5G)
+// If there is a BSSID’s score > current BSSID’s score, then report the cached scan results
+// at the end of the scan (excluding the ones on blacklist) to the upper layer.
+// Additionally, all BSSIDs that are in the BSSID blacklist should be ignored by Enhanced PNO
+
+// Whether directed scan needs to be performed (for hidden SSIDs)
+#define WIFI_PNO_FLAG_DIRECTED_SCAN (1 << 0)
+// Whether PNO event shall be triggered if the network is found on A band
+#define WIFI_PNO_FLAG_A_BAND (1 << 1)
+// Whether PNO event shall be triggered if the network is found on G band
+#define WIFI_PNO_FLAG_G_BAND (1 << 2)
+// Whether strict matching is required
+// If required then the firmware must store the network's SSID and not just a hash
+#define WIFI_PNO_FLAG_STRICT_MATCH (1 << 3)
+// If this SSID should be considered the same network as the currently connected one for scoring
+#define WIFI_PNO_FLAG_SAME_NETWORK (1 << 4)
+
+// Code for matching the beacon AUTH IE - additional codes TBD
+#define WIFI_PNO_AUTH_CODE_OPEN (1 << 0) // open
+#define WIFI_PNO_AUTH_CODE_PSK (1 << 1) // WPA_PSK or WPA2PSK
+#define WIFI_PNO_AUTH_CODE_EAPOL (1 << 2) // any EAPOL
+
+typedef struct {
+ char ssid[32 + 1]; // null terminated
+ byte flags; // WIFI_PNO_FLAG_XXX
+ byte auth_bit_field; // auth bit field for matching WPA IE
+} wifi_epno_network;
+
+/* ePNO Parameters */
+typedef struct {
+ int min5GHz_rssi; // minimum 5GHz RSSI for a BSSID to be considered
+ int min24GHz_rssi; // minimum 2.4GHz RSSI for a BSSID to be considered
+ int initial_score_max; // the maximum score that a network can have before bonuses
+ int current_connection_bonus; // only report when there is a network's score this much higher
+ // than the current connection.
+ int same_network_bonus; // score bonus for all networks with the same network flag
+ int secure_bonus; // score bonus for networks that are not open
+ int band5GHz_bonus; // 5GHz RSSI score bonus (applied to all 5GHz networks)
+ int num_networks; // number of wifi_epno_network objects
+ wifi_epno_network networks[MAX_EPNO_NETWORKS]; // PNO networks
+} wifi_epno_params;
+
+typedef struct {
+ // on results
+ void (*on_network_found)(wifi_request_id id, unsigned num_results, wifi_scan_result* results);
+} wifi_epno_handler;
+
+/* Set the ePNO list - enable ePNO with the given parameters */
+wifi_error wifi_set_epno_list(wifi_request_id id, wifi_interface_handle iface,
+ const wifi_epno_params* epno_params, wifi_epno_handler handler);
+
+/* Reset the ePNO list - no ePNO networks should be matched after this */
+wifi_error wifi_reset_epno_list(wifi_request_id id, wifi_interface_handle iface);
+
+typedef struct {
+ int id; // identifier of this network block, report this in event
+ char realm[256]; // null terminated UTF8 encoded realm, 0 if unspecified
+ int64_t roamingConsortiumIds[16]; // roaming consortium ids to match, 0s if unspecified
+ byte plmn[3]; // mcc/mnc combination as per rules, 0s if unspecified
+} wifi_passpoint_network;
+
+typedef struct {
+ void (*on_passpoint_network_found)(
+ wifi_request_id id,
+ int net_id, // network block identifier for the matched network
+ wifi_scan_result* result, // scan result, with channel and beacon information
+ int anqp_len, // length of ANQP blob
+ byte* anqp // ANQP data, in the information_element format
+ );
+} wifi_passpoint_event_handler;
+
+/* Sets a list for passpoint networks for PNO purposes; it should be matched
+ * against any passpoint networks (designated by Interworking element) found
+ * during regular PNO scan. */
+wifi_error wifi_set_passpoint_list(wifi_request_id id, wifi_interface_handle iface, int num,
+ wifi_passpoint_network* networks,
+ wifi_passpoint_event_handler handler);
+
+/* Reset passpoint network list - no Passpoint networks should be matched after this */
+wifi_error wifi_reset_passpoint_list(wifi_request_id id, wifi_interface_handle iface);
+
+#endif
diff --git a/wifi/1.6/default/hal_legacy/link_layer_stats.h b/wifi/1.6/default/hal_legacy/link_layer_stats.h
new file mode 100644
index 0000000..7585cdf
--- /dev/null
+++ b/wifi/1.6/default/hal_legacy/link_layer_stats.h
@@ -0,0 +1,285 @@
+#include "wifi_hal.h"
+
+#ifndef __WIFI_HAL_STATS_H
+#define __WIFI_HAL_STATS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define STATS_MAJOR_VERSION 1
+#define STATS_MINOR_VERSION 0
+#define STATS_MICRO_VERSION 0
+
+typedef enum {
+ WIFI_DISCONNECTED = 0,
+ WIFI_AUTHENTICATING = 1,
+ WIFI_ASSOCIATING = 2,
+ WIFI_ASSOCIATED = 3,
+ WIFI_EAPOL_STARTED = 4, // if done by firmware/driver
+ WIFI_EAPOL_COMPLETED = 5, // if done by firmware/driver
+} wifi_connection_state;
+
+typedef enum {
+ WIFI_ROAMING_IDLE = 0,
+ WIFI_ROAMING_ACTIVE = 1,
+} wifi_roam_state;
+
+typedef enum {
+ WIFI_INTERFACE_STA = 0,
+ WIFI_INTERFACE_SOFTAP = 1,
+ WIFI_INTERFACE_IBSS = 2,
+ WIFI_INTERFACE_P2P_CLIENT = 3,
+ WIFI_INTERFACE_P2P_GO = 4,
+ WIFI_INTERFACE_NAN = 5,
+ WIFI_INTERFACE_MESH = 6,
+ WIFI_INTERFACE_TDLS = 7,
+ WIFI_INTERFACE_UNKNOWN = -1
+} wifi_interface_mode;
+
+#define WIFI_CAPABILITY_QOS 0x00000001 // set for QOS association
+#define WIFI_CAPABILITY_PROTECTED \
+ 0x00000002 // set for protected association (802.11 beacon frame control protected bit set)
+#define WIFI_CAPABILITY_INTERWORKING \
+ 0x00000004 // set if 802.11 Extended Capabilities element interworking bit is set
+#define WIFI_CAPABILITY_HS20 0x00000008 // set for HS20 association
+#define WIFI_CAPABILITY_SSID_UTF8 \
+ 0x00000010 // set is 802.11 Extended Capabilities element UTF-8 SSID bit is set
+#define WIFI_CAPABILITY_COUNTRY 0x00000020 // set is 802.11 Country Element is present
+
+typedef struct {
+ wifi_interface_mode mode; // interface mode
+ u8 mac_addr[6]; // interface mac address (self)
+ wifi_connection_state state; // connection state (valid for STA, CLI only)
+ wifi_roam_state roaming; // roaming state
+ u32 capabilities; // WIFI_CAPABILITY_XXX (self)
+ u8 ssid[33]; // null terminated SSID
+ u8 bssid[6]; // bssid
+ u8 ap_country_str[3]; // country string advertised by AP
+ u8 country_str[3]; // country string for this association
+ u8 time_slicing_duty_cycle_percent; // if this iface is being served using time slicing on a
+ // radio with one or more ifaces (i.e MCC), then the duty
+ // cycle assigned to this iface in %. If not using time
+ // slicing (i.e SCC or DBS), set to 100.
+} wifi_interface_link_layer_info;
+
+/* channel information */
+typedef struct {
+ wifi_channel_width width; // channel width (20, 40, 80, 80+80, 160, 320)
+ wifi_channel center_freq; // primary 20 MHz channel
+ wifi_channel center_freq0; // center frequency (MHz) first segment
+ wifi_channel center_freq1; // center frequency (MHz) second segment
+} wifi_channel_info;
+
+/* wifi rate */
+typedef struct {
+ u32 preamble : 3; // 0: OFDM, 1:CCK, 2:HT 3:VHT 4:HE 5:EHT 6..7 reserved
+ u32 nss : 2; // 0:1x1, 1:2x2, 3:3x3, 4:4x4
+ u32 bw : 3; // 0:20MHz, 1:40Mhz, 2:80Mhz, 3:160Mhz 4:320Mhz
+ u32 rateMcsIdx : 8; // OFDM/CCK rate code would be as per ieee std in the units of 0.5mbps
+ // HT/VHT/HE/EHT it would be mcs index
+ u32 reserved : 16; // reserved
+ u32 bitrate; // units of 100 Kbps
+} wifi_rate;
+
+/* channel statistics */
+typedef struct {
+ wifi_channel_info channel; // channel
+ u32 on_time; // msecs the radio is awake (32 bits number accruing over time)
+ u32 cca_busy_time; // msecs the CCA register is busy (32 bits number accruing over time)
+} wifi_channel_stat;
+
+// Max number of tx power levels. The actual number vary per device and is specified by
+// |num_tx_levels|
+#define RADIO_STAT_MAX_TX_LEVELS 256
+
+/* radio statistics */
+typedef struct {
+ wifi_radio radio; // wifi radio (if multiple radio supported)
+ u32 on_time; // msecs the radio is awake (32 bits number accruing over time)
+ u32 tx_time; // msecs the radio is transmitting (32 bits number accruing over time)
+ u32 num_tx_levels; // number of radio transmit power levels
+ u32* tx_time_per_levels; // pointer to an array of radio transmit per power levels in
+ // msecs accured over time
+ u32 rx_time; // msecs the radio is in active receive (32 bits number accruing over time)
+ u32 on_time_scan; // msecs the radio is awake due to all scan (32 bits number accruing over
+ // time)
+ u32 on_time_nbd; // msecs the radio is awake due to NAN (32 bits number accruing over time)
+ u32 on_time_gscan; // msecs the radio is awake due to G?scan (32 bits number accruing over
+ // time)
+ u32 on_time_roam_scan; // msecs the radio is awake due to roam?scan (32 bits number accruing
+ // over time)
+ u32 on_time_pno_scan; // msecs the radio is awake due to PNO scan (32 bits number accruing over
+ // time)
+ u32 on_time_hs20; // msecs the radio is awake due to HS2.0 scans and GAS exchange (32 bits
+ // number accruing over time)
+ u32 num_channels; // number of channels
+ wifi_channel_stat channels[]; // channel statistics
+} wifi_radio_stat;
+
+/**
+ * Packet statistics reporting by firmware is performed on MPDU basi (i.e. counters increase by 1
+ * for each MPDU) As well, "data packet" in associated comments, shall be interpreted as 802.11 data
+ * packet, that is, 802.11 frame control subtype == 2 and excluding management and control frames.
+ *
+ * As an example, in the case of transmission of an MSDU fragmented in 16 MPDUs which are
+ * transmitted OTA in a 16 units long a-mpdu, for which a block ack is received with 5 bits set:
+ * tx_mpdu : shall increase by 5
+ * retries : shall increase by 16
+ * tx_ampdu : shall increase by 1
+ * data packet counters shall not increase regardless of the number of BAR potentially sent by
+ * device for this a-mpdu data packet counters shall not increase regardless of the number of BA
+ * received by device for this a-mpdu
+ *
+ * For each subsequent retransmission of the 11 remaining non ACK'ed mpdus
+ * (regardless of the fact that they are transmitted in a-mpdu or not)
+ * retries : shall increase by 1
+ *
+ * If no subsequent BA or ACK are received from AP, until packet lifetime expires for those 11
+ * packet that were not ACK'ed mpdu_lost : shall increase by 11
+ */
+
+/* per rate statistics */
+typedef struct {
+ wifi_rate rate; // rate information
+ u32 tx_mpdu; // number of successfully transmitted data pkts (ACK rcvd)
+ u32 rx_mpdu; // number of received data pkts
+ u32 mpdu_lost; // number of data packet losses (no ACK)
+ u32 retries; // total number of data pkt retries
+ u32 retries_short; // number of short data pkt retries
+ u32 retries_long; // number of long data pkt retries
+} wifi_rate_stat;
+
+/* access categories */
+typedef enum {
+ WIFI_AC_VO = 0,
+ WIFI_AC_VI = 1,
+ WIFI_AC_BE = 2,
+ WIFI_AC_BK = 3,
+ WIFI_AC_MAX = 4,
+} wifi_traffic_ac;
+
+/* wifi peer type */
+typedef enum {
+ WIFI_PEER_STA,
+ WIFI_PEER_AP,
+ WIFI_PEER_P2P_GO,
+ WIFI_PEER_P2P_CLIENT,
+ WIFI_PEER_NAN,
+ WIFI_PEER_TDLS,
+ WIFI_PEER_INVALID,
+} wifi_peer_type;
+
+/* per peer statistics */
+typedef struct bssload_info {
+ u16 sta_count; // station count
+ u16 chan_util; // channel utilization
+ u8 PAD[4];
+} bssload_info_t;
+
+typedef struct {
+ wifi_peer_type type; // peer type (AP, TDLS, GO etc.)
+ u8 peer_mac_address[6]; // mac address
+ u32 capabilities; // peer WIFI_CAPABILITY_XXX
+ bssload_info_t bssload; // STA count and CU
+ u32 num_rate; // number of rates
+ wifi_rate_stat rate_stats[]; // per rate statistics, number of entries = num_rate
+} wifi_peer_info;
+
+/* Per access category statistics */
+typedef struct {
+ wifi_traffic_ac ac; // access category (VI, VO, BE, BK)
+ u32 tx_mpdu; // number of successfully transmitted unicast data pkts (ACK rcvd)
+ u32 rx_mpdu; // number of received unicast data packets
+ u32 tx_mcast; // number of succesfully transmitted multicast data packets
+ // STA case: implies ACK received from AP for the unicast packet in which mcast
+ // pkt was sent
+ u32 rx_mcast; // number of received multicast data packets
+ u32 rx_ampdu; // number of received unicast a-mpdus; support of this counter is optional
+ u32 tx_ampdu; // number of transmitted unicast a-mpdus; support of this counter is optional
+ u32 mpdu_lost; // number of data pkt losses (no ACK)
+ u32 retries; // total number of data pkt retries
+ u32 retries_short; // number of short data pkt retries
+ u32 retries_long; // number of long data pkt retries
+ u32 contention_time_min; // data pkt min contention time (usecs)
+ u32 contention_time_max; // data pkt max contention time (usecs)
+ u32 contention_time_avg; // data pkt avg contention time (usecs)
+ u32 contention_num_samples; // num of data pkts used for contention statistics
+} wifi_wmm_ac_stat;
+
+/* interface statistics */
+typedef struct {
+ wifi_interface_handle iface; // wifi interface
+ wifi_interface_link_layer_info info; // current state of the interface
+ u32 beacon_rx; // access point beacon received count from connected AP
+ u64 average_tsf_offset; // average beacon offset encountered (beacon_TSF - TBTT)
+ // The average_tsf_offset field is used so as to calculate the
+ // typical beacon contention time on the channel as well may be
+ // used to debug beacon synchronization and related power consumption
+ // issue
+ u32 leaky_ap_detected; // indicate that this AP typically leaks packets beyond the driver guard
+ // time.
+ u32 leaky_ap_avg_num_frames_leaked; // average number of frame leaked by AP after frame with PM
+ // bit set was ACK'ed by AP
+ u32 leaky_ap_guard_time; // guard time currently in force (when implementing IEEE power
+ // management based on frame control PM bit), How long driver waits
+ // before shutting down the radio and after receiving an ACK for a
+ // data frame with PM bit set)
+ u32 mgmt_rx; // access point mgmt frames received count from connected AP (including Beacon)
+ u32 mgmt_action_rx; // action frames received count
+ u32 mgmt_action_tx; // action frames transmit count
+ wifi_rssi rssi_mgmt; // access Point Beacon and Management frames RSSI (averaged)
+ wifi_rssi rssi_data; // access Point Data Frames RSSI (averaged) from connected AP
+ wifi_rssi rssi_ack; // access Point ACK RSSI (averaged) from connected AP
+ wifi_wmm_ac_stat ac[WIFI_AC_MAX]; // per ac data packet statistics
+ u32 num_peers; // number of peers
+ wifi_peer_info peer_info[]; // per peer statistics
+} wifi_iface_stat;
+
+/* configuration params */
+typedef struct {
+ u32 mpdu_size_threshold; // threshold to classify the pkts as short or long
+ // packet size < mpdu_size_threshold => short
+ u32 aggressive_statistics_gathering; // set for field debug mode. Driver should collect all
+ // statistics regardless of performance impact.
+} wifi_link_layer_params;
+
+/* API to trigger the link layer statistics collection.
+ Unless his API is invoked - link layer statistics will not be collected.
+ Radio statistics (once started) do not stop or get reset unless wifi_clear_link_stats is invoked
+ Interface statistics (once started) reset and start afresh after each connection */
+wifi_error wifi_set_link_stats(wifi_interface_handle iface, wifi_link_layer_params params);
+
+/* callback for reporting link layer stats */
+typedef struct {
+ void (*on_link_stats_results)(wifi_request_id id, wifi_iface_stat* iface_stat, int num_radios,
+ wifi_radio_stat* radio_stat);
+} wifi_stats_result_handler;
+
+/* api to collect the link layer statistics for a given iface and all the radio stats */
+wifi_error wifi_get_link_stats(wifi_request_id id, wifi_interface_handle iface,
+ wifi_stats_result_handler handler);
+
+/* wifi statistics bitmap */
+#define WIFI_STATS_RADIO 0x00000001 // all radio statistics
+#define WIFI_STATS_RADIO_CCA 0x00000002 // cca_busy_time (within radio statistics)
+#define WIFI_STATS_RADIO_CHANNELS 0x00000004 // all channel statistics (within radio statistics)
+#define WIFI_STATS_RADIO_SCAN 0x00000008 // all scan statistics (within radio statistics)
+#define WIFI_STATS_IFACE 0x00000010 // all interface statistics
+#define WIFI_STATS_IFACE_TXRATE 0x00000020 // all tx rate statistics (within interface statistics)
+#define WIFI_STATS_IFACE_AC 0x00000040 // all ac statistics (within interface statistics)
+#define WIFI_STATS_IFACE_CONTENTION \
+ 0x00000080 // all contention (min, max, avg) statistics (within ac statisctics)
+
+/* clear api to reset statistics, stats_clear_rsp_mask identifies what stats have been cleared
+ stop_req = 1 will imply whether to stop the statistics collection.
+ stop_rsp = 1 will imply that stop_req was honored and statistics collection was stopped.
+ */
+wifi_error wifi_clear_link_stats(wifi_interface_handle iface, u32 stats_clear_req_mask,
+ u32* stats_clear_rsp_mask, u8 stop_req, u8* stop_rsp);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /*__WIFI_HAL_STATS_ */
diff --git a/wifi/1.6/default/hal_legacy/power.h b/wifi/1.6/default/hal_legacy/power.h
new file mode 100644
index 0000000..2b6d12a
--- /dev/null
+++ b/wifi/1.6/default/hal_legacy/power.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _HARDWARE_POWER_H
+#define _HARDWARE_POWER_H
+
+#include <stdint.h>
+
+#if __cplusplus
+extern "C" {
+#endif
+
+enum {
+ PARTIAL_WAKE_LOCK = 1, // the cpu stays on, but the screen is off
+ FULL_WAKE_LOCK = 2 // the screen is also on
+};
+
+// while you have a lock held, the device will stay on at least at the
+// level you request.
+int acquire_wake_lock(int lock, const char* id);
+int release_wake_lock(const char* id);
+
+#if __cplusplus
+} // extern "C"
+#endif
+
+#endif // _HARDWARE_POWER_H
diff --git a/wifi/1.6/default/hal_legacy/roam.h b/wifi/1.6/default/hal_legacy/roam.h
new file mode 100644
index 0000000..3369e3e
--- /dev/null
+++ b/wifi/1.6/default/hal_legacy/roam.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __WIFI_HAL_ROAM_H__
+#define __WIFI_HAL_ROAM_H__
+
+#include "wifi_hal.h"
+
+#define MAX_BLACKLIST_BSSID 16
+#define MAX_WHITELIST_SSID 8
+#define MAX_SSID_LENGTH 32
+
+typedef struct {
+ u32 max_blacklist_size;
+ u32 max_whitelist_size;
+} wifi_roaming_capabilities;
+
+typedef enum { ROAMING_DISABLE, ROAMING_ENABLE } fw_roaming_state_t;
+
+typedef struct {
+ u32 length;
+ char ssid_str[MAX_SSID_LENGTH];
+} ssid_t;
+
+typedef struct {
+ u32 num_blacklist_bssid; // Number of bssids valid in blacklist_bssid[].
+ mac_addr blacklist_bssid[MAX_BLACKLIST_BSSID]; // List of bssids which should not be considered
+ // for romaing by firmware/driver.
+ u32 num_whitelist_ssid; // Number of ssids valid in whitelist_ssid[].
+ ssid_t whitelist_ssid[MAX_WHITELIST_SSID]; // List of ssids to which firmware/driver can
+ // consider to roam to.
+} wifi_roaming_config;
+
+/* Get the chipset roaming capabilities. */
+wifi_error wifi_get_roaming_capabilities(wifi_interface_handle handle,
+ wifi_roaming_capabilities* caps);
+/* Enable/disable firmware roaming */
+wifi_error wifi_enable_firmware_roaming(wifi_interface_handle handle, fw_roaming_state_t state);
+
+/* Pass down the blacklist BSSID and whitelist SSID to firmware. */
+wifi_error wifi_configure_roaming(wifi_interface_handle handle,
+ wifi_roaming_config* roaming_config);
+
+#endif /* __WIFI_HAL_ROAM_H__ */
diff --git a/wifi/1.6/default/hal_legacy/rtt.h b/wifi/1.6/default/hal_legacy/rtt.h
new file mode 100644
index 0000000..8be7fd3
--- /dev/null
+++ b/wifi/1.6/default/hal_legacy/rtt.h
@@ -0,0 +1,314 @@
+
+#include "gscan.h"
+#include "wifi_hal.h"
+
+#ifndef __WIFI_HAL_RTT_H__
+#define __WIFI_HAL_RTT_H__
+
+/* Ranging status */
+typedef enum {
+ RTT_STATUS_SUCCESS = 0,
+ RTT_STATUS_FAILURE = 1, // general failure status
+ RTT_STATUS_FAIL_NO_RSP = 2, // target STA does not respond to request
+ RTT_STATUS_FAIL_REJECTED = 3, // request rejected. Applies to 2-sided RTT only
+ RTT_STATUS_FAIL_NOT_SCHEDULED_YET = 4,
+ RTT_STATUS_FAIL_TM_TIMEOUT = 5, // timing measurement times out
+ RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL = 6, // Target on different channel, cannot range
+ RTT_STATUS_FAIL_NO_CAPABILITY = 7, // ranging not supported
+ RTT_STATUS_ABORTED = 8, // request aborted for unknown reason
+ RTT_STATUS_FAIL_INVALID_TS = 9, // Invalid T1-T4 timestamp
+ RTT_STATUS_FAIL_PROTOCOL = 10, // 11mc protocol failed
+ RTT_STATUS_FAIL_SCHEDULE = 11, // request could not be scheduled
+ RTT_STATUS_FAIL_BUSY_TRY_LATER = 12, // responder cannot collaborate at time of request
+ RTT_STATUS_INVALID_REQ = 13, // bad request args
+ RTT_STATUS_NO_WIFI = 14, // WiFi not enabled
+ RTT_STATUS_FAIL_FTM_PARAM_OVERRIDE =
+ 15, // Responder overrides param info, cannot range with new params
+ RTT_STATUS_NAN_RANGING_PROTOCOL_FAILURE = 16, // Negotiation failure
+ RTT_STATUS_NAN_RANGING_CONCURRENCY_NOT_SUPPORTED = 17, // concurrency not supported (NDP+RTT)
+} wifi_rtt_status;
+
+/* RTT peer type */
+typedef enum {
+ RTT_PEER_AP = 0x1,
+ RTT_PEER_STA = 0x2,
+ RTT_PEER_P2P_GO = 0x3,
+ RTT_PEER_P2P_CLIENT = 0x4,
+ RTT_PEER_NAN = 0x5
+} rtt_peer_type;
+
+/* RTT Measurement Bandwidth */
+typedef enum {
+ WIFI_RTT_BW_5 = 0x01,
+ WIFI_RTT_BW_10 = 0x02,
+ WIFI_RTT_BW_20 = 0x04,
+ WIFI_RTT_BW_40 = 0x08,
+ WIFI_RTT_BW_80 = 0x10,
+ WIFI_RTT_BW_160 = 0x20,
+ WIFI_RTT_BW_320 = 0x40
+} wifi_rtt_bw;
+
+/* RTT Measurement Preamble */
+typedef enum {
+ WIFI_RTT_PREAMBLE_LEGACY = 0x1,
+ WIFI_RTT_PREAMBLE_HT = 0x2,
+ WIFI_RTT_PREAMBLE_VHT = 0x4,
+ WIFI_RTT_PREAMBLE_HE = 0x8,
+ WIFI_RTT_PREAMBLE_EHT = 0x10,
+} wifi_rtt_preamble;
+
+/* RTT Type */
+typedef enum {
+ RTT_TYPE_1_SIDED = 0x1,
+ RTT_TYPE_2_SIDED = 0x2,
+} wifi_rtt_type;
+
+/* RTT configuration */
+typedef struct {
+ mac_addr addr; // peer device mac address
+ wifi_rtt_type type; // 1-sided or 2-sided RTT
+ rtt_peer_type peer; // optional - peer device hint (STA, P2P, AP)
+ wifi_channel_info channel; // Required for STA-AP mode, optional for P2P, NBD etc.
+ unsigned burst_period; // Time interval between bursts (units: 100 ms).
+ // Applies to 1-sided and 2-sided RTT multi-burst requests.
+ // Range: 0-31, 0: no preference by initiator (2-sided RTT)
+ unsigned num_burst; // Total number of RTT bursts to be executed. It will be
+ // specified in the same way as the parameter "Number of
+ // Burst Exponent" found in the FTM frame format. It
+ // applies to both: 1-sided RTT and 2-sided RTT. Valid
+ // values are 0 to 15 as defined in 802.11mc std.
+ // 0 means single shot
+ // The implication of this parameter on the maximum
+ // number of RTT results is the following:
+ // for 1-sided RTT: max num of RTT results =
+ // (2^num_burst)*(num_frames_per_burst) for 2-sided RTT: max num of RTT
+ // results = (2^num_burst)*(num_frames_per_burst - 1)
+ unsigned num_frames_per_burst; // num of frames per burst.
+ // Minimum value = 1, Maximum value = 31
+ // For 2-sided this equals the number of FTM frames
+ // to be attempted in a single burst. This also
+ // equals the number of FTM frames that the
+ // initiator will request that the responder send
+ // in a single frame.
+ unsigned
+ num_retries_per_rtt_frame; // number of retries for a failed RTT frame. Applies
+ // to 1-sided RTT only. Minimum value = 0, Maximum value = 3
+
+ // following fields are only valid for 2-side RTT
+ unsigned num_retries_per_ftmr; // Maximum number of retries that the initiator can
+ // retry an FTMR frame.
+ // Minimum value = 0, Maximum value = 3
+ byte LCI_request; // 1: request LCI, 0: do not request LCI
+ byte LCR_request; // 1: request LCR, 0: do not request LCR
+ unsigned burst_duration; // Applies to 1-sided and 2-sided RTT. Valid values will
+ // be 2-11 and 15 as specified by the 802.11mc std for
+ // the FTM parameter burst duration. In a multi-burst
+ // request, if responder overrides with larger value,
+ // the initiator will return failure. In a single-burst
+ // request if responder overrides with larger value,
+ // the initiator will sent TMR_STOP to terminate RTT
+ // at the end of the burst_duration it requested.
+ wifi_rtt_preamble preamble; // RTT preamble to be used in the RTT frames
+ wifi_rtt_bw bw; // RTT BW to be used in the RTT frames
+} wifi_rtt_config;
+
+/* RTT results */
+typedef struct {
+ mac_addr addr; // device mac address
+ unsigned burst_num; // burst number in a multi-burst request
+ unsigned measurement_number; // Total RTT measurement frames attempted
+ unsigned success_number; // Total successful RTT measurement frames
+ byte number_per_burst_peer; // Maximum number of "FTM frames per burst" supported by
+ // the responder STA. Applies to 2-sided RTT only.
+ // If reponder overrides with larger value:
+ // - for single-burst request initiator will truncate the
+ // larger value and send a TMR_STOP after receiving as
+ // many frames as originally requested.
+ // - for multi-burst request, initiator will return
+ // failure right away.
+ wifi_rtt_status status; // ranging status
+ byte retry_after_duration; // When status == RTT_STATUS_FAIL_BUSY_TRY_LATER,
+ // this will be the time provided by the responder as to
+ // when the request can be tried again. Applies to 2-sided
+ // RTT only. In sec, 1-31sec.
+ wifi_rtt_type type; // RTT type
+ wifi_rssi rssi; // average rssi in 0.5 dB steps e.g. 143 implies -71.5 dB
+ wifi_rssi rssi_spread; // rssi spread in 0.5 dB steps e.g. 5 implies 2.5 dB spread (optional)
+ wifi_rate tx_rate; // 1-sided RTT: TX rate of RTT frame.
+ // 2-sided RTT: TX rate of initiator's Ack in response to FTM frame.
+ wifi_rate rx_rate; // 1-sided RTT: TX rate of Ack from other side.
+ // 2-sided RTT: TX rate of FTM frame coming from responder.
+ wifi_timespan rtt; // round trip time in picoseconds
+ wifi_timespan rtt_sd; // rtt standard deviation in picoseconds
+ wifi_timespan rtt_spread; // difference between max and min rtt times recorded in picoseconds
+ int distance_mm; // distance in mm (optional)
+ int distance_sd_mm; // standard deviation in mm (optional)
+ int distance_spread_mm; // difference between max and min distance recorded in mm (optional)
+ wifi_timestamp ts; // time of the measurement (in microseconds since boot)
+ int burst_duration; // in ms, actual time taken by the FW to finish one burst
+ // measurement. Applies to 1-sided and 2-sided RTT.
+ int negotiated_burst_num; // Number of bursts allowed by the responder. Applies
+ // to 2-sided RTT only.
+ wifi_information_element* LCI; // for 11mc only
+ wifi_information_element* LCR; // for 11mc only
+} wifi_rtt_result;
+
+/* RTT result callback */
+typedef struct {
+ void (*on_rtt_results)(wifi_request_id id, unsigned num_results, wifi_rtt_result* rtt_result[]);
+} wifi_rtt_event_handler;
+
+/* API to request RTT measurement */
+wifi_error wifi_rtt_range_request(wifi_request_id id, wifi_interface_handle iface,
+ unsigned num_rtt_config, wifi_rtt_config rtt_config[],
+ wifi_rtt_event_handler handler);
+
+/* API to cancel RTT measurements */
+wifi_error wifi_rtt_range_cancel(wifi_request_id id, wifi_interface_handle iface,
+ unsigned num_devices, mac_addr addr[]);
+
+/* NBD ranging channel map */
+typedef struct {
+ wifi_channel availablity[32]; // specifies the channel map for each of the 16 TU windows
+ // frequency of 0 => unspecified; which means firmware is
+ // free to do whatever it wants in this window.
+} wifi_channel_map;
+
+/* API to start publishing the channel map on responder device in a NBD cluster.
+ Responder device will take this request and schedule broadcasting the channel map
+ in a NBD ranging attribute in a SDF. DE will automatically remove the ranging
+ attribute from the OTA queue after number of DW specified by num_dw
+ where Each DW is 512 TUs apart */
+wifi_error wifi_rtt_channel_map_set(wifi_request_id id, wifi_interface_handle iface,
+ wifi_channel_map* params, unsigned num_dw);
+
+/* API to clear the channel map on the responder device in a NBD cluster.
+ Responder device will cancel future ranging channel request, starting from “next”
+ DW interval and will also stop broadcasting NBD ranging attribute in SDF */
+wifi_error wifi_rtt_channel_map_clear(wifi_request_id id, wifi_interface_handle iface);
+
+// Preamble definition for bit mask used in wifi_rtt_capabilities
+#define PREAMBLE_LEGACY 0x1
+#define PREAMBLE_HT 0x2
+#define PREAMBLE_VHT 0x4
+#define PREAMBLE_HE 0x8
+#define PREAMBLE_EHT 0x10
+
+// BW definition for bit mask used in wifi_rtt_capabilities
+#define BW_5_SUPPORT 0x1
+#define BW_10_SUPPORT 0x2
+#define BW_20_SUPPORT 0x4
+#define BW_40_SUPPORT 0x8
+#define BW_80_SUPPORT 0x10
+#define BW_160_SUPPORT 0x20
+#define BW_320_SUPPORT 0x40
+
+/* RTT Capabilities */
+typedef struct {
+ byte rtt_one_sided_supported; // if 1-sided rtt data collection is supported
+ byte rtt_ftm_supported; // if ftm rtt data collection is supported
+ byte lci_support; // if initiator supports LCI request. Applies to 2-sided RTT
+ byte lcr_support; // if initiator supports LCR request. Applies to 2-sided RTT
+ byte preamble_support; // bit mask indicates what preamble is supported by initiator
+ byte bw_support; // bit mask indicates what BW is supported by initiator
+ byte responder_supported; // if 11mc responder mode is supported
+ byte mc_version; // draft 11mc spec version supported by chip. For instance,
+ // version 4.0 should be 40 and version 4.3 should be 43 etc.
+} wifi_rtt_capabilities;
+
+/* RTT capabilities of the device */
+wifi_error wifi_get_rtt_capabilities(wifi_interface_handle iface,
+ wifi_rtt_capabilities* capabilities);
+
+/* debugging definitions */
+enum {
+ RTT_DEBUG_DISABLE,
+ RTT_DEBUG_LOG,
+ RTT_DEBUG_PROTO,
+ RTT_DEBUG_BURST,
+ RTT_DEBUG_ACCURACY,
+ RTT_DEBUG_LOGDETAIL
+}; // rtt debug type
+
+enum { RTT_DEBUG_FORMAT_TXT, RTT_DEBUG_FORMAT_BINARY }; // rtt debug format
+
+typedef struct rtt_debug {
+ unsigned version;
+ unsigned len; // total length of after len field
+ unsigned type; // rtt debug type
+ unsigned format; // rtt debug format
+ char dbuf[0]; // debug content
+} rtt_debug_t;
+
+/* set configuration for debug */
+wifi_error wifi_rtt_debug_cfg(wifi_interface_handle h, unsigned rtt_dbg_type, char* cfgbuf,
+ unsigned cfg_buf_size);
+/* get the debug information */
+wifi_error wifi_rtt_debug_get(wifi_interface_handle h, rtt_debug_t** debugbuf);
+/* free the debug buffer */
+wifi_error wifi_rtt_debug_free(wifi_interface_handle h, rtt_debug_t* debugbuf);
+
+/* API for setting LCI/LCR information to be provided to a requestor */
+typedef enum {
+ WIFI_MOTION_NOT_EXPECTED = 0, // Not expected to change location
+ WIFI_MOTION_EXPECTED = 1, // Expected to change location
+ WIFI_MOTION_UNKNOWN = 2, // Movement pattern unknown
+} wifi_motion_pattern;
+
+typedef struct {
+ long latitude; // latitude in degrees * 2^25 , 2's complement
+ long longitude; // latitude in degrees * 2^25 , 2's complement
+ int altitude; // Altitude in units of 1/256 m
+ byte latitude_unc; // As defined in Section 2.3.2 of IETF RFC 6225
+ byte longitude_unc; // As defined in Section 2.3.2 of IETF RFC 6225
+ byte altitude_unc; // As defined in Section 2.4.5 from IETF RFC 6225:
+
+ // Following element for configuring the Z subelement
+ wifi_motion_pattern motion_pattern;
+ int floor; // floor in units of 1/16th of floor. 0x80000000 if unknown.
+ int height_above_floor; // in units of 1/64 m
+ int height_unc; // in units of 1/64 m. 0 if unknown
+} wifi_lci_information;
+
+typedef struct {
+ char country_code[2]; // country code
+ int length; // length of the info field
+ char civic_info[256]; // Civic info to be copied in FTM frame
+} wifi_lcr_information;
+
+// API to configure the LCI. Used in RTT Responder mode only
+wifi_error wifi_set_lci(wifi_request_id id, wifi_interface_handle iface, wifi_lci_information* lci);
+
+// API to configure the LCR. Used in RTT Responder mode only.
+wifi_error wifi_set_lcr(wifi_request_id id, wifi_interface_handle iface, wifi_lcr_information* lcr);
+
+/**
+ * RTT Responder information
+ */
+typedef struct {
+ wifi_channel_info channel;
+ wifi_rtt_preamble preamble;
+} wifi_rtt_responder;
+
+/**
+ * Get RTT responder information e.g. WiFi channel to enable responder on.
+ */
+wifi_error wifi_rtt_get_responder_info(wifi_interface_handle iface,
+ wifi_rtt_responder* responder_info);
+
+/**
+ * Enable RTT responder mode.
+ * channel_hint - hint of the channel information where RTT responder should be enabled on.
+ * max_duration_seconds - timeout of responder mode.
+ * channel_used - channel used for RTT responder, NULL if responder is not enabled.
+ */
+wifi_error wifi_enable_responder(wifi_request_id id, wifi_interface_handle iface,
+ wifi_channel_info channel_hint, unsigned max_duration_seconds,
+ wifi_rtt_responder* responder_info);
+
+/**
+ * Disable RTT responder mode.
+ */
+wifi_error wifi_disable_responder(wifi_request_id id, wifi_interface_handle iface);
+
+#endif
diff --git a/wifi/1.6/default/hal_legacy/tdls.h b/wifi/1.6/default/hal_legacy/tdls.h
new file mode 100644
index 0000000..787b13a
--- /dev/null
+++ b/wifi/1.6/default/hal_legacy/tdls.h
@@ -0,0 +1,84 @@
+
+#include "wifi_hal.h"
+
+#ifndef _TDLS_H_
+#define _TDLS_H_
+
+typedef enum {
+ WIFI_TDLS_DISABLED = 1, /* TDLS is not enabled, default status for all STAs */
+ WIFI_TDLS_ENABLED, /* TDLS is enabled, but not yet tried */
+ WIFI_TDLS_ESTABLISHED, /* Direct link is established */
+ WIFI_TDLS_ESTABLISHED_OFF_CHANNEL, /* Direct link is established using MCC */
+ WIFI_TDLS_DROPPED, /* Direct link was established,
+ * but is temporarily dropped now */
+ WIFI_TDLS_FAILED /* TDLS permanent failed. Inform error to upper layer
+ * and go back to WIFI_TDLS_DISABLED */
+} wifi_tdls_state;
+
+typedef enum {
+ WIFI_TDLS_SUCCESS, /* Success */
+ WIFI_TDLS_UNSPECIFIED = -1, /* Unspecified reason */
+ WIFI_TDLS_NOT_SUPPORTED = -2, /* Remote side doesn't support TDLS */
+ WIFI_TDLS_UNSUPPORTED_BAND = -3, /* Remote side doesn't support this band */
+ WIFI_TDLS_NOT_BENEFICIAL = -4, /* Going to AP is better than going direct */
+ WIFI_TDLS_DROPPED_BY_REMOTE = -5 /* Remote side doesn't want it anymore */
+} wifi_tdls_reason;
+
+typedef struct {
+ int channel; /* channel hint, in channel number (NOT frequency ) */
+ int global_operating_class; /* operating class to use */
+ int max_latency_ms; /* max latency that can be tolerated by apps */
+ int min_bandwidth_kbps; /* bandwidth required by apps, in kilo bits per second */
+} wifi_tdls_params;
+
+typedef struct {
+ int channel;
+ int global_operating_class;
+ wifi_tdls_state state;
+ wifi_tdls_reason reason;
+} wifi_tdls_status;
+
+typedef struct {
+ int max_concurrent_tdls_session_num; /* Maximum TDLS session number can be supported by the
+ * Firmware and hardware*/
+ int is_global_tdls_supported; /* 1 -- support, 0 -- not support */
+ int is_per_mac_tdls_supported; /* 1 -- support, 0 -- not support */
+ int is_off_channel_tdls_supported; /* 1 -- support, 0 -- not support */
+} wifi_tdls_capabilities;
+
+typedef struct {
+ /* on_tdls_state_changed - reports state of TDLS link to framework
+ * Report this event when the state of TDLS link changes */
+ void (*on_tdls_state_changed)(mac_addr addr, wifi_tdls_status status);
+} wifi_tdls_handler;
+
+/* wifi_enable_tdls - enables TDLS-auto mode for a specific route
+ *
+ * params specifies hints, which provide more information about
+ * why TDLS is being sought. The firmware should do its best to
+ * honor the hints before downgrading regular AP link
+ * If upper layer has no specific values, this should be NULL
+ *
+ * handler is used to inform the upper layer about the status change and the corresponding reason
+ */
+wifi_error wifi_enable_tdls(wifi_interface_handle iface, mac_addr addr, wifi_tdls_params* params,
+ wifi_tdls_handler handler);
+
+/* wifi_disable_tdls - disables TDLS-auto mode for a specific route
+ *
+ * This terminates any existing TDLS with addr device, and frees the
+ * device resources to make TDLS connections on new routes.
+ *
+ * DON'T fire any more events on 'handler' specified in earlier call to
+ * wifi_enable_tdls after this action.
+ */
+wifi_error wifi_disable_tdls(wifi_interface_handle iface, mac_addr addr);
+
+/* wifi_get_tdls_status - allows getting the status of TDLS for a specific route */
+wifi_error wifi_get_tdls_status(wifi_interface_handle iface, mac_addr addr,
+ wifi_tdls_status* status);
+
+/* return the current HW + Firmware combination's TDLS capabilities */
+wifi_error wifi_get_tdls_capabilities(wifi_interface_handle iface,
+ wifi_tdls_capabilities* capabilities);
+#endif
diff --git a/wifi/1.6/default/hal_legacy/uevent.h b/wifi/1.6/default/hal_legacy/uevent.h
new file mode 100644
index 0000000..5b82b32
--- /dev/null
+++ b/wifi/1.6/default/hal_legacy/uevent.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _HARDWARE_UEVENT_H
+#define _HARDWARE_UEVENT_H
+
+#if __cplusplus
+extern "C" {
+#endif
+
+int uevent_init();
+int uevent_get_fd();
+int uevent_next_event(char* buffer, int buffer_length);
+int uevent_add_native_handler(void (*handler)(void* data, const char* msg, int msg_len),
+ void* handler_data);
+int uevent_remove_native_handler(void (*handler)(void* data, const char* msg, int msg_len));
+
+#if __cplusplus
+} // extern "C"
+#endif
+
+#endif // _HARDWARE_UEVENT_H
diff --git a/wifi/1.6/default/hal_legacy/wifi_cached_scan_results.h b/wifi/1.6/default/hal_legacy/wifi_cached_scan_results.h
new file mode 100644
index 0000000..c7392c2
--- /dev/null
+++ b/wifi/1.6/default/hal_legacy/wifi_cached_scan_results.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __WIFI_CACHED_SCAN_RESULTS_H__
+#define __WIFI_CACHED_SCAN_RESULTS_H__
+
+#include "wifi_hal.h"
+
+#define WIFI_CACHED_SCAN_RESULT_FLAGS_NONE (0)
+/* Element ID 61 (HT Operation) is present (see HT 7.3.2) */
+#define WIFI_CACHED_SCAN_RESULT_FLAGS_HT_OPS_PRESENT (1 << 0)
+/* Element ID 192 (VHT Operation) is present (see VHT 8.4.2) */
+#define WIFI_CACHED_SCAN_RESULT_FLAGS_VHT_OPS_PRESENT (1 << 1)
+/* Element ID 255 + Extension 36 (HE Operation) is present
+ * (see 802.11ax 9.4.2.1)
+ */
+#define WIFI_CACHED_SCAN_RESULT_FLAGS_HE_OPS_PRESENT (1 << 2)
+/* Element ID 255 + Extension 106 (HE Operation) is present
+ * (see 802.11be D1.5 9.4.2.1)
+ */
+#define WIFI_CACHED_SCAN_RESULT_FLAGS_EHT_OPS_PRESENT (1 << 3)
+/* Element ID 127 (Extended Capabilities) is present, and bit 70
+ * (Fine Timing Measurement Responder) is set to 1
+ * (see IEEE Std 802.11-2016 9.4.2.27)
+ */
+#define WIFI_CACHED_SCAN_RESULT_FLAGS_IS_FTM_RESPONDER (1 << 4)
+
+/**
+ * Provides information about a single access point (AP) detected in a scan.
+ */
+typedef struct {
+ /* Number of milliseconds prior to ts in the enclosing
+ * wifi_cached_scan_result_report struct when
+ * the probe response or beacon frame that
+ * was used to populate this structure was received.
+ */
+ u32 age_ms;
+ /* The Capability Information field */
+ u16 capability;
+ /* null terminated */
+ u8 ssid[33];
+ u8 ssid_len;
+ u8 bssid[6];
+ /* A set of flags from WIFI_CACHED_SCAN_RESULT_FLAGS_* */
+ u8 flags;
+ s8 rssi;
+ wifi_channel_spec chanspec;
+} wifi_cached_scan_result;
+
+/*
+ * Data structure sent with events of type WifiCachedScanResult.
+ */
+typedef struct {
+ /* time since boot (in microsecond) when the result was retrieved */
+ wifi_timestamp ts;
+ /* If 0, indicates that all frequencies in current regulation were
+ * scanned. Otherwise, indicates the number of frequencies scanned, as
+ * specified in scanned_freq_list.
+ */
+ u16 scanned_freq_num;
+ /* Pointer to an array containing scanned_freq_num values comprising the
+ * set of frequencies that were scanned. Frequencies are specified as
+ * channel center frequencies in MHz. May be NULL if scannedFreqListLen is
+ * 0.
+ */
+ const u32* scanned_freq_list;
+ /* The total number of cached results returned. */
+ u8 result_cnt;
+ /* Pointer to an array containing result_cnt entries. May be NULL if
+ * result_cnt is 0.
+ */
+ const wifi_cached_scan_result* results;
+} wifi_cached_scan_report;
+
+/* callback for reporting cached scan report */
+typedef struct {
+ void (*on_cached_scan_results)(wifi_cached_scan_report* cache_report);
+} wifi_cached_scan_result_handler;
+#endif
diff --git a/wifi/1.6/default/hal_legacy/wifi_config.h b/wifi/1.6/default/hal_legacy/wifi_config.h
new file mode 100644
index 0000000..459a3fe
--- /dev/null
+++ b/wifi/1.6/default/hal_legacy/wifi_config.h
@@ -0,0 +1,44 @@
+#include "wifi_hal.h"
+
+#ifndef __WIFI_HAL_CONFIG_H
+#define __WIFI_HAL_CONFIG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define CONFIG_MAJOR_VERSION 1
+#define CONFIG_MINOR_VERSION 0
+#define CONFIG_MICRO_VERSION 0
+
+// whether the wifi chipset wakes at every dtim beacon or a multiple of the dtim period
+// if extended_dtim is set to 3, the STA shall wake up every 3 DTIM beacons
+wifi_error wifi_extended_dtim_config_set(wifi_request_id id, wifi_interface_handle iface,
+ int extended_dtim);
+
+// set the country code to driver
+wifi_error wifi_set_country_code(wifi_interface_handle iface, const char* country_code);
+
+// set the wifi_iface stats averaging factor used to calculate
+// statistics like average the TSF offset or average number of frame leaked
+// For instance, upon beacon reception:
+// current_avg = ((beacon_TSF - TBTT) * factor + previous_avg * (0x10000 - factor) ) / 0x10000
+// For instance, when evaluating leaky APs:
+// current_avg = ((num frame received within guard time) * factor + previous_avg * (0x10000 -
+// factor)) / 0x10000
+
+wifi_error wifi_set_beacon_wifi_iface_stats_averaging_factor(wifi_request_id id,
+ wifi_interface_handle iface,
+ u16 factor);
+
+// configure guard time, i.e. when implementing IEEE power management based on
+// frame control PM bit, how long driver waits before shutting down the radio and
+// after receiving an ACK for a data frame with PM bit set
+wifi_error wifi_set_guard_time(wifi_request_id id, wifi_interface_handle iface, u32 guard_time);
+
+#ifdef __cplusplus
+}
+
+#endif /* __cplusplus */
+
+#endif /*__WIFI_HAL_STATS_ */
diff --git a/wifi/1.6/default/hal_legacy/wifi_hal.h b/wifi/1.6/default/hal_legacy/wifi_hal.h
new file mode 100644
index 0000000..383ba71
--- /dev/null
+++ b/wifi/1.6/default/hal_legacy/wifi_hal.h
@@ -0,0 +1,1020 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __WIFI_HAL_H__
+#define __WIFI_HAL_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include <stdint.h>
+
+#define IFNAMSIZ 16
+
+/* typedefs */
+typedef unsigned char byte;
+typedef unsigned char u8;
+typedef signed char s8;
+typedef uint16_t u16;
+typedef uint32_t u32;
+typedef int32_t s32;
+typedef uint64_t u64;
+typedef int64_t s64;
+typedef int wifi_request_id;
+typedef int wifi_channel; // indicates channel frequency in MHz
+typedef int wifi_rssi;
+typedef int wifi_radio;
+typedef byte mac_addr[6];
+typedef byte oui[3];
+typedef int64_t wifi_timestamp; // In microseconds (us)
+typedef int64_t wifi_timespan; // In picoseconds (ps)
+typedef uint64_t feature_set;
+
+/* forward declarations */
+struct wifi_info;
+struct wifi_interface_info;
+typedef struct wifi_info* wifi_handle;
+typedef struct wifi_interface_info* wifi_interface_handle;
+
+/* WiFi Common definitions */
+/* channel operating width */
+typedef enum {
+ WIFI_CHAN_WIDTH_20 = 0,
+ WIFI_CHAN_WIDTH_40 = 1,
+ WIFI_CHAN_WIDTH_80 = 2,
+ WIFI_CHAN_WIDTH_160 = 3,
+ WIFI_CHAN_WIDTH_80P80 = 4,
+ WIFI_CHAN_WIDTH_5 = 5,
+ WIFI_CHAN_WIDTH_10 = 6,
+ WIFI_CHAN_WIDTH_320 = 7,
+ WIFI_CHAN_WIDTH_INVALID = -1
+} wifi_channel_width;
+
+/* Pre selected Power scenarios to be applied from BDF file */
+typedef enum {
+ WIFI_POWER_SCENARIO_INVALID = -2,
+ WIFI_POWER_SCENARIO_DEFAULT = -1,
+ WIFI_POWER_SCENARIO_VOICE_CALL = 0,
+ WIFI_POWER_SCENARIO_ON_HEAD_CELL_OFF = 1,
+ WIFI_POWER_SCENARIO_ON_HEAD_CELL_ON = 2,
+ WIFI_POWER_SCENARIO_ON_BODY_CELL_OFF = 3,
+ WIFI_POWER_SCENARIO_ON_BODY_CELL_ON = 4,
+ WIFI_POWER_SCENARIO_ON_BODY_BT = 5,
+ WIFI_POWER_SCENARIO_ON_HEAD_HOTSPOT = 6,
+ WIFI_POWER_SCENARIO_ON_HEAD_HOTSPOT_MMW = 7,
+ WIFI_POWER_SCENARIO_ON_BODY_CELL_ON_BT = 8,
+ WIFI_POWER_SCENARIO_ON_BODY_HOTSPOT = 9,
+ WIFI_POWER_SCENARIO_ON_BODY_HOTSPOT_BT = 10,
+ WIFI_POWER_SCENARIO_ON_BODY_HOTSPOT_MMW = 11,
+ WIFI_POWER_SCENARIO_ON_BODY_HOTSPOT_BT_MMW = 12,
+ WIFI_POWER_SCENARIO_ON_HEAD_CELL_OFF_UNFOLDED = 13,
+ WIFI_POWER_SCENARIO_ON_HEAD_CELL_ON_UNFOLDED = 14,
+ WIFI_POWER_SCENARIO_ON_HEAD_HOTSPOT_UNFOLDED = 15,
+ WIFI_POWER_SCENARIO_ON_HEAD_HOTSPOT_MMW_UNFOLDED = 16,
+ WIFI_POWER_SCENARIO_ON_BODY_CELL_OFF_UNFOLDED = 17,
+ WIFI_POWER_SCENARIO_ON_BODY_BT_UNFOLDED = 18,
+ WIFI_POWER_SCENARIO_ON_BODY_CELL_ON_UNFOLDED = 19,
+ WIFI_POWER_SCENARIO_ON_BODY_CELL_ON_BT_UNFOLDED = 20,
+ WIFI_POWER_SCENARIO_ON_BODY_HOTSPOT_UNFOLDED = 21,
+ WIFI_POWER_SCENARIO_ON_BODY_HOTSPOT_BT_UNFOLDED = 22,
+ WIFI_POWER_SCENARIO_ON_BODY_HOTSPOT_MMW_UNFOLDED = 23,
+ WIFI_POWER_SCENARIO_ON_BODY_HOTSPOT_BT_MMW_UNFOLDED = 24,
+} wifi_power_scenario;
+
+typedef enum {
+ WIFI_LATENCY_MODE_NORMAL = 0,
+ WIFI_LATENCY_MODE_LOW = 1,
+} wifi_latency_mode;
+
+/* Wifi Thermal mitigation modes */
+typedef enum {
+ WIFI_MITIGATION_NONE = 0,
+ WIFI_MITIGATION_LIGHT = 1,
+ WIFI_MITIGATION_MODERATE = 2,
+ WIFI_MITIGATION_SEVERE = 3,
+ WIFI_MITIGATION_CRITICAL = 4,
+ WIFI_MITIGATION_EMERGENCY = 5,
+} wifi_thermal_mode;
+
+/*
+ * Wifi voice over IP mode
+ * may add new modes later, for example, voice + video over IP mode.
+ */
+typedef enum {
+ WIFI_VOIP_MODE_OFF = 0,
+ WIFI_VOIP_MODE_ON = 1,
+} wifi_voip_mode;
+
+/* List of interface types supported */
+typedef enum {
+ WIFI_INTERFACE_TYPE_STA = 0,
+ WIFI_INTERFACE_TYPE_AP = 1,
+ WIFI_INTERFACE_TYPE_P2P = 2,
+ WIFI_INTERFACE_TYPE_NAN = 3,
+} wifi_interface_type;
+
+/*
+ * enum wlan_mac_band - Band information corresponding to the WLAN MAC.
+ */
+typedef enum {
+ /* WLAN MAC Operates in 2.4 GHz Band */
+ WLAN_MAC_2_4_BAND = 1 << 0,
+ /* WLAN MAC Operates in 5 GHz Band */
+ WLAN_MAC_5_0_BAND = 1 << 1,
+ /* WLAN MAC Operates in 6 GHz Band */
+ WLAN_MAC_6_0_BAND = 1 << 2,
+ /* WLAN MAC Operates in 60 GHz Band */
+ WLAN_MAC_60_0_BAND = 1 << 3,
+} wlan_mac_band;
+
+/* List of chre nan rtt state */
+typedef enum {
+ CHRE_PREEMPTED = 0,
+ CHRE_UNAVAILABLE = 1,
+ CHRE_AVAILABLE = 2,
+} chre_nan_rtt_state;
+
+typedef struct {
+ wifi_channel_width width;
+ int center_frequency0;
+ int center_frequency1;
+ int primary_frequency;
+} wifi_channel_spec;
+
+/*
+ * wifi_usable_channel specifies a channel frequency, bandwidth, and bitmask
+ * of modes allowed on the channel.
+ */
+typedef struct {
+ /* Channel frequency in MHz */
+ wifi_channel freq;
+ /* Channel operating width (20, 40, 80, 160, 320 etc.) */
+ wifi_channel_width width;
+ /* BIT MASK of BIT(WIFI_INTERFACE_*) represented by |wifi_interface_mode|
+ * Bitmask does not represent concurrency.
+ * Examples:
+ * - If a channel is usable only for STA, then only the WIFI_INTERFACE_STA
+ * bit would be set for that channel.
+ * - If 5GHz SAP is not allowed, then none of the 5GHz channels will have
+ * WIFI_INTERFACE_SOFTAP bit set.
+ * Note: TDLS bit is set only if there is a STA connection. TDLS bit is set
+ * on non-STA channels only if TDLS off channel is supported.
+ */
+ u32 iface_mode_mask;
+} wifi_usable_channel;
+
+/*
+ * wifi_usable_channel_filter
+ */
+typedef enum {
+ /* Filter Wifi channels that should be avoided due to cellular coex
+ * restrictions. Some Wifi channels can have extreme interference
+ * from/to cellular due to short frequency separation with neighboring
+ * cellular channels or when there is harmonic and intermodulation
+ * interference. Channels which only have some performance degradation
+ * (e.g. power back off is sufficient to deal with coexistence issue)
+ * can be included and should not be filtered out.
+ */
+ WIFI_USABLE_CHANNEL_FILTER_CELLULAR_COEXISTENCE = 1 << 0,
+ /* Filter channels due to concurrency state.
+ * Examples:
+ * - 5GHz SAP operation may be supported in standalone mode, but if
+ * there is STA connection on 5GHz DFS channel, none of the 5GHz
+ * channels are usable for SAP if device does not support DFS SAP mode.
+ * - P2P GO may not be supported on indoor channels in EU during
+ * standalone mode but if there is a STA connection on indoor channel,
+ * P2P GO may be supported by some vendors on the same STA channel.
+ */
+ WIFI_USABLE_CHANNEL_FILTER_CONCURRENCY = 1 << 1,
+ /* This Filter queries Wifi channels and bands that are supported for
+ * NAN3.1 Instant communication mode. This filter should only be applied to NAN interface.
+ * If 5G is supported default discovery channel 149/44 is considered,
+ * If 5G is not supported then channel 6 has to be considered.
+ * Based on regulatory domain if channel 149 and 44 are restricted, channel 6 should
+ * be considered for instant communication channel
+ */
+ WIFI_USABLE_CHANNEL_FILTER_NAN_INSTANT_MODE = 1 << 2,
+} wifi_usable_channel_filter;
+
+typedef enum {
+ WIFI_SUCCESS = 0,
+ WIFI_ERROR_NONE = 0,
+ WIFI_ERROR_UNKNOWN = -1,
+ WIFI_ERROR_UNINITIALIZED = -2,
+ WIFI_ERROR_NOT_SUPPORTED = -3,
+ WIFI_ERROR_NOT_AVAILABLE = -4, // Not available right now, but try later
+ WIFI_ERROR_INVALID_ARGS = -5,
+ WIFI_ERROR_INVALID_REQUEST_ID = -6,
+ WIFI_ERROR_TIMED_OUT = -7,
+ WIFI_ERROR_TOO_MANY_REQUESTS = -8, // Too many instances of this request
+ WIFI_ERROR_OUT_OF_MEMORY = -9,
+ WIFI_ERROR_BUSY = -10,
+} wifi_error;
+
+typedef enum {
+ WIFI_ACCESS_CATEGORY_BEST_EFFORT = 0,
+ WIFI_ACCESS_CATEGORY_BACKGROUND = 1,
+ WIFI_ACCESS_CATEGORY_VIDEO = 2,
+ WIFI_ACCESS_CATEGORY_VOICE = 3
+} wifi_access_category;
+
+/* Antenna configuration */
+typedef enum {
+ WIFI_ANTENNA_UNSPECIFIED = 0,
+ WIFI_ANTENNA_1X1 = 1,
+ WIFI_ANTENNA_2X2 = 2,
+ WIFI_ANTENNA_3X3 = 3,
+ WIFI_ANTENNA_4X4 = 4,
+} wifi_antenna_configuration;
+
+/* Wifi Radio configuration */
+typedef struct {
+ /* Operating band */
+ wlan_mac_band band;
+ /* Antenna configuration */
+ wifi_antenna_configuration antenna_cfg;
+} wifi_radio_configuration;
+
+/* WiFi Radio Combination */
+typedef struct {
+ u32 num_radio_configurations;
+ wifi_radio_configuration radio_configurations[];
+} wifi_radio_combination;
+
+/* WiFi Radio combinations matrix */
+/* For Example in case of a chip which has two radios, where one radio is
+ * capable of 2.4GHz 2X2 only and another radio which is capable of either
+ * 5GHz or 6GHz 2X2, number of possible radio combinations in this case
+ * are 5 and possible combinations are
+ * {{{2G 2X2}}, //Standalone 2G
+ * {{5G 2X2}}, //Standalone 5G
+ * {{6G 2X2}}, //Standalone 6G
+ * {{2G 2X2}, {5G 2X2}}, //2G+5G DBS
+ * {{2G 2X2}, {6G 2X2}}} //2G+6G DBS
+ * Note: Since this chip doesn’t support 5G+6G simultaneous operation
+ * as there is only one radio which can support both, So it can only
+ * do MCC 5G+6G. This table should not get populated with possible MCC
+ * configurations. This is only for simultaneous radio configurations
+ * (such as Standalone, multi band simultaneous or single band simultaneous).
+ */
+typedef struct {
+ u32 num_radio_combinations;
+ /* Each row represents possible radio combinations */
+ wifi_radio_combination radio_combinations[];
+} wifi_radio_combination_matrix;
+
+/* Initialize/Cleanup */
+
+wifi_error wifi_initialize(wifi_handle* handle);
+
+/**
+ * wifi_wait_for_driver
+ * Function should block until the driver is ready to proceed.
+ * Any errors from this function is considered fatal & will fail the HAL startup sequence.
+ *
+ * on success returns WIFI_SUCCESS
+ * on failure returns WIFI_ERROR_TIMED_OUT
+ */
+wifi_error wifi_wait_for_driver_ready(void);
+
+typedef void (*wifi_cleaned_up_handler)(wifi_handle handle);
+void wifi_cleanup(wifi_handle handle, wifi_cleaned_up_handler handler);
+void wifi_event_loop(wifi_handle handle);
+
+/* Error handling */
+void wifi_get_error_info(wifi_error err, const char** msg); // return a pointer to a static string
+
+/* Feature enums */
+#define WIFI_FEATURE_INFRA (uint64_t)0x1 // Basic infrastructure mode
+#define WIFI_FEATURE_INFRA_5G (uint64_t)0x2 // Support for 5 GHz Band
+#define WIFI_FEATURE_HOTSPOT (uint64_t)0x4 // Support for GAS/ANQP
+#define WIFI_FEATURE_P2P (uint64_t)0x8 // Wifi-Direct
+#define WIFI_FEATURE_SOFT_AP (uint64_t)0x10 // Soft AP
+#define WIFI_FEATURE_GSCAN (uint64_t)0x20 // Google-Scan APIs
+#define WIFI_FEATURE_NAN (uint64_t)0x40 // Neighbor Awareness Networking
+#define WIFI_FEATURE_D2D_RTT (uint64_t)0x80 // Device-to-device RTT
+#define WIFI_FEATURE_D2AP_RTT (uint64_t)0x100 // Device-to-AP RTT
+#define WIFI_FEATURE_BATCH_SCAN (uint64_t)0x200 // Batched Scan (legacy)
+#define WIFI_FEATURE_PNO (uint64_t)0x400 // Preferred network offload
+#define WIFI_FEATURE_ADDITIONAL_STA (uint64_t)0x800 // Support for two STAs
+#define WIFI_FEATURE_TDLS (uint64_t)0x1000 // Tunnel directed link setup
+#define WIFI_FEATURE_TDLS_OFFCHANNEL (uint64_t)0x2000 // Support for TDLS off channel
+#define WIFI_FEATURE_EPR (uint64_t)0x4000 // Enhanced power reporting
+#define WIFI_FEATURE_AP_STA (uint64_t)0x8000 // Support for AP STA Concurrency
+#define WIFI_FEATURE_LINK_LAYER_STATS (uint64_t)0x10000 // Link layer stats collection
+#define WIFI_FEATURE_LOGGER (uint64_t)0x20000 // WiFi Logger
+#define WIFI_FEATURE_HAL_EPNO (uint64_t)0x40000 // WiFi PNO enhanced
+#define WIFI_FEATURE_RSSI_MONITOR (uint64_t)0x80000 // RSSI Monitor
+#define WIFI_FEATURE_MKEEP_ALIVE (uint64_t)0x100000 // WiFi mkeep_alive
+#define WIFI_FEATURE_CONFIG_NDO (uint64_t)0x200000 // ND offload configure
+#define WIFI_FEATURE_TX_TRANSMIT_POWER (uint64_t)0x400000 // Capture Tx transmit power levels
+#define WIFI_FEATURE_CONTROL_ROAMING (uint64_t)0x800000 // Enable/Disable firmware roaming
+#define WIFI_FEATURE_IE_WHITELIST (uint64_t)0x1000000 // Support Probe IE white listing
+#define WIFI_FEATURE_SCAN_RAND \
+ (uint64_t)0x2000000 // Support MAC & Probe Sequence Number randomization
+#define WIFI_FEATURE_SET_TX_POWER_LIMIT (uint64_t)0x4000000 // Support Tx Power Limit setting
+#define WIFI_FEATURE_USE_BODY_HEAD_SAR \
+ (uint64_t)0x8000000 // Support Using Body/Head Proximity for SAR
+#define WIFI_FEATURE_DYNAMIC_SET_MAC \
+ (uint64_t)0x10000000 // Support changing MAC address without iface reset(down and up)
+#define WIFI_FEATURE_SET_LATENCY_MODE (uint64_t)0x40000000 // Support Latency mode setting
+#define WIFI_FEATURE_P2P_RAND_MAC (uint64_t)0x80000000 // Support P2P MAC randomization
+#define WIFI_FEATURE_INFRA_60G (uint64_t)0x100000000 // Support for 60GHz Band
+// Add more features here
+
+#define IS_MASK_SET(mask, flags) (((flags) & (mask)) == (mask))
+
+#define IS_SUPPORTED_FEATURE(feature, featureSet) IS_MASK_SET(feature, featureSet)
+
+/* Feature set */
+wifi_error wifi_get_supported_feature_set(wifi_interface_handle handle, feature_set* set);
+
+/*
+ * Each row represents a valid feature combination;
+ * all other combinations are invalid!
+ */
+wifi_error wifi_get_concurrency_matrix(wifi_interface_handle handle, int set_size_max,
+ feature_set set[], int* set_size);
+
+/* multiple interface support */
+
+wifi_error wifi_get_ifaces(wifi_handle handle, int* num_ifaces, wifi_interface_handle** ifaces);
+wifi_error wifi_get_iface_name(wifi_interface_handle iface, char* name, size_t size);
+wifi_interface_handle wifi_get_iface_handle(wifi_handle handle, char* name);
+
+/* STA + STA support - Supported if WIFI_FEATURE_ADDITIONAL_STA is set */
+
+/**
+ * Invoked to indicate that the provided iface is the primary STA iface when there are more
+ * than 1 STA iface concurrently active.
+ *
+ * Note: If the wifi firmware/chip cannot support multiple instances of any offload
+ * (like roaming, APF, rssi threshold, etc), the firmware should ensure that these
+ * offloads are at least enabled for the primary interface. If the new primary interface is
+ * already connected to a network, the firmware must switch all the offloads on
+ * this new interface without disconnecting.
+ */
+wifi_error wifi_multi_sta_set_primary_connection(wifi_handle handle, wifi_interface_handle iface);
+
+/**
+ * When there are 2 or more simultaneous STA connections, this use case hint indicates what
+ * use-case is being enabled by the framework. This use case hint can be used by the firmware
+ * to modify various firmware configurations like:
+ * - Allowed BSSIDs the firmware can choose for the initial connection/roaming attempts.
+ * - Duty cycle to choose for the 2 STA connections if the radio is in MCC mode.
+ * - Whether roaming, APF and other offloads needs to be enabled or not.
+ *
+ * Note:
+ * - This will be invoked before an active wifi connection is established on the second interface.
+ * - This use-case hint is implicitly void when the second STA interface is brought down.
+ */
+typedef enum {
+ /**
+ * Usage:
+ * - This will be sent down for make before break use-case.
+ * - Platform is trying to speculatively connect to a second network and evaluate it without
+ * disrupting the primary connection.
+ *
+ * Requirements for Firmware:
+ * - Do not reduce the number of tx/rx chains of primary connection.
+ * - If using MCC, should set the MCC duty cycle of the primary connection to be higher than
+ * the secondary connection (maybe 70/30 split).
+ * - Should pick the best BSSID for the secondary STA (disregard the chip mode) independent of
+ * the primary STA:
+ * - Don’t optimize for DBS vs MCC/SCC
+ * - Should not impact the primary connection’s bssid selection:
+ * - Don’t downgrade chains of the existing primary connection.
+ * - Don’t optimize for DBS vs MCC/SCC.
+ */
+ WIFI_DUAL_STA_TRANSIENT_PREFER_PRIMARY = 0,
+ /**
+ * Usage:
+ * - This will be sent down for any app requested peer to peer connections.
+ * - In this case, both the connections needs to be allocated equal resources.
+ * - For the peer to peer use case, BSSID for the secondary connection will be chosen by the
+ * framework.
+ *
+ * Requirements for Firmware:
+ * - Can choose MCC or DBS mode depending on the MCC efficiency and HW capability.
+ * - If using MCC, set the MCC duty cycle of the primary connection to be equal to the secondary
+ * connection.
+ * - Prefer BSSID candidates which will help provide the best "overall" performance for both the
+ * connections.
+ */
+ WIFI_DUAL_STA_NON_TRANSIENT_UNBIASED = 1
+} wifi_multi_sta_use_case;
+
+wifi_error wifi_multi_sta_set_use_case(wifi_handle handle, wifi_multi_sta_use_case use_case);
+
+/* Configuration events */
+
+typedef struct {
+ void (*on_country_code_changed)(char code[2]); // We can get this from supplicant too
+
+ // More event handlers
+} wifi_event_handler;
+
+typedef struct {
+ char iface_name[IFNAMSIZ + 1];
+ wifi_channel channel;
+} wifi_iface_info;
+
+typedef struct {
+ u32 wlan_mac_id;
+ /* BIT MASK of BIT(WLAN_MAC*) as represented by wlan_mac_band */
+ u32 mac_band;
+ /* Represents the connected Wi-Fi interfaces associated with each MAC */
+ int num_iface;
+ wifi_iface_info* iface_info;
+} wifi_mac_info;
+
+typedef struct {
+ void (*on_radio_mode_change)(wifi_request_id id, unsigned num_mac, wifi_mac_info* mac_info);
+} wifi_radio_mode_change_handler;
+
+typedef struct {
+ void (*on_rssi_threshold_breached)(wifi_request_id id, u8* cur_bssid, s8 cur_rssi);
+} wifi_rssi_event_handler;
+
+typedef struct {
+ void (*on_subsystem_restart)(const char* error);
+} wifi_subsystem_restart_handler;
+
+typedef struct {
+ void (*on_chre_nan_rtt_change)(chre_nan_rtt_state state);
+} wifi_chre_handler;
+
+wifi_error wifi_set_iface_event_handler(wifi_request_id id, wifi_interface_handle iface,
+ wifi_event_handler eh);
+wifi_error wifi_reset_iface_event_handler(wifi_request_id id, wifi_interface_handle iface);
+
+wifi_error wifi_set_nodfs_flag(wifi_interface_handle handle, u32 nodfs);
+wifi_error wifi_select_tx_power_scenario(wifi_interface_handle handle,
+ wifi_power_scenario scenario);
+wifi_error wifi_reset_tx_power_scenario(wifi_interface_handle handle);
+wifi_error wifi_set_latency_mode(wifi_interface_handle handle, wifi_latency_mode mode);
+wifi_error wifi_map_dscp_access_category(wifi_handle handle, uint32_t start, uint32_t end,
+ uint32_t access_category);
+wifi_error wifi_reset_dscp_mapping(wifi_handle handle);
+
+wifi_error wifi_set_subsystem_restart_handler(wifi_handle handle,
+ wifi_subsystem_restart_handler handler);
+
+/**
+ * Wifi HAL Thermal Mitigation API
+ *
+ * wifi_handle : wifi global handle (note: this is not a interface specific
+ * command). Mitigation is expected to be applied across all active interfaces
+ * The implementation and the mitigation action mapping to each mode is chip
+ * specific. Mitigation will be active until Wifi is turned off or
+ * WIFI_MITIGATION_NONE mode is sent
+ *
+ * mode: Thermal mitigation mode
+ * WIFI_MITIGATION_NONE : Clear all Wifi thermal mitigation actions
+ * WIFI_MITIGATION_LIGHT : Light Throttling where UX is not impacted
+ * WIFI_MITIGATION_MODERATE : Moderate throttling where UX not largely impacted
+ * WIFI_MITIGATION_SEVERE : Severe throttling where UX is largely impacted
+ * WIFI_MITIGATION_CRITICAL : Platform has done everything to reduce power
+ * WIFI_MITIGATION_EMERGENCY: Key components in platform are shutting down
+ *
+ * completion_window
+ * Deadline (in milliseconds) to complete this request, value 0 implies apply
+ * immediately. Deadline is basically a relaxed limit and allows vendors to
+ * apply the mitigation within the window (if it cannot apply immediately)
+ *
+ * Return
+ * WIFI_ERROR_NOT_SUPPORTED : Chip does not support thermal mitigation
+ * WIFI_ERROR_BUSY : Mitigation is supported, but retry later
+ * WIFI_ERROR_NONE : Mitigation request has been accepted
+ */
+wifi_error wifi_set_thermal_mitigation_mode(wifi_handle handle, wifi_thermal_mode mode,
+ u32 completion_window);
+
+typedef struct rx_data_cnt_details_t {
+ int rx_unicast_cnt; /*Total rx unicast packet which woke up host */
+ int rx_multicast_cnt; /*Total rx multicast packet which woke up host */
+ int rx_broadcast_cnt; /*Total rx broadcast packet which woke up host */
+} RX_DATA_WAKE_CNT_DETAILS;
+
+typedef struct rx_wake_pkt_type_classification_t {
+ int icmp_pkt; /*wake icmp packet count */
+ int icmp6_pkt; /*wake icmp6 packet count */
+ int icmp6_ra; /*wake icmp6 RA packet count */
+ int icmp6_na; /*wake icmp6 NA packet count */
+ int icmp6_ns; /*wake icmp6 NS packet count */
+ // ToDo: Any more interesting classification to add?
+} RX_WAKE_PKT_TYPE_CLASSFICATION;
+
+typedef struct rx_multicast_cnt_t {
+ int ipv4_rx_multicast_addr_cnt; /*Rx wake packet was ipv4 multicast */
+ int ipv6_rx_multicast_addr_cnt; /*Rx wake packet was ipv6 multicast */
+ int other_rx_multicast_addr_cnt; /*Rx wake packet was non-ipv4 and non-ipv6*/
+} RX_MULTICAST_WAKE_DATA_CNT;
+
+/*
+ * Structure holding all the driver/firmware wake count reasons.
+ *
+ * Buffers for the array fields (cmd_event_wake_cnt/driver_fw_local_wake_cnt)
+ * are allocated and freed by the framework. The size of each allocated
+ * array is indicated by the corresponding |_cnt| field. HAL needs to fill in
+ * the corresponding |_used| field to indicate the number of elements used in
+ * the array.
+ */
+typedef struct wlan_driver_wake_reason_cnt_t {
+ int total_cmd_event_wake; /* Total count of cmd event wakes */
+ int* cmd_event_wake_cnt; /* Individual wake count array, each index a reason */
+ int cmd_event_wake_cnt_sz; /* Max number of cmd event wake reasons */
+ int cmd_event_wake_cnt_used; /* Number of cmd event wake reasons specific to the driver */
+
+ int total_driver_fw_local_wake; /* Total count of drive/fw wakes, for local reasons */
+ int* driver_fw_local_wake_cnt; /* Individual wake count array, each index a reason */
+ int driver_fw_local_wake_cnt_sz; /* Max number of local driver/fw wake reasons */
+ int driver_fw_local_wake_cnt_used; /* Number of local driver/fw wake reasons specific to the
+ driver */
+
+ int total_rx_data_wake; /* total data rx packets, that woke up host */
+ RX_DATA_WAKE_CNT_DETAILS rx_wake_details;
+ RX_WAKE_PKT_TYPE_CLASSFICATION rx_wake_pkt_classification_info;
+ RX_MULTICAST_WAKE_DATA_CNT rx_multicast_wake_pkt_info;
+} WLAN_DRIVER_WAKE_REASON_CNT;
+
+/* Wi-Fi coex channel avoidance support */
+
+#define WIFI_COEX_NO_POWER_CAP (int32_t)0x7FFFFFF
+
+typedef enum { WIFI_AWARE = 1 << 0, SOFTAP = 1 << 1, WIFI_DIRECT = 1 << 2 } wifi_coex_restriction;
+
+/**
+ * Representation of a Wi-Fi channel to be avoided for Wi-Fi coex channel avoidance.
+ *
+ * band is represented as an WLAN_MAC* enum value defined in wlan_mac_band.
+ * If power_cap_dbm is WIFI_COEX_NO_POWER_CAP, then no power cap should be applied if the specified
+ * channel is used.
+ */
+typedef struct {
+ wlan_mac_band band;
+ u32 channel;
+ s32 power_cap_dbm;
+} wifi_coex_unsafe_channel;
+
+/* include various feature headers */
+
+#include "gscan.h"
+#include "link_layer_stats.h"
+#include "roam.h"
+#include "rtt.h"
+#include "tdls.h"
+#include "wifi_cached_scan_results.h"
+#include "wifi_config.h"
+#include "wifi_logger.h"
+#include "wifi_nan.h"
+#include "wifi_offload.h"
+#include "wifi_twt.h"
+
+// wifi HAL function pointer table
+typedef struct {
+ wifi_error (*wifi_initialize)(wifi_handle*);
+ wifi_error (*wifi_wait_for_driver_ready)(void);
+ void (*wifi_cleanup)(wifi_handle, wifi_cleaned_up_handler);
+ void (*wifi_event_loop)(wifi_handle);
+ void (*wifi_get_error_info)(wifi_error, const char**);
+ wifi_error (*wifi_get_supported_feature_set)(wifi_interface_handle, feature_set*);
+ wifi_error (*wifi_get_concurrency_matrix)(wifi_interface_handle, int, feature_set*, int*);
+ wifi_error (*wifi_set_scanning_mac_oui)(wifi_interface_handle, unsigned char*);
+ wifi_error (*wifi_get_supported_channels)(wifi_handle, int*, wifi_channel*);
+ wifi_error (*wifi_is_epr_supported)(wifi_handle);
+ wifi_error (*wifi_get_ifaces)(wifi_handle, int*, wifi_interface_handle**);
+ wifi_error (*wifi_get_iface_name)(wifi_interface_handle, char* name, size_t);
+ wifi_error (*wifi_set_iface_event_handler)(wifi_request_id, wifi_interface_handle,
+ wifi_event_handler);
+ wifi_error (*wifi_reset_iface_event_handler)(wifi_request_id, wifi_interface_handle);
+ wifi_error (*wifi_start_gscan)(wifi_request_id, wifi_interface_handle, wifi_scan_cmd_params,
+ wifi_scan_result_handler);
+ wifi_error (*wifi_stop_gscan)(wifi_request_id, wifi_interface_handle);
+ wifi_error (*wifi_get_cached_gscan_results)(wifi_interface_handle, byte, int,
+ wifi_cached_scan_results*, int*);
+ wifi_error (*wifi_set_bssid_hotlist)(wifi_request_id, wifi_interface_handle,
+ wifi_bssid_hotlist_params, wifi_hotlist_ap_found_handler);
+ wifi_error (*wifi_reset_bssid_hotlist)(wifi_request_id, wifi_interface_handle);
+ wifi_error (*wifi_set_significant_change_handler)(wifi_request_id, wifi_interface_handle,
+ wifi_significant_change_params,
+ wifi_significant_change_handler);
+ wifi_error (*wifi_reset_significant_change_handler)(wifi_request_id, wifi_interface_handle);
+ wifi_error (*wifi_get_gscan_capabilities)(wifi_interface_handle, wifi_gscan_capabilities*);
+ wifi_error (*wifi_set_link_stats)(wifi_interface_handle, wifi_link_layer_params);
+ wifi_error (*wifi_get_link_stats)(wifi_request_id, wifi_interface_handle,
+ wifi_stats_result_handler);
+ wifi_error (*wifi_clear_link_stats)(wifi_interface_handle, u32, u32*, u8, u8*);
+ wifi_error (*wifi_get_valid_channels)(wifi_interface_handle, int, int, wifi_channel*, int*);
+ wifi_error (*wifi_rtt_range_request)(wifi_request_id, wifi_interface_handle, unsigned,
+ wifi_rtt_config[], wifi_rtt_event_handler);
+ wifi_error (*wifi_rtt_range_cancel)(wifi_request_id, wifi_interface_handle, unsigned,
+ mac_addr[]);
+ wifi_error (*wifi_get_rtt_capabilities)(wifi_interface_handle, wifi_rtt_capabilities*);
+ wifi_error (*wifi_rtt_get_responder_info)(wifi_interface_handle iface,
+ wifi_rtt_responder* responder_info);
+ wifi_error (*wifi_enable_responder)(wifi_request_id id, wifi_interface_handle iface,
+ wifi_channel_info channel_hint,
+ unsigned max_duration_seconds,
+ wifi_rtt_responder* responder_info);
+ wifi_error (*wifi_disable_responder)(wifi_request_id id, wifi_interface_handle iface);
+ wifi_error (*wifi_set_nodfs_flag)(wifi_interface_handle, u32);
+ wifi_error (*wifi_start_logging)(wifi_interface_handle, u32, u32, u32, u32, char*);
+ wifi_error (*wifi_set_epno_list)(wifi_request_id, wifi_interface_handle,
+ const wifi_epno_params*, wifi_epno_handler);
+ wifi_error (*wifi_reset_epno_list)(wifi_request_id, wifi_interface_handle);
+ wifi_error (*wifi_set_country_code)(wifi_interface_handle, const char*);
+ wifi_error (*wifi_get_firmware_memory_dump)(wifi_interface_handle iface,
+ wifi_firmware_memory_dump_handler handler);
+ wifi_error (*wifi_set_log_handler)(wifi_request_id id, wifi_interface_handle iface,
+ wifi_ring_buffer_data_handler handler);
+ wifi_error (*wifi_reset_log_handler)(wifi_request_id id, wifi_interface_handle iface);
+ wifi_error (*wifi_set_alert_handler)(wifi_request_id id, wifi_interface_handle iface,
+ wifi_alert_handler handler);
+ wifi_error (*wifi_reset_alert_handler)(wifi_request_id id, wifi_interface_handle iface);
+ wifi_error (*wifi_get_firmware_version)(wifi_interface_handle iface, char* buffer,
+ int buffer_size);
+ wifi_error (*wifi_get_ring_buffers_status)(wifi_interface_handle iface, u32* num_rings,
+ wifi_ring_buffer_status* status);
+ wifi_error (*wifi_get_logger_supported_feature_set)(wifi_interface_handle iface,
+ unsigned int* support);
+ wifi_error (*wifi_get_ring_data)(wifi_interface_handle iface, char* ring_name);
+ wifi_error (*wifi_enable_tdls)(wifi_interface_handle, mac_addr, wifi_tdls_params*,
+ wifi_tdls_handler);
+ wifi_error (*wifi_disable_tdls)(wifi_interface_handle, mac_addr);
+ wifi_error (*wifi_get_tdls_status)(wifi_interface_handle, mac_addr, wifi_tdls_status*);
+ wifi_error (*wifi_get_tdls_capabilities)(wifi_interface_handle iface,
+ wifi_tdls_capabilities* capabilities);
+ wifi_error (*wifi_get_driver_version)(wifi_interface_handle iface, char* buffer,
+ int buffer_size);
+ wifi_error (*wifi_set_passpoint_list)(wifi_request_id id, wifi_interface_handle iface, int num,
+ wifi_passpoint_network* networks,
+ wifi_passpoint_event_handler handler);
+ wifi_error (*wifi_reset_passpoint_list)(wifi_request_id id, wifi_interface_handle iface);
+ wifi_error (*wifi_set_lci)(wifi_request_id id, wifi_interface_handle iface,
+ wifi_lci_information* lci);
+ wifi_error (*wifi_set_lcr)(wifi_request_id id, wifi_interface_handle iface,
+ wifi_lcr_information* lcr);
+ wifi_error (*wifi_start_sending_offloaded_packet)(wifi_request_id id,
+ wifi_interface_handle iface, u16 ether_type,
+ u8* ip_packet, u16 ip_packet_len,
+ u8* src_mac_addr, u8* dst_mac_addr,
+ u32 period_msec);
+ wifi_error (*wifi_stop_sending_offloaded_packet)(wifi_request_id id,
+ wifi_interface_handle iface);
+ wifi_error (*wifi_start_rssi_monitoring)(wifi_request_id id, wifi_interface_handle iface,
+ s8 max_rssi, s8 min_rssi, wifi_rssi_event_handler eh);
+ wifi_error (*wifi_stop_rssi_monitoring)(wifi_request_id id, wifi_interface_handle iface);
+ wifi_error (*wifi_get_wake_reason_stats)(wifi_interface_handle iface,
+ WLAN_DRIVER_WAKE_REASON_CNT* wifi_wake_reason_cnt);
+ wifi_error (*wifi_configure_nd_offload)(wifi_interface_handle iface, u8 enable);
+ wifi_error (*wifi_get_driver_memory_dump)(wifi_interface_handle iface,
+ wifi_driver_memory_dump_callbacks callbacks);
+ wifi_error (*wifi_start_pkt_fate_monitoring)(wifi_interface_handle iface);
+ wifi_error (*wifi_get_tx_pkt_fates)(wifi_interface_handle handle,
+ wifi_tx_report* tx_report_bufs, size_t n_requested_fates,
+ size_t* n_provided_fates);
+ wifi_error (*wifi_get_rx_pkt_fates)(wifi_interface_handle handle,
+ wifi_rx_report* rx_report_bufs, size_t n_requested_fates,
+ size_t* n_provided_fates);
+
+ /* NAN functions */
+ wifi_error (*wifi_nan_enable_request)(transaction_id id, wifi_interface_handle iface,
+ NanEnableRequest* msg);
+ wifi_error (*wifi_nan_disable_request)(transaction_id id, wifi_interface_handle iface);
+ wifi_error (*wifi_nan_publish_request)(transaction_id id, wifi_interface_handle iface,
+ NanPublishRequest* msg);
+ wifi_error (*wifi_nan_publish_cancel_request)(transaction_id id, wifi_interface_handle iface,
+ NanPublishCancelRequest* msg);
+ wifi_error (*wifi_nan_subscribe_request)(transaction_id id, wifi_interface_handle iface,
+ NanSubscribeRequest* msg);
+ wifi_error (*wifi_nan_subscribe_cancel_request)(transaction_id id, wifi_interface_handle iface,
+ NanSubscribeCancelRequest* msg);
+ wifi_error (*wifi_nan_transmit_followup_request)(transaction_id id, wifi_interface_handle iface,
+ NanTransmitFollowupRequest* msg);
+ wifi_error (*wifi_nan_stats_request)(transaction_id id, wifi_interface_handle iface,
+ NanStatsRequest* msg);
+ wifi_error (*wifi_nan_config_request)(transaction_id id, wifi_interface_handle iface,
+ NanConfigRequest* msg);
+ wifi_error (*wifi_nan_tca_request)(transaction_id id, wifi_interface_handle iface,
+ NanTCARequest* msg);
+ wifi_error (*wifi_nan_beacon_sdf_payload_request)(transaction_id id,
+ wifi_interface_handle iface,
+ NanBeaconSdfPayloadRequest* msg);
+ wifi_error (*wifi_nan_register_handler)(wifi_interface_handle iface,
+ NanCallbackHandler handlers);
+ wifi_error (*wifi_nan_get_version)(wifi_handle handle, NanVersion* version);
+ wifi_error (*wifi_nan_get_capabilities)(transaction_id id, wifi_interface_handle iface);
+ wifi_error (*wifi_nan_data_interface_create)(transaction_id id, wifi_interface_handle iface,
+ char* iface_name);
+ wifi_error (*wifi_nan_data_interface_delete)(transaction_id id, wifi_interface_handle iface,
+ char* iface_name);
+ wifi_error (*wifi_nan_data_request_initiator)(transaction_id id, wifi_interface_handle iface,
+ NanDataPathInitiatorRequest* msg);
+ wifi_error (*wifi_nan_data_indication_response)(transaction_id id, wifi_interface_handle iface,
+ NanDataPathIndicationResponse* msg);
+ wifi_error (*wifi_nan_data_end)(transaction_id id, wifi_interface_handle iface,
+ NanDataPathEndRequest* msg);
+ wifi_error (*wifi_select_tx_power_scenario)(wifi_interface_handle iface,
+ wifi_power_scenario scenario);
+ wifi_error (*wifi_reset_tx_power_scenario)(wifi_interface_handle iface);
+
+ /**
+ * Returns the chipset's hardware filtering capabilities:
+ * @param version pointer to version of the packet filter interpreter
+ * supported, filled in upon return. 0 indicates no support.
+ * @param max_len pointer to maximum size of the filter bytecode, filled in
+ * upon return.
+ */
+ wifi_error (*wifi_get_packet_filter_capabilities)(wifi_interface_handle handle, u32* version,
+ u32* max_len);
+ /**
+ * Programs the packet filter.
+ * @param program pointer to the program byte-code.
+ * @param len length of the program byte-code.
+ */
+ wifi_error (*wifi_set_packet_filter)(wifi_interface_handle handle, const u8* program, u32 len);
+ wifi_error (*wifi_read_packet_filter)(wifi_interface_handle handle, u32 src_offset,
+ u8* host_dst, u32 length);
+ wifi_error (*wifi_get_roaming_capabilities)(wifi_interface_handle handle,
+ wifi_roaming_capabilities* caps);
+ wifi_error (*wifi_enable_firmware_roaming)(wifi_interface_handle handle,
+ fw_roaming_state_t state);
+ wifi_error (*wifi_configure_roaming)(wifi_interface_handle handle,
+ wifi_roaming_config* roaming_config);
+ wifi_error (*wifi_set_radio_mode_change_handler)(wifi_request_id id,
+ wifi_interface_handle iface,
+ wifi_radio_mode_change_handler eh);
+ wifi_error (*wifi_set_latency_mode)(wifi_interface_handle iface, wifi_latency_mode mode);
+ wifi_error (*wifi_set_thermal_mitigation_mode)(wifi_handle handle, wifi_thermal_mode mode,
+ u32 completion_window);
+ wifi_error (*wifi_map_dscp_access_category)(wifi_handle handle, u32 start, u32 end,
+ u32 access_category);
+ wifi_error (*wifi_reset_dscp_mapping)(wifi_handle handle);
+
+ wifi_error (*wifi_virtual_interface_create)(wifi_handle handle, const char* ifname,
+ wifi_interface_type iface_type);
+ wifi_error (*wifi_virtual_interface_delete)(wifi_handle handle, const char* ifname);
+
+ wifi_error (*wifi_set_subsystem_restart_handler)(wifi_handle handle,
+ wifi_subsystem_restart_handler handler);
+
+ /**
+ * Allow vendor HAL to choose interface name when creating
+ * an interface. This can be implemented by chips with their
+ * own interface naming policy.
+ * If not implemented, the default naming will be used.
+ */
+ wifi_error (*wifi_get_supported_iface_name)(wifi_handle handle, u32 iface_type, char* name,
+ size_t len);
+
+ /**
+ * Perform early initialization steps that are needed when WIFI
+ * is disabled.
+ * If the function returns failure, it means the vendor HAL is unusable
+ * (for example, if chip hardware is not installed) and no further
+ * functions should be called.
+ */
+ wifi_error (*wifi_early_initialize)(void);
+
+ /**
+ * Get supported feature set which are chip-global, that is
+ * not dependent on any created interface.
+ */
+ wifi_error (*wifi_get_chip_feature_set)(wifi_handle handle, feature_set* set);
+
+ /**
+ * Invoked to indicate that the provided iface is the primary STA iface when there are more
+ * than 1 STA iface concurrently active.
+ */
+ wifi_error (*wifi_multi_sta_set_primary_connection)(wifi_handle handle,
+ wifi_interface_handle iface);
+
+ /**
+ * When there are 2 simultaneous STA connections, this use case hint
+ * indicates what STA + STA use-case is being enabled by the framework.
+ */
+ wifi_error (*wifi_multi_sta_set_use_case)(wifi_handle handle, wifi_multi_sta_use_case use_case);
+
+ /**
+ * Invoked to indicate that the following list of wifi_coex_unsafe_channel should be avoided
+ * with the specified restrictions.
+ * @param unsafeChannels list of current |wifi_coex_unsafe_channel| to avoid.
+ * @param restrictions bitmask of |wifi_coex_restriction| indicating wifi interfaces to
+ * restrict from the current unsafe channels.
+ */
+ wifi_error (*wifi_set_coex_unsafe_channels)(wifi_handle handle, u32 num_channels,
+ wifi_coex_unsafe_channel* unsafeChannels,
+ u32 restrictions);
+
+ /**
+ * Invoked to set voip optimization mode for the provided STA iface
+ */
+ wifi_error (*wifi_set_voip_mode)(wifi_interface_handle iface, wifi_voip_mode mode);
+
+ /**@brief twt_register_handler
+ * Request to register TWT callback before sending any TWT request
+ * @param wifi_interface_handle:
+ * @param TwtCallbackHandler: callback function pointers
+ * @return Synchronous wifi_error
+ */
+ wifi_error (*wifi_twt_register_handler)(wifi_interface_handle iface,
+ TwtCallbackHandler handler);
+
+ /**@brief twt_get_capability
+ * Request TWT capability
+ * @param wifi_interface_handle:
+ * @return Synchronous wifi_error and TwtCapabilitySet
+ */
+ wifi_error (*wifi_twt_get_capability)(wifi_interface_handle iface,
+ TwtCapabilitySet* twt_cap_set);
+
+ /**@brief twt_setup_request
+ * Request to send TWT setup frame
+ * @param wifi_interface_handle:
+ * @param TwtSetupRequest: detailed parameters of setup request
+ * @return Synchronous wifi_error
+ * @return Asynchronous EventTwtSetupResponse CB return TwtSetupResponse
+ */
+ wifi_error (*wifi_twt_setup_request)(wifi_interface_handle iface, TwtSetupRequest* msg);
+
+ /**@brief twt_teardown_request
+ * Request to send TWT teardown frame
+ * @param wifi_interface_handle:
+ * @param TwtTeardownRequest: detailed parameters of teardown request
+ * @return Synchronous wifi_error
+ * @return Asynchronous EventTwtTeardownCompletion CB return TwtTeardownCompletion
+ * TwtTeardownCompletion may also be received due to other events
+ * like CSA, BTCX, TWT scheduler, MultiConnection, peer-initiated teardown, etc.
+ */
+ wifi_error (*wifi_twt_teardown_request)(wifi_interface_handle iface, TwtTeardownRequest* msg);
+
+ /**@brief twt_info_frame_request
+ * Request to send TWT info frame
+ * @param wifi_interface_handle:
+ * @param TwtInfoFrameRequest: detailed parameters in info frame
+ * @return Synchronous wifi_error
+ * @return Asynchronous EventTwtInfoFrameReceived CB return TwtInfoFrameReceived
+ * Driver may also receive Peer-initiated TwtInfoFrame
+ */
+ wifi_error (*wifi_twt_info_frame_request)(wifi_interface_handle iface,
+ TwtInfoFrameRequest* msg);
+
+ /**@brief twt_get_stats
+ * Request to get TWT stats
+ * @param wifi_interface_handle:
+ * @param config_id: configuration ID of TWT request
+ * @return Synchronous wifi_error and TwtStats
+ */
+ wifi_error (*wifi_twt_get_stats)(wifi_interface_handle iface, u8 config_id, TwtStats* stats);
+
+ /**@brief twt_clear_stats
+ * Request to clear TWT stats
+ * @param wifi_interface_handle:
+ * @param config_id: configuration ID of TWT request
+ * @return Synchronous wifi_error
+ */
+ wifi_error (*wifi_twt_clear_stats)(wifi_interface_handle iface, u8 config_id);
+
+ /**
+ * Invoked to set DTIM configuration when the host is in the suspend mode
+ * @param wifi_interface_handle:
+ * @param multiplier: when STA in the power saving mode, the wake up interval will be set to
+ * 1) multiplier * DTIM period if multiplier > 0.
+ * 2) the device default value if multiplier <=0
+ * Some implementations may apply an additional cap to wake up interval in the case of 1).
+ */
+ wifi_error (*wifi_set_dtim_config)(wifi_interface_handle handle, u32 multiplier);
+
+ /**@brief wifi_get_usable_channels
+ * Request list of usable channels for the requested bands and modes. Usable
+ * implies channel is allowed as per regulatory for the current country code
+ * and not restricted due to other hard limitations (e.g. DFS, Coex) In
+ * certain modes (e.g. STA+SAP) there could be other hard restrictions
+ * since MCC operation many not be supported by SAP. This API also allows
+ * driver to return list of usable channels for each mode uniquely to
+ * distinguish cases where only a limited set of modes are allowed on
+ * a given channel e.g. srd channels may be supported for P2P but not
+ * for SAP or P2P-Client may be allowed on an indoor channel but P2P-GO
+ * may not be allowed. This API is not interface specific and will be
+ * used to query capabilities of driver in terms of what modes (STA, SAP,
+ * P2P_CLI, P2P_GO, NAN, TDLS) can be supported on each of the channels.
+ * @param handle global wifi_handle
+ * @param band_mask BIT MASK of WLAN_MAC* as represented by |wlan_mac_band|
+ * @param iface_mode_mask BIT MASK of BIT(WIFI_INTERFACE_*) represented by
+ * |wifi_interface_mode|. Bitmask respresents all the modes that the
+ * caller is interested in (e.g. STA, SAP, WFD-CLI, WFD-GO, TDLS, NAN).
+ * Note: Bitmask does not represent concurrency matrix. If the caller
+ * is interested in CLI, GO modes, the iface_mode_mask would be set
+ * to WIFI_INTERFACE_P2P_CLIENT|WIFI_INTERFACE_P2P_GO.
+ * @param filter_mask BIT MASK of WIFI_USABLE_CHANNEL_FILTER_* represented by
+ * |wifi_usable_channel_filter|. Indicates if the channel list should
+ * be filtered based on additional criteria. If filter_mask is not
+ * specified, driver should return list of usable channels purely
+ * based on regulatory constraints.
+ * @param max_size maximum number of |wifi_usable_channel|
+ * @param size actual number of |wifi_usable_channel| entries returned by driver
+ * @param channels list of usable channels represented by |wifi_usable_channel|
+ */
+ wifi_error (*wifi_get_usable_channels)(wifi_handle handle, u32 band_mask, u32 iface_mode_mask,
+ u32 filter_mask, u32 max_size, u32* size,
+ wifi_usable_channel* channels);
+
+ /**
+ * Trigger wifi subsystem restart to reload firmware
+ */
+ wifi_error (*wifi_trigger_subsystem_restart)(wifi_handle handle);
+
+ /**
+ * Invoked to set that the device is operating in an indoor environment.
+ * @param handle global wifi_handle
+ * @param isIndoor: true if the device is operating in an indoor
+ * environment, false otherwise.
+ * @return Synchronous wifi_error
+ */
+ wifi_error (*wifi_set_indoor_state)(wifi_handle handle, bool isIndoor);
+
+ /**@brief wifi_get_supported_radio_combinations_matrix
+ * Request all the possible radio combinations this device can offer.
+ * @param handle global wifi_handle
+ * @param max_size maximum size allocated for filling the wifi_radio_combination_matrix
+ * @param wifi_radio_combination_matrix to return all the possible radio
+ * combinations.
+ * @param size actual size of wifi_radio_combination_matrix returned from
+ * lower layer
+ *
+ */
+ wifi_error (*wifi_get_supported_radio_combinations_matrix)(
+ wifi_handle handle, u32 max_size, u32* size,
+ wifi_radio_combination_matrix* radio_combination_matrix);
+
+ /**@brief wifi_nan_rtt_chre_enable_request
+ * Request to enable CHRE NAN RTT
+ * @param transaction_id: NAN transaction id
+ * @param wifi_interface_handle
+ * @param NanEnableRequest request message
+ * @return Synchronous wifi_error
+ */
+ wifi_error (*wifi_nan_rtt_chre_enable_request)(transaction_id id, wifi_interface_handle iface,
+ NanEnableRequest* msg);
+
+ /**@brief wifi_nan_rtt_chre_disable_request
+ * Request to disable CHRE NAN RTT
+ * @param transaction_id: NAN transaction id
+ * @param wifi_interface_handle
+ * @return Synchronous wifi_error
+ */
+ wifi_error (*wifi_nan_rtt_chre_disable_request)(transaction_id id, wifi_interface_handle iface);
+
+ /**@brief wifi_chre_register_handler
+ * register a handler to get the state of CHR
+ * @param wifi_interface_handle
+ * @param wifi_chre_handler: callback function pointer
+ * @return Synchronous wifi_error
+ */
+ wifi_error (*wifi_chre_register_handler)(wifi_interface_handle iface,
+ wifi_chre_handler handler);
+
+ /**@brief wifi_enable_tx_power_limits
+ * Enable WiFi Tx power limis
+ * @param wifi_interface_handle
+ * @param isEnable : If enable TX limit or not
+ * @return Synchronous wifi_error
+ */
+ wifi_error (*wifi_enable_tx_power_limits)(wifi_interface_handle iface, bool isEnable);
+
+ /**@brief wifi_get_cached_scan_results
+ * Retrieve scan results cached in wifi firmware
+ * @param wifi_interface_handle
+ * @param wifi_cached_scan_result_handler : callback function pointer
+ * @return Synchronous wifi_error
+ */
+ wifi_error (*wifi_get_cached_scan_results)(wifi_interface_handle iface,
+ wifi_cached_scan_result_handler handler);
+ /*
+ * when adding new functions make sure to add stubs in
+ * hal_tool.cpp::init_wifi_stub_hal_func_table
+ */
+} wifi_hal_fn;
+
+wifi_error init_wifi_vendor_hal_func_table(wifi_hal_fn* fn);
+typedef wifi_error (*init_wifi_vendor_hal_func_table_t)(wifi_hal_fn* fn);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/wifi/1.6/default/hal_legacy/wifi_logger.h b/wifi/1.6/default/hal_legacy/wifi_logger.h
new file mode 100644
index 0000000..76d6f74
--- /dev/null
+++ b/wifi/1.6/default/hal_legacy/wifi_logger.h
@@ -0,0 +1,650 @@
+#include "wifi_hal.h"
+
+#ifndef __WIFI_HAL_LOGGER_H
+#define __WIFI_HAL_LOGGER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define LOGGER_MAJOR_VERSION 1
+#define LOGGER_MINOR_VERSION 0
+#define LOGGER_MICRO_VERSION 0
+
+/**
+ * WiFi logger life cycle is as follow:
+ *
+ * - At initialization time, framework will call wifi_get_ring_buffers_status
+ * so as to obtain the names and list of supported buffers.
+ * - When WiFi operation start framework will call wifi_start_logging
+ * so as to trigger log collection.
+ * - Developper UI will provide an option to the user, so as it can set the verbose level
+ * of individual buffer as reported by wifi_get_ring_buffers_status.
+ * - During wifi operations, driver will periodically report per ring data to framework
+ * by invoking the on_ring_buffer_data call back.
+ * - when capturing a bug report, framework will indicate to driver that all the data
+ * has to be uploaded, urgently, by calling wifi_get_ring_data.
+ *
+ * The data uploaded by driver will be stored by framework in separate files, with one stream
+ * of file per ring.
+ * Framework will store the files in pcapng format, allowing for easy merging and parsing
+ * with network analyzer tools.
+ */
+
+typedef int wifi_ring_buffer_id;
+
+#define PER_PACKET_ENTRY_FLAGS_DIRECTION_TX 1 // 0: TX, 1: RX
+#define PER_PACKET_ENTRY_FLAGS_TX_SUCCESS \
+ 2 // whether packet was transmitted or
+ // received/decrypted successfully
+#define PER_PACKET_ENTRY_FLAGS_80211_HEADER 4 // has full 802.11 header, else has 802.3 header
+#define PER_PACKET_ENTRY_FLAGS_PROTECTED 8 // whether packet was encrypted
+
+typedef struct {
+ u8 flags;
+ u8 tid; // transmit or received tid
+ u16 MCS; // modulation and bandwidth
+ u8 rssi; // TX: RSSI of ACK for that packet
+ // RX: RSSI of packet
+ u8 num_retries; // number of attempted retries
+ u16 last_transmit_rate; // last transmit rate in .5 mbps
+ u16 link_layer_transmit_sequence; // transmit/reeive sequence for that MPDU packet
+ u64 firmware_entry_timestamp; // TX: firmware timestamp (us) when packet is queued within
+ // firmware buffer for SDIO/HSIC or into PCIe buffer
+ // RX: firmware receive timestamp
+ u64 start_contention_timestamp; // firmware timestamp (us) when packet start contending for the
+ // medium for the first time, at head of its AC queue,
+ // or as part of an MPDU or A-MPDU. This timestamp is
+ // not updated for each retry, only the first transmit attempt.
+ u64 transmit_success_timestamp; // fimrware timestamp (us) when packet is successfully
+ // transmitted or aborted because it has exhausted
+ // its maximum number of retries.
+ u8 data[0]; // packet data. The length of packet data is determined by the entry_size field of
+ // the wifi_ring_buffer_entry structure. It is expected that first bytes of the
+ // packet, or packet headers only (up to TCP or RTP/UDP headers)
+ // will be copied into the ring
+} __attribute__((packed)) wifi_ring_per_packet_status_entry;
+
+/* Below events refer to the wifi_connectivity_event ring and shall be supported */
+#define WIFI_EVENT_ASSOCIATION_REQUESTED 0 // driver receives association command from kernel
+#define WIFI_EVENT_AUTH_COMPLETE 1
+#define WIFI_EVENT_ASSOC_COMPLETE 2
+#define WIFI_EVENT_FW_AUTH_STARTED 3 // fw event indicating auth frames are sent
+#define WIFI_EVENT_FW_ASSOC_STARTED 4 // fw event indicating assoc frames are sent
+#define WIFI_EVENT_FW_RE_ASSOC_STARTED 5 // fw event indicating reassoc frames are sent
+#define WIFI_EVENT_DRIVER_SCAN_REQUESTED 6
+#define WIFI_EVENT_DRIVER_SCAN_RESULT_FOUND 7
+#define WIFI_EVENT_DRIVER_SCAN_COMPLETE 8
+#define WIFI_EVENT_G_SCAN_STARTED 9
+#define WIFI_EVENT_G_SCAN_COMPLETE 10
+#define WIFI_EVENT_DISASSOCIATION_REQUESTED 11
+#define WIFI_EVENT_RE_ASSOCIATION_REQUESTED 12
+#define WIFI_EVENT_ROAM_REQUESTED 13
+#define WIFI_EVENT_BEACON_RECEIVED \
+ 14 // received beacon from AP (event enabled
+ // only in verbose mode)
+#define WIFI_EVENT_ROAM_SCAN_STARTED 15 // firmware has triggered a roam scan (not g-scan)
+#define WIFI_EVENT_ROAM_SCAN_COMPLETE 16 // firmware has completed a roam scan (not g-scan)
+#define WIFI_EVENT_ROAM_SEARCH_STARTED \
+ 17 // firmware has started searching for roam
+ // candidates (with reason =xx)
+#define WIFI_EVENT_ROAM_SEARCH_STOPPED \
+ 18 // firmware has stopped searching for roam
+ // candidates (with reason =xx)
+#define WIFI_EVENT_CHANNEL_SWITCH_ANOUNCEMENT 20 // received channel switch anouncement from AP
+#define WIFI_EVENT_FW_EAPOL_FRAME_TRANSMIT_START \
+ 21 // fw start transmit eapol frame, with
+ // EAPOL index 1-4
+#define WIFI_EVENT_FW_EAPOL_FRAME_TRANSMIT_STOP \
+ 22 // fw gives up eapol frame, with rate,
+ // success/failure and number retries
+#define WIFI_EVENT_DRIVER_EAPOL_FRAME_TRANSMIT_REQUESTED \
+ 23 // kernel queue EAPOL for transmission
+ // in driver with EAPOL index 1-4
+#define WIFI_EVENT_FW_EAPOL_FRAME_RECEIVED \
+ 24 // with rate, regardless of the fact that
+ // EAPOL frame is accepted or rejected by fw
+#define WIFI_EVENT_DRIVER_EAPOL_FRAME_RECEIVED \
+ 26 // with rate, and eapol index, driver has
+ // received EAPOL frame and will queue it up
+ // to wpa_supplicant
+#define WIFI_EVENT_BLOCK_ACK_NEGOTIATION_COMPLETE 27 // with success/failure, parameters
+#define WIFI_EVENT_BT_COEX_BT_SCO_START 28
+#define WIFI_EVENT_BT_COEX_BT_SCO_STOP 29
+#define WIFI_EVENT_BT_COEX_BT_SCAN_START \
+ 30 // for paging/scan etc., when BT starts transmiting
+ // twice per BT slot
+#define WIFI_EVENT_BT_COEX_BT_SCAN_STOP 31
+#define WIFI_EVENT_BT_COEX_BT_HID_START 32
+#define WIFI_EVENT_BT_COEX_BT_HID_STOP 33
+#define WIFI_EVENT_ROAM_AUTH_STARTED 34 // fw sends auth frame in roaming to next candidate
+#define WIFI_EVENT_ROAM_AUTH_COMPLETE 35 // fw receive auth confirm from ap
+#define WIFI_EVENT_ROAM_ASSOC_STARTED \
+ 36 // firmware sends assoc/reassoc frame in
+ // roaming to next candidate
+#define WIFI_EVENT_ROAM_ASSOC_COMPLETE 37 // firmware receive assoc/reassoc confirm from ap
+#define WIFI_EVENT_G_SCAN_STOP 38 // firmware sends stop G_SCAN
+#define WIFI_EVENT_G_SCAN_CYCLE_STARTED 39 // firmware indicates G_SCAN scan cycle started
+#define WIFI_EVENT_G_SCAN_CYCLE_COMPLETED 40 // firmware indicates G_SCAN scan cycle completed
+#define WIFI_EVENT_G_SCAN_BUCKET_STARTED \
+ 41 // firmware indicates G_SCAN scan start
+ // for a particular bucket
+#define WIFI_EVENT_G_SCAN_BUCKET_COMPLETED \
+ 42 // firmware indicates G_SCAN scan completed for
+ // for a particular bucket
+#define WIFI_EVENT_G_SCAN_RESULTS_AVAILABLE \
+ 43 // Event received from firmware about G_SCAN scan
+ // results being available
+#define WIFI_EVENT_G_SCAN_CAPABILITIES \
+ 44 // Event received from firmware with G_SCAN
+ // capabilities
+#define WIFI_EVENT_ROAM_CANDIDATE_FOUND \
+ 45 // Event received from firmware when eligible
+ // candidate is found
+#define WIFI_EVENT_ROAM_SCAN_CONFIG \
+ 46 // Event received from firmware when roam scan
+ // configuration gets enabled or disabled
+#define WIFI_EVENT_AUTH_TIMEOUT 47 // firmware/driver timed out authentication
+#define WIFI_EVENT_ASSOC_TIMEOUT 48 // firmware/driver timed out association
+#define WIFI_EVENT_MEM_ALLOC_FAILURE 49 // firmware/driver encountered allocation failure
+#define WIFI_EVENT_DRIVER_PNO_ADD 50 // driver added a PNO network in firmware
+#define WIFI_EVENT_DRIVER_PNO_REMOVE 51 // driver removed a PNO network in firmware
+#define WIFI_EVENT_DRIVER_PNO_NETWORK_FOUND \
+ 52 // driver received PNO networks
+ // found indication from firmware
+#define WIFI_EVENT_DRIVER_PNO_SCAN_REQUESTED 53 // driver triggered a scan for PNO networks
+#define WIFI_EVENT_DRIVER_PNO_SCAN_RESULT_FOUND \
+ 54 // driver received scan results
+ // of PNO networks
+#define WIFI_EVENT_DRIVER_PNO_SCAN_COMPLETE \
+ 55 // driver updated scan results from
+ // PNO networks to cfg80211
+
+/**
+ * Parameters of wifi logger events are TLVs
+ * Event parameters tags are defined as:
+ */
+#define WIFI_TAG_VENDOR_SPECIFIC 0 // take a byte stream as parameter
+#define WIFI_TAG_BSSID 1 // takes a 6 bytes MAC address as parameter
+#define WIFI_TAG_ADDR 2 // takes a 6 bytes MAC address as parameter
+#define WIFI_TAG_SSID 3 // takes a 32 bytes SSID address as parameter
+#define WIFI_TAG_STATUS 4 // takes an integer as parameter
+#define WIFI_TAG_CHANNEL_SPEC 5 // takes one or more wifi_channel_spec as parameter
+#define WIFI_TAG_WAKE_LOCK_EVENT 6 // takes a wake_lock_event struct as parameter
+#define WIFI_TAG_ADDR1 7 // takes a 6 bytes MAC address as parameter
+#define WIFI_TAG_ADDR2 8 // takes a 6 bytes MAC address as parameter
+#define WIFI_TAG_ADDR3 9 // takes a 6 bytes MAC address as parameter
+#define WIFI_TAG_ADDR4 10 // takes a 6 bytes MAC address as parameter
+#define WIFI_TAG_TSF 11 // take a 64 bits TSF value as parameter
+#define WIFI_TAG_IE \
+ 12 // take one or more specific 802.11 IEs parameter,
+ // IEs are in turn indicated in TLV format as per
+ // 802.11 spec
+#define WIFI_TAG_INTERFACE 13 // take interface name as parameter
+#define WIFI_TAG_REASON_CODE 14 // take a reason code as per 802.11 as parameter
+#define WIFI_TAG_RATE_MBPS 15 // take a wifi rate in 0.5 mbps
+#define WIFI_TAG_REQUEST_ID 16 // take an integer as parameter
+#define WIFI_TAG_BUCKET_ID 17 // take an integer as parameter
+#define WIFI_TAG_GSCAN_PARAMS 18 // takes a wifi_scan_cmd_params struct as parameter
+#define WIFI_TAG_GSCAN_CAPABILITIES 19 // takes a wifi_gscan_capabilities struct as parameter
+#define WIFI_TAG_SCAN_ID 20 // take an integer as parameter
+#define WIFI_TAG_RSSI 21 // take an integer as parameter
+#define WIFI_TAG_CHANNEL 22 // take an integer as parameter
+#define WIFI_TAG_LINK_ID 23 // take an integer as parameter
+#define WIFI_TAG_LINK_ROLE 24 // take an integer as parameter
+#define WIFI_TAG_LINK_STATE 25 // take an integer as parameter
+#define WIFI_TAG_LINK_TYPE 26 // take an integer as parameter
+#define WIFI_TAG_TSCO 27 // take an integer as parameter
+#define WIFI_TAG_RSCO 28 // take an integer as parameter
+#define WIFI_TAG_EAPOL_MESSAGE_TYPE \
+ 29 // take an integer as parameter
+ // M1-1, M2-2, M3-3, M4-4
+
+typedef struct {
+ u16 tag;
+ u16 length; // length of value
+ u8 value[0];
+} __attribute__((packed)) tlv_log;
+
+typedef struct {
+ u16 event;
+ tlv_log tlvs[0]; // separate parameter structure per event to be provided and optional data
+ // the event_data is expected to include an official android part, with some
+ // parameter as transmit rate, num retries, num scan result found etc...
+ // as well, event_data can include a vendor proprietary part which is
+ // understood by the developer only.
+} __attribute__((packed)) wifi_ring_buffer_driver_connectivity_event;
+
+/**
+ * Ring buffer name for power events ring. note that power event are extremely frequents
+ * and thus should be stored in their own ring/file so as not to clobber connectivity events.
+ */
+typedef struct {
+ int status; // 0 taken, 1 released
+ int reason; // reason why this wake lock is taken
+ char name[0]; // null terminated
+} __attribute__((packed)) wake_lock_event;
+
+typedef struct {
+ u16 event;
+ tlv_log tlvs[0];
+} __attribute__((packed)) wifi_power_event;
+
+/**
+ * This structure represent a logger entry within a ring buffer.
+ * Wifi driver are responsible to manage the ring buffer and write the debug
+ * information into those rings.
+ *
+ * In general, the debug entries can be used to store meaningful 802.11 information (SME, MLME,
+ * connection and packet statistics) as well as vendor proprietary data that is specific to a
+ * specific driver or chipset.
+ * Binary entries can be used so as to store packet data or vendor specific information and
+ * will be treated as blobs of data by android.
+ *
+ * A user land process will be started by framework so as to periodically retrieve the
+ * data logged by drivers into their ring buffer, store the data into log files and include
+ * the logs into android bugreports.
+ */
+enum {
+ RING_BUFFER_ENTRY_FLAGS_HAS_BINARY = (1 << (0)), // set for binary entries
+ RING_BUFFER_ENTRY_FLAGS_HAS_TIMESTAMP = (1 << (1)) // set if 64 bits timestamp is present
+};
+
+enum {
+ ENTRY_TYPE_CONNECT_EVENT = 1,
+ ENTRY_TYPE_PKT,
+ ENTRY_TYPE_WAKE_LOCK,
+ ENTRY_TYPE_POWER_EVENT,
+ ENTRY_TYPE_DATA
+};
+
+typedef struct {
+ u16 entry_size; // the size of payload excluding the header.
+ u8 flags;
+ u8 type; // entry type
+ u64 timestamp; // present if has_timestamp bit is set.
+} __attribute__((packed)) wifi_ring_buffer_entry;
+
+#define WIFI_RING_BUFFER_FLAG_HAS_BINARY_ENTRIES 0x00000001 // set if binary entries are present
+#define WIFI_RING_BUFFER_FLAG_HAS_ASCII_ENTRIES 0x00000002 // set if ascii entries are present
+
+/* ring buffer params */
+/**
+ * written_bytes and read_bytes implement a producer consumer API
+ * hence written_bytes >= read_bytes
+ * a modulo arithmetic of the buffer size has to be applied to those counters:
+ * actual offset into ring buffer = written_bytes % ring_buffer_byte_size
+ *
+ */
+typedef struct {
+ u8 name[32];
+ u32 flags;
+ wifi_ring_buffer_id ring_id; // unique integer representing the ring
+ u32 ring_buffer_byte_size; // total memory size allocated for the buffer
+ u32 verbose_level; // verbose level for ring buffer
+ u32 written_bytes; // number of bytes that was written to the buffer by driver,
+ // monotonously increasing integer
+ u32 read_bytes; // number of bytes that was read from the buffer by user land,
+ // monotonously increasing integer
+ u32 written_records; // number of records that was written to the buffer by driver,
+ // monotonously increasing integer
+} wifi_ring_buffer_status;
+
+/**
+ * Callback for reporting ring data
+ *
+ * The ring buffer data collection is event based:
+ * - Driver calls on_ring_buffer_data when new records are available, the wifi_ring_buffer_status
+ * passed up to framework in the call back indicates to framework if more data is available in
+ * the ring buffer. It is not expected that driver will necessarily always empty the ring
+ * immediately as data is available, instead driver will report data every X seconds or if
+ * N bytes are available.
+ * - In the case where a bug report has to be captured, framework will require driver to upload
+ * all data immediately. This is indicated to driver when framework calls wifi_get_ringdata.
+ * When framework calls wifi_get_ring_data, driver will start sending all available data in the
+ * indicated ring by repeatedly invoking the on_ring_buffer_data callback.
+ *
+ * The callback is called by log handler whenever ring data comes in driver.
+ */
+typedef struct {
+ void (*on_ring_buffer_data)(char* ring_name, char* buffer, int buffer_size,
+ wifi_ring_buffer_status* status);
+} wifi_ring_buffer_data_handler;
+
+/**
+ * API to set the log handler for getting ring data
+ * - Only a single instance of log handler can be instantiated for each ring buffer.
+ */
+wifi_error wifi_set_log_handler(wifi_request_id id, wifi_interface_handle iface,
+ wifi_ring_buffer_data_handler handler);
+
+/* API to reset the log handler */
+wifi_error wifi_reset_log_handler(wifi_request_id id, wifi_interface_handle iface);
+
+/**
+ * Callback for reporting FW dump
+ *
+ * The buffer data collection is event based such as FW health check or FW dump.
+ * The callback is called by alert handler.
+ */
+typedef struct {
+ void (*on_alert)(wifi_request_id id, char* buffer, int buffer_size, int err_code);
+} wifi_alert_handler;
+
+/*
+ * API to set the alert handler for the alert case in Wi-Fi Chip
+ * - Only a single instance of alert handler can be instantiated.
+ */
+wifi_error wifi_set_alert_handler(wifi_request_id id, wifi_interface_handle iface,
+ wifi_alert_handler handler);
+
+/* API to reset the alert handler */
+wifi_error wifi_reset_alert_handler(wifi_request_id id, wifi_interface_handle iface);
+
+/* API for framework to indicate driver has to upload and drain all data of a given ring */
+wifi_error wifi_get_ring_data(wifi_interface_handle iface, char* ring_name);
+
+/**
+ * API to trigger the debug collection.
+ * Unless his API is invoked - logging is not triggered.
+ * - Verbose_level 0 corresponds to no collection,
+ * and it makes log handler stop by no more events from driver.
+ * - Verbose_level 1 correspond to normal log level, with minimal user impact.
+ * This is the default value.
+ * - Verbose_level 2 are enabled when user is lazily trying to reproduce a problem,
+ * wifi performances and power can be impacted but device should not otherwise be
+ * significantly impacted.
+ * - Verbose_level 3+ are used when trying to actively debug a problem.
+ *
+ * ring_name represent the name of the ring for which data collection shall start.
+ *
+ * flags: TBD parameter used to enable/disable specific events on a ring
+ * max_interval: maximum interval in seconds for driver to invoke on_ring_buffer_data,
+ * ignore if zero
+ * min_data_size: minimum data size in buffer for driver to invoke on_ring_buffer_data,
+ * ignore if zero
+ */
+wifi_error wifi_start_logging(wifi_interface_handle iface, u32 verbose_level, u32 flags,
+ u32 max_interval_sec, u32 min_data_size, char* ring_name);
+
+/**
+ * API to get the status of all ring buffers supported by driver.
+ * - Caller is responsible to allocate / free ring buffer status.
+ * - Maximum no of ring buffer would be 10.
+ */
+wifi_error wifi_get_ring_buffers_status(wifi_interface_handle iface, u32* num_rings,
+ wifi_ring_buffer_status* status);
+
+/**
+ * Synchronous memory dump by user request.
+ * - Caller is responsible to store memory dump data into a local,
+ * e.g., /data/misc/wifi/memdump.bin
+ */
+typedef struct {
+ void (*on_firmware_memory_dump)(char* buffer, int buffer_size);
+} wifi_firmware_memory_dump_handler;
+
+/**
+ * API to collect a firmware memory dump for a given iface by async memdump event.
+ * - Triggered by Alerthandler, esp. when FW problem or FW health check happens
+ * - Caller is responsible to store fw dump data into a local,
+ * e.g., /data/misc/wifi/alertdump-1.bin
+ */
+wifi_error wifi_get_firmware_memory_dump(wifi_interface_handle iface,
+ wifi_firmware_memory_dump_handler handler);
+
+/**
+ * API to collect a firmware version string.
+ * - Caller is responsible to allocate / free a buffer to retrieve firmware verion info.
+ * - Max string will be at most 256 bytes.
+ */
+wifi_error wifi_get_firmware_version(wifi_interface_handle iface, char* buffer, int buffer_size);
+
+/**
+ * API to collect a driver version string.
+ * - Caller is responsible to allocate / free a buffer to retrieve driver verion info.
+ * - Max string will be at most 256 bytes.
+ */
+wifi_error wifi_get_driver_version(wifi_interface_handle iface, char* buffer, int buffer_size);
+
+/* Feature set */
+enum {
+ WIFI_LOGGER_MEMORY_DUMP_SUPPORTED = (1 << (0)), // Memory dump of FW
+ WIFI_LOGGER_PER_PACKET_TX_RX_STATUS_SUPPORTED = (1 << (1)), // PKT status
+ WIFI_LOGGER_CONNECT_EVENT_SUPPORTED = (1 << (2)), // Connectivity event
+ WIFI_LOGGER_POWER_EVENT_SUPPORTED = (1 << (3)), // POWER of Driver
+ WIFI_LOGGER_WAKE_LOCK_SUPPORTED = (1 << (4)), // WAKE LOCK of Driver
+ WIFI_LOGGER_VERBOSE_SUPPORTED = (1 << (5)), // verbose log of FW
+ WIFI_LOGGER_WATCHDOG_TIMER_SUPPORTED = (1 << (6)), // monitor the health of FW
+ WIFI_LOGGER_DRIVER_DUMP_SUPPORTED = (1 << (7)), // dumps driver state
+ WIFI_LOGGER_PACKET_FATE_SUPPORTED = (1 << (8)), // tracks connection packets' fate
+};
+
+/**
+ * API to retrieve the current supportive features.
+ * - An integer variable is enough to have bit mapping info by caller.
+ */
+wifi_error wifi_get_logger_supported_feature_set(wifi_interface_handle iface,
+ unsigned int* support);
+
+typedef struct {
+ /* Buffer is to be allocated and freed by HAL implementation. */
+ void (*on_driver_memory_dump)(char* buffer, int buffer_size);
+} wifi_driver_memory_dump_callbacks;
+
+/**
+ API to collect driver state.
+
+ Framework will call this API soon before or after (but not
+ concurrently with) wifi_get_firmware_memory_dump(). Capturing
+ firmware and driver dumps is intended to help identify
+ inconsistent state between these components.
+
+ - In response to this call, HAL implementation should make one or
+ more calls to callbacks.on_driver_memory_dump(). Framework will
+ copy data out of the received |buffer|s, and concatenate the
+ contents thereof.
+ - HAL implemention will indicate completion of the driver memory
+ dump by returning from this call.
+*/
+wifi_error wifi_get_driver_memory_dump(wifi_interface_handle iface,
+ wifi_driver_memory_dump_callbacks callbacks);
+
+/* packet fate logs */
+
+#define MD5_PREFIX_LEN 4
+#define MAX_FATE_LOG_LEN 32
+#define MAX_FRAME_LEN_ETHERNET 1518
+#define MAX_FRAME_LEN_80211_MGMT 2352 // 802.11-2012 Fig. 8-34
+
+typedef enum {
+ // Sent over air and ACKed.
+ TX_PKT_FATE_ACKED,
+
+ // Sent over air but not ACKed. (Normal for broadcast/multicast.)
+ TX_PKT_FATE_SENT,
+
+ // Queued within firmware, but not yet sent over air.
+ TX_PKT_FATE_FW_QUEUED,
+
+ // Dropped by firmware as invalid. E.g. bad source address, bad checksum,
+ // or invalid for current state.
+ TX_PKT_FATE_FW_DROP_INVALID,
+
+ // Dropped by firmware due to lack of buffer space.
+ TX_PKT_FATE_FW_DROP_NOBUFS,
+
+ // Dropped by firmware for any other reason. Includes frames that
+ // were sent by driver to firmware, but unaccounted for by
+ // firmware.
+ TX_PKT_FATE_FW_DROP_OTHER,
+
+ // Queued within driver, not yet sent to firmware.
+ TX_PKT_FATE_DRV_QUEUED,
+
+ // Dropped by driver as invalid. E.g. bad source address, or
+ // invalid for current state.
+ TX_PKT_FATE_DRV_DROP_INVALID,
+
+ // Dropped by driver due to lack of buffer space.
+ TX_PKT_FATE_DRV_DROP_NOBUFS,
+
+ // Dropped by driver for any other reason.
+ TX_PKT_FATE_DRV_DROP_OTHER,
+} wifi_tx_packet_fate;
+
+typedef enum {
+ // Valid and delivered to network stack (e.g., netif_rx()).
+ RX_PKT_FATE_SUCCESS,
+
+ // Queued within firmware, but not yet sent to driver.
+ RX_PKT_FATE_FW_QUEUED,
+
+ // Dropped by firmware due to host-programmable filters.
+ RX_PKT_FATE_FW_DROP_FILTER,
+
+ // Dropped by firmware as invalid. E.g. bad checksum, decrypt failed,
+ // or invalid for current state.
+ RX_PKT_FATE_FW_DROP_INVALID,
+
+ // Dropped by firmware due to lack of buffer space.
+ RX_PKT_FATE_FW_DROP_NOBUFS,
+
+ // Dropped by firmware for any other reason.
+ RX_PKT_FATE_FW_DROP_OTHER,
+
+ // Queued within driver, not yet delivered to network stack.
+ RX_PKT_FATE_DRV_QUEUED,
+
+ // Dropped by driver due to filter rules.
+ RX_PKT_FATE_DRV_DROP_FILTER,
+
+ // Dropped by driver as invalid. E.g. not permitted in current state.
+ RX_PKT_FATE_DRV_DROP_INVALID,
+
+ // Dropped by driver due to lack of buffer space.
+ RX_PKT_FATE_DRV_DROP_NOBUFS,
+
+ // Dropped by driver for any other reason.
+ RX_PKT_FATE_DRV_DROP_OTHER,
+} wifi_rx_packet_fate;
+
+typedef enum {
+ FRAME_TYPE_UNKNOWN,
+ FRAME_TYPE_ETHERNET_II,
+ FRAME_TYPE_80211_MGMT,
+} frame_type;
+
+typedef struct {
+ // The type of MAC-layer frame that this frame_info holds.
+ // - For data frames, use FRAME_TYPE_ETHERNET_II.
+ // - For management frames, use FRAME_TYPE_80211_MGMT.
+ // - If the type of the frame is unknown, use FRAME_TYPE_UNKNOWN.
+ frame_type payload_type;
+
+ // The number of bytes included in |frame_content|. If the frame
+ // contents are missing (e.g. RX frame dropped in firmware),
+ // |frame_len| should be set to 0.
+ size_t frame_len;
+
+ // Host clock when this frame was received by the driver (either
+ // outbound from the host network stack, or inbound from the
+ // firmware).
+ // - The timestamp should be taken from a clock which includes time
+ // the host spent suspended (e.g. ktime_get_boottime()).
+ // - If no host timestamp is available (e.g. RX frame was dropped in
+ // firmware), this field should be set to 0.
+ u32 driver_timestamp_usec;
+
+ // Firmware clock when this frame was received by the firmware
+ // (either outbound from the host, or inbound from a remote
+ // station).
+ // - The timestamp should be taken from a clock which includes time
+ // firmware spent suspended (if applicable).
+ // - If no firmware timestamp is available (e.g. TX frame was
+ // dropped by driver), this field should be set to 0.
+ // - Consumers of |frame_info| should _not_ assume any
+ // synchronization between driver and firmware clocks.
+ u32 firmware_timestamp_usec;
+
+ // Actual frame content.
+ // - Should be provided for TX frames originated by the host.
+ // - Should be provided for RX frames received by the driver.
+ // - Optionally provided for TX frames originated by firmware. (At
+ // discretion of HAL implementation.)
+ // - Optionally provided for RX frames dropped in firmware. (At
+ // discretion of HAL implementation.)
+ // - If frame content is not provided, |frame_len| should be set
+ // to 0.
+ union {
+ char ethernet_ii_bytes[MAX_FRAME_LEN_ETHERNET];
+ char ieee_80211_mgmt_bytes[MAX_FRAME_LEN_80211_MGMT];
+ } frame_content;
+} frame_info;
+
+typedef struct {
+ // Prefix of MD5 hash of |frame_inf.frame_content|. If frame
+ // content is not provided, prefix of MD5 hash over the same data
+ // that would be in frame_content, if frame content were provided.
+ char md5_prefix[MD5_PREFIX_LEN];
+ wifi_tx_packet_fate fate;
+ frame_info frame_inf;
+} wifi_tx_report;
+
+typedef struct {
+ // Prefix of MD5 hash of |frame_inf.frame_content|. If frame
+ // content is not provided, prefix of MD5 hash over the same data
+ // that would be in frame_content, if frame content were provided.
+ char md5_prefix[MD5_PREFIX_LEN];
+ wifi_rx_packet_fate fate;
+ frame_info frame_inf;
+} wifi_rx_report;
+
+/**
+ API to start packet fate monitoring.
+ - Once stared, monitoring should remain active until HAL is unloaded.
+ - When HAL is unloaded, all packet fate buffers should be cleared.
+*/
+wifi_error wifi_start_pkt_fate_monitoring(wifi_interface_handle handle);
+
+/**
+ API to retrieve fates of outbound packets.
+ - HAL implementation should fill |tx_report_bufs| with fates of
+ _first_ min(n_requested_fates, actual packets) frames
+ transmitted for the most recent association. The fate reports
+ should follow the same order as their respective packets.
+ - HAL implementation may choose (but is not required) to include
+ reports for management frames.
+ - Packets reported by firmware, but not recognized by driver,
+ should be included. However, the ordering of the corresponding
+ reports is at the discretion of HAL implementation.
+ - Framework may call this API multiple times for the same association.
+ - Framework will ensure |n_requested_fates <= MAX_FATE_LOG_LEN|.
+ - Framework will allocate and free the referenced storage.
+*/
+wifi_error wifi_get_tx_pkt_fates(wifi_interface_handle handle, wifi_tx_report* tx_report_bufs,
+ size_t n_requested_fates, size_t* n_provided_fates);
+
+/**
+ API to retrieve fates of inbound packets.
+ - HAL implementation should fill |rx_report_bufs| with fates of
+ _first_ min(n_requested_fates, actual packets) frames
+ received for the most recent association. The fate reports
+ should follow the same order as their respective packets.
+ - HAL implementation may choose (but is not required) to include
+ reports for management frames.
+ - Packets reported by firmware, but not recognized by driver,
+ should be included. However, the ordering of the corresponding
+ reports is at the discretion of HAL implementation.
+ - Framework may call this API multiple times for the same association.
+ - Framework will ensure |n_requested_fates <= MAX_FATE_LOG_LEN|.
+ - Framework will allocate and free the referenced storage.
+*/
+wifi_error wifi_get_rx_pkt_fates(wifi_interface_handle handle, wifi_rx_report* rx_report_bufs,
+ size_t n_requested_fates, size_t* n_provided_fates);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /*__WIFI_HAL_STATS_ */
diff --git a/wifi/1.6/default/hal_legacy/wifi_nan.h b/wifi/1.6/default/hal_legacy/wifi_nan.h
new file mode 100644
index 0000000..3591b98
--- /dev/null
+++ b/wifi/1.6/default/hal_legacy/wifi_nan.h
@@ -0,0 +1,2726 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NAN_H__
+#define __NAN_H__
+
+#include <net/if.h>
+#include <stdbool.h>
+#include "wifi_hal.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/*****************************************************************************
+ * Neighbour Aware Network Service Structures and Functions
+ *****************************************************************************/
+
+/*
+ Definitions
+ All multi-byte fields within all NAN protocol stack messages are assumed to be in Little Endian
+ order.
+*/
+
+typedef int NanVersion;
+typedef u16 transaction_id;
+typedef u32 NanDataPathId;
+
+#define NAN_MAC_ADDR_LEN 6
+#define NAN_MAJOR_VERSION 2
+#define NAN_MINOR_VERSION 0
+#define NAN_MICRO_VERSION 1
+#define NAN_MAX_SOCIAL_CHANNELS 3
+
+/* NAN Maximum Lengths */
+#define NAN_MAX_SERVICE_NAME_LEN 255
+#define NAN_MAX_MATCH_FILTER_LEN 255
+#define NAN_MAX_SERVICE_SPECIFIC_INFO_LEN 1024
+#define NAN_MAX_VSA_DATA_LEN 1024
+#define NAN_MAX_MESH_DATA_LEN 32
+#define NAN_MAX_INFRA_DATA_LEN 32
+#define NAN_MAX_CLUSTER_ATTRIBUTE_LEN 255
+#define NAN_MAX_SUBSCRIBE_MAX_ADDRESS 42
+#define NAN_MAX_FAM_CHANNELS 32
+#define NAN_MAX_POSTDISCOVERY_LEN 5
+#define NAN_MAX_FRAME_DATA_LEN 504
+#define NAN_DP_MAX_APP_INFO_LEN 512
+#define NAN_ERROR_STR_LEN 255
+#define NAN_PMK_INFO_LEN 32
+#define NAN_MAX_SCID_BUF_LEN 1024
+#define NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN 1024
+#define NAN_SECURITY_MIN_PASSPHRASE_LEN 8
+#define NAN_SECURITY_MAX_PASSPHRASE_LEN 63
+#define NAN_MAX_CHANNEL_INFO_SUPPORTED 4
+
+/*
+ Definition of various NanResponseType
+*/
+typedef enum {
+ NAN_RESPONSE_ENABLED = 0,
+ NAN_RESPONSE_DISABLED = 1,
+ NAN_RESPONSE_PUBLISH = 2,
+ NAN_RESPONSE_PUBLISH_CANCEL = 3,
+ NAN_RESPONSE_TRANSMIT_FOLLOWUP = 4,
+ NAN_RESPONSE_SUBSCRIBE = 5,
+ NAN_RESPONSE_SUBSCRIBE_CANCEL = 6,
+ NAN_RESPONSE_STATS = 7,
+ NAN_RESPONSE_CONFIG = 8,
+ NAN_RESPONSE_TCA = 9,
+ NAN_RESPONSE_ERROR = 10,
+ NAN_RESPONSE_BEACON_SDF_PAYLOAD = 11,
+ NAN_GET_CAPABILITIES = 12,
+ NAN_DP_INTERFACE_CREATE = 13,
+ NAN_DP_INTERFACE_DELETE = 14,
+ NAN_DP_INITIATOR_RESPONSE = 15,
+ NAN_DP_RESPONDER_RESPONSE = 16,
+ NAN_DP_END = 17
+} NanResponseType;
+
+/* NAN Publish Types */
+typedef enum {
+ NAN_PUBLISH_TYPE_UNSOLICITED = 0,
+ NAN_PUBLISH_TYPE_SOLICITED,
+ NAN_PUBLISH_TYPE_UNSOLICITED_SOLICITED
+} NanPublishType;
+
+/* NAN Transmit Priorities */
+typedef enum { NAN_TX_PRIORITY_NORMAL = 0, NAN_TX_PRIORITY_HIGH } NanTxPriority;
+
+/* NAN Statistics Request ID Codes */
+typedef enum {
+ NAN_STATS_ID_DE_PUBLISH = 0,
+ NAN_STATS_ID_DE_SUBSCRIBE,
+ NAN_STATS_ID_DE_MAC,
+ NAN_STATS_ID_DE_TIMING_SYNC,
+ NAN_STATS_ID_DE_DW,
+ NAN_STATS_ID_DE
+} NanStatsType;
+
+/* NAN Protocol Event ID Codes */
+typedef enum {
+ NAN_EVENT_ID_DISC_MAC_ADDR = 0,
+ NAN_EVENT_ID_STARTED_CLUSTER,
+ NAN_EVENT_ID_JOINED_CLUSTER
+} NanDiscEngEventType;
+
+/* NAN Data Path type */
+typedef enum { NAN_DATA_PATH_UNICAST_MSG = 0, NAN_DATA_PATH_MULTICAST_MSG } NdpType;
+
+/* NAN Ranging Configuration */
+typedef enum { NAN_RANGING_DISABLE = 0, NAN_RANGING_ENABLE } NanRangingState;
+
+/* TCA Type */
+typedef enum { NAN_TCA_ID_CLUSTER_SIZE = 0 } NanTcaType;
+
+/* NAN Channel Info */
+typedef struct {
+ u32 channel;
+ u32 bandwidth;
+ u32 nss;
+} NanChannelInfo;
+
+/*
+ Various NAN Protocol Response code
+*/
+typedef enum {
+ /* NAN Protocol Response Codes */
+ NAN_STATUS_SUCCESS = 0,
+ /* NAN Discovery Engine/Host driver failures */
+ NAN_STATUS_INTERNAL_FAILURE = 1,
+ /* NAN OTA failures */
+ NAN_STATUS_PROTOCOL_FAILURE = 2,
+ /* if the publish/subscribe id is invalid */
+ NAN_STATUS_INVALID_PUBLISH_SUBSCRIBE_ID = 3,
+ /* If we run out of resources allocated */
+ NAN_STATUS_NO_RESOURCE_AVAILABLE = 4,
+ /* if invalid params are passed */
+ NAN_STATUS_INVALID_PARAM = 5,
+ /* if the requestor instance id is invalid */
+ NAN_STATUS_INVALID_REQUESTOR_INSTANCE_ID = 6,
+ /* if the ndp id is invalid */
+ NAN_STATUS_INVALID_NDP_ID = 7,
+ /* if NAN is enabled when wifi is turned off */
+ NAN_STATUS_NAN_NOT_ALLOWED = 8,
+ /* if over the air ack is not received */
+ NAN_STATUS_NO_OTA_ACK = 9,
+ /* If NAN is already enabled and we are try to re-enable the same */
+ NAN_STATUS_ALREADY_ENABLED = 10,
+ /* If followup message internal queue is full */
+ NAN_STATUS_FOLLOWUP_QUEUE_FULL = 11,
+ /* Unsupported concurrency session enabled, NAN disabled notified */
+ NAN_STATUS_UNSUPPORTED_CONCURRENCY_NAN_DISABLED = 12
+} NanStatusType;
+
+/* NAN Transmit Types */
+typedef enum { NAN_TX_TYPE_BROADCAST = 0, NAN_TX_TYPE_UNICAST } NanTxType;
+
+/* NAN Subscribe Type */
+typedef enum { NAN_SUBSCRIBE_TYPE_PASSIVE = 0, NAN_SUBSCRIBE_TYPE_ACTIVE } NanSubscribeType;
+
+/* NAN Service Response Filter Attribute Bit */
+typedef enum { NAN_SRF_ATTR_BLOOM_FILTER = 0, NAN_SRF_ATTR_PARTIAL_MAC_ADDR } NanSRFType;
+
+/* NAN Service Response Filter Include Bit */
+typedef enum { NAN_SRF_INCLUDE_DO_NOT_RESPOND = 0, NAN_SRF_INCLUDE_RESPOND } NanSRFIncludeType;
+
+/* NAN Match indication type */
+typedef enum {
+ NAN_MATCH_ALG_MATCH_ONCE = 0,
+ NAN_MATCH_ALG_MATCH_CONTINUOUS,
+ NAN_MATCH_ALG_MATCH_NEVER
+} NanMatchAlg;
+
+/* NAN Transmit Window Type */
+typedef enum { NAN_TRANSMIT_IN_DW = 0, NAN_TRANSMIT_IN_FAW } NanTransmitWindowType;
+
+/* NAN SRF State in Subscribe */
+typedef enum { NAN_DO_NOT_USE_SRF = 0, NAN_USE_SRF } NanSRFState;
+
+/* NAN Include SSI in MatchInd */
+typedef enum {
+ NAN_SSI_NOT_REQUIRED_IN_MATCH_IND = 0,
+ NAN_SSI_REQUIRED_IN_MATCH_IND
+} NanSsiInMatchInd;
+
+/* NAN DP security Configuration */
+typedef enum { NAN_DP_CONFIG_NO_SECURITY = 0, NAN_DP_CONFIG_SECURITY } NanDataPathSecurityCfgStatus;
+
+typedef enum { NAN_QOS_NOT_REQUIRED = 0, NAN_QOS_REQUIRED } NanQosCfgStatus;
+
+/* Data request Responder's response */
+typedef enum { NAN_DP_REQUEST_ACCEPT = 0, NAN_DP_REQUEST_REJECT } NanDataPathResponseCode;
+
+/* NAN DP channel config options */
+typedef enum {
+ NAN_DP_CHANNEL_NOT_REQUESTED = 0,
+ NAN_DP_REQUEST_CHANNEL_SETUP,
+ NAN_DP_FORCE_CHANNEL_SETUP
+} NanDataPathChannelCfg;
+
+/* Enable/Disable NAN Ranging Auto response */
+typedef enum {
+ NAN_RANGING_AUTO_RESPONSE_ENABLE = 1,
+ NAN_RANGING_AUTO_RESPONSE_DISABLE
+} NanRangingAutoResponse;
+
+/* Enable/Disable NAN service range report */
+typedef enum { NAN_DISABLE_RANGE_REPORT = 1, NAN_ENABLE_RANGE_REPORT } NanRangeReport;
+
+/* NAN Range Response */
+typedef enum {
+ NAN_RANGE_REQUEST_ACCEPT = 1,
+ NAN_RANGE_REQUEST_REJECT,
+ NAN_RANGE_REQUEST_CANCEL
+} NanRangeResponse;
+
+/* NAN Security Key Input Type*/
+typedef enum {
+ NAN_SECURITY_KEY_INPUT_PMK = 1,
+ NAN_SECURITY_KEY_INPUT_PASSPHRASE
+} NanSecurityKeyInputType;
+
+typedef struct {
+ /* pmk length */
+ u32 pmk_len;
+ /*
+ PMK: Info is optional in Discovery phase.
+ PMK info can be passed during
+ the NDP session.
+ */
+ u8 pmk[NAN_PMK_INFO_LEN];
+} NanSecurityPmk;
+
+typedef struct {
+ /* passphrase length */
+ u32 passphrase_len;
+ /*
+ passphrase info is optional in Discovery phase.
+ passphrase info can be passed during
+ the NDP session.
+ */
+ u8 passphrase[NAN_SECURITY_MAX_PASSPHRASE_LEN];
+} NanSecurityPassPhrase;
+
+typedef struct {
+ NanSecurityKeyInputType key_type;
+ union {
+ NanSecurityPmk pmk_info;
+ NanSecurityPassPhrase passphrase_info;
+ } body;
+} NanSecurityKeyInfo;
+
+/* NAN Security Cipher Suites Mask */
+#define NAN_CIPHER_SUITE_SHARED_KEY_NONE 0x00
+#define NAN_CIPHER_SUITE_SHARED_KEY_128_MASK 0x01
+#define NAN_CIPHER_SUITE_SHARED_KEY_256_MASK 0x02
+#define NAN_CIPHER_SUITE_PUBLIC_KEY_2WDH_128_MASK 0x04
+#define NAN_CIPHER_SUITE_PUBLIC_KEY_2WDH_256_MASK 0x08
+
+/* NAN ranging indication condition MASKS */
+#define NAN_RANGING_INDICATE_CONTINUOUS_MASK 0x01
+#define NAN_RANGING_INDICATE_INGRESS_MET_MASK 0x02
+#define NAN_RANGING_INDICATE_EGRESS_MET_MASK 0x04
+
+/* NAN schedule update reason MASKS */
+#define NAN_SCHEDULE_UPDATE_NSS_MASK 0x01
+#define NAN_SCHEDULE_UPDATE_CHANNEL_MASK 0x02
+
+/*
+ Structure to set the Service Descriptor Extension
+ Attribute (SDEA) passed as part of NanPublishRequest/
+ NanSubscribeRequest/NanMatchInd.
+*/
+typedef struct {
+ /*
+ Optional configuration of Data Path Enable request.
+ configure flag determines whether configuration needs
+ to be passed or not.
+ */
+ u8 config_nan_data_path;
+ NdpType ndp_type;
+ /*
+ NAN secuirty required flag to indicate
+ if the security is enabled or disabled
+ */
+ NanDataPathSecurityCfgStatus security_cfg;
+ /*
+ NAN ranging required flag to indicate
+ if ranging is enabled on disabled
+ */
+ NanRangingState ranging_state;
+ /*
+ Enable/Disable Ranging report,
+ when configured NanRangeReportInd received
+ */
+ NanRangeReport range_report;
+ /*
+ NAN QOS required flag to indicate
+ if QOS is required or not.
+ */
+ NanQosCfgStatus qos_cfg;
+} NanSdeaCtrlParams;
+
+/*
+ Nan Ranging Peer Info in MatchInd
+*/
+typedef struct {
+ /*
+ Distance to the NAN device with the MAC address indicated
+ with ranged mac address.
+ */
+ u32 range_measurement_mm;
+ /* Ranging event matching the configuration of continuous/ingress/egress. */
+ u32 ranging_event_type;
+} NanRangeInfo;
+
+/* Nan/NDP Capabilites info */
+typedef struct {
+ u32 max_concurrent_nan_clusters;
+ u32 max_publishes;
+ u32 max_subscribes;
+ u32 max_service_name_len;
+ u32 max_match_filter_len;
+ u32 max_total_match_filter_len;
+ u32 max_service_specific_info_len;
+ u32 max_vsa_data_len;
+ u32 max_mesh_data_len;
+ u32 max_ndi_interfaces;
+ u32 max_ndp_sessions;
+ u32 max_app_info_len;
+ u32 max_queued_transmit_followup_msgs;
+ u32 ndp_supported_bands;
+ u32 cipher_suites_supported;
+ u32 max_scid_len;
+ bool is_ndp_security_supported;
+ u32 max_sdea_service_specific_info_len;
+ u32 max_subscribe_address;
+ u32 ndpe_attr_supported;
+ bool is_instant_mode_supported;
+} NanCapabilities;
+
+/*
+ Nan accept policy: Per service basis policy
+ Based on this policy(ALL/NONE), responder side
+ will send ACCEPT/REJECT
+*/
+typedef enum {
+ NAN_SERVICE_ACCEPT_POLICY_NONE = 0,
+ /* Default value */
+ NAN_SERVICE_ACCEPT_POLICY_ALL
+} NanServiceAcceptPolicy;
+
+/*
+ Host can send Vendor specific attributes which the Discovery Engine can
+ enclose in Beacons and/or Service Discovery frames transmitted.
+ Below structure is used to populate that.
+*/
+typedef struct {
+ /*
+ 0 = transmit only in the next discovery window
+ 1 = transmit in next 16 discovery window
+ */
+ u8 payload_transmit_flag;
+ /*
+ Below flags will determine in which all frames
+ the vendor specific attributes should be included
+ */
+ u8 tx_in_discovery_beacon;
+ u8 tx_in_sync_beacon;
+ u8 tx_in_service_discovery;
+ /* Organizationally Unique Identifier */
+ u32 vendor_oui;
+ /*
+ vendor specific attribute to be transmitted
+ vsa_len : Length of the vsa data.
+ */
+ u32 vsa_len;
+ u8 vsa[NAN_MAX_VSA_DATA_LEN];
+} NanTransmitVendorSpecificAttribute;
+
+/*
+ Discovery Engine will forward any Vendor Specific Attributes
+ which it received as part of this structure.
+*/
+/* Mask to determine on which frames attribute was received */
+#define RX_DISCOVERY_BEACON_MASK 0x01
+#define RX_SYNC_BEACON_MASK 0x02
+#define RX_SERVICE_DISCOVERY_MASK 0x04
+typedef struct {
+ /*
+ Frames on which this vendor specific attribute
+ was received. Mask defined above
+ */
+ u8 vsa_received_on;
+ /* Organizationally Unique Identifier */
+ u32 vendor_oui;
+ /* vendor specific attribute */
+ u32 attr_len;
+ u8 vsa[NAN_MAX_VSA_DATA_LEN];
+} NanReceiveVendorSpecificAttribute;
+
+/*
+ NAN Beacon SDF Payload Received structure
+ Discovery engine sends the details of received Beacon or
+ Service Discovery Frames as part of this structure.
+*/
+typedef struct {
+ /* Frame data */
+ u32 frame_len;
+ u8 frame_data[NAN_MAX_FRAME_DATA_LEN];
+} NanBeaconSdfPayloadReceive;
+
+/*
+ Host can set the Periodic scan parameters for each of the
+ 3(6, 44, 149) Social channels. Only these channels are allowed
+ any other channels are rejected
+*/
+typedef enum {
+ NAN_CHANNEL_24G_BAND = 0,
+ NAN_CHANNEL_5G_BAND_LOW,
+ NAN_CHANNEL_5G_BAND_HIGH
+} NanChannelIndex;
+
+/*
+ Structure to set the Social Channel Scan parameters
+ passed as part of NanEnableRequest/NanConfigRequest
+*/
+typedef struct {
+ /*
+ Dwell time of each social channel in milliseconds
+ NanChannelIndex corresponds to the respective channel
+ If time set to 0 then the FW default time will be used.
+ */
+ u8 dwell_time[NAN_MAX_SOCIAL_CHANNELS]; // default value 200 msec
+
+ /*
+ Scan period of each social channel in seconds
+ NanChannelIndex corresponds to the respective channel
+ If time set to 0 then the FW default time will be used.
+ */
+ u16 scan_period[NAN_MAX_SOCIAL_CHANNELS]; // default value 20 sec
+} NanSocialChannelScanParams;
+
+/*
+ Host can send Post Connectivity Capability attributes
+ to be included in Service Discovery frames transmitted
+ as part of this structure.
+*/
+typedef struct {
+ /*
+ 0 = transmit only in the next discovery window
+ 1 = transmit in next 16 discovery window
+ */
+ u8 payload_transmit_flag;
+ /* 1 - Wifi Direct supported 0 - Not supported */
+ u8 is_wfd_supported;
+ /* 1 - Wifi Direct Services supported 0 - Not supported */
+ u8 is_wfds_supported;
+ /* 1 - TDLS supported 0 - Not supported */
+ u8 is_tdls_supported;
+ /* 1 - IBSS supported 0 - Not supported */
+ u8 is_ibss_supported;
+ /* 1 - Mesh supported 0 - Not supported */
+ u8 is_mesh_supported;
+ /*
+ 1 - NAN Device currently connect to WLAN Infra AP
+ 0 - otherwise
+ */
+ u8 wlan_infra_field;
+} NanTransmitPostConnectivityCapability;
+
+/*
+ Discovery engine providing the post connectivity capability
+ received.
+*/
+typedef struct {
+ /* 1 - Wifi Direct supported 0 - Not supported */
+ u8 is_wfd_supported;
+ /* 1 - Wifi Direct Services supported 0 - Not supported */
+ u8 is_wfds_supported;
+ /* 1 - TDLS supported 0 - Not supported */
+ u8 is_tdls_supported;
+ /* 1 - IBSS supported 0 - Not supported */
+ u8 is_ibss_supported;
+ /* 1 - Mesh supported 0 - Not supported */
+ u8 is_mesh_supported;
+ /*
+ 1 - NAN Device currently connect to WLAN Infra AP
+ 0 - otherwise
+ */
+ u8 wlan_infra_field;
+} NanReceivePostConnectivityCapability;
+
+/*
+ Indicates the availability interval duration associated with the
+ Availability Intervals Bitmap field
+*/
+typedef enum {
+ NAN_DURATION_16MS = 0,
+ NAN_DURATION_32MS = 1,
+ NAN_DURATION_64MS = 2
+} NanAvailDuration;
+
+/* Further availability per channel information */
+typedef struct {
+ /* Defined above */
+ NanAvailDuration entry_control;
+ /*
+ 1 byte field indicating the frequency band the NAN Device
+ will be available as defined in IEEE Std. 802.11-2012
+ Annex E Table E-4 Global Operating Classes
+ */
+ u8 class_val;
+ /*
+ 1 byte field indicating the channel the NAN Device
+ will be available.
+ */
+ u8 channel;
+ /*
+ Map Id - 4 bit field which identifies the Further
+ availability map attribute.
+ */
+ u8 mapid;
+ /*
+ divides the time between the beginnings of consecutive Discovery
+ Windows of a given NAN cluster into consecutive time intervals
+ of equal durations. The time interval duration is specified by
+ the Availability Interval Duration subfield of the Entry Control
+ field.
+
+ A Nan device that sets the i-th bit of the Availability
+ Intervals Bitmap to 1 shall be present during the corresponding
+ i-th time interval in the operation channel indicated by the
+ Operating Class and Channel Number fields in the same Availability Entry.
+
+ A Nan device that sets the i-th bit of the Availability Intervals Bitmap to
+ 0 may be present during the corresponding i-th time interval in the operation
+ channel indicated by the Operating Class and Channel Number fields in the same
+ Availability Entry.
+
+ The size of the Bitmap is dependent upon the Availability Interval Duration
+ chosen in the Entry Control Field. The size can be either 1, 2 or 4 bytes long
+
+ - Duration field is equal to 0, only AIB[0] is valid
+ - Duration field is equal to 1, only AIB [0] and AIB [1] is valid
+ - Duration field is equal to 2, AIB [0], AIB [1], AIB [2] and AIB [3] are valid
+ */
+ u32 avail_interval_bitmap;
+} NanFurtherAvailabilityChannel;
+
+/*
+ Further availability map which can be sent and received from
+ Discovery engine
+*/
+typedef struct {
+ /*
+ Number of channels indicates the number of channel
+ entries which is part of fam
+ */
+ u8 numchans;
+ NanFurtherAvailabilityChannel famchan[NAN_MAX_FAM_CHANNELS];
+} NanFurtherAvailabilityMap;
+
+/*
+ Host can send Post-Nan Discovery attributes which the Discovery Engine can
+ enclose in Service Discovery frames
+*/
+/* Possible connection types in Post NAN Discovery attributes */
+typedef enum {
+ NAN_CONN_WLAN_INFRA = 0,
+ NAN_CONN_P2P_OPER = 1,
+ NAN_CONN_WLAN_IBSS = 2,
+ NAN_CONN_WLAN_MESH = 3,
+ NAN_CONN_FURTHER_SERVICE_AVAILABILITY = 4,
+ NAN_CONN_WLAN_RANGING = 5
+} NanConnectionType;
+
+/* Possible device roles in Post NAN Discovery attributes */
+typedef enum {
+ NAN_WLAN_INFRA_AP = 0,
+ NAN_WLAN_INFRA_STA = 1,
+ NAN_P2P_OPER_GO = 2,
+ NAN_P2P_OPER_DEV = 3,
+ NAN_P2P_OPER_CLI = 4
+} NanDeviceRole;
+
+/* Configuration params of NAN Ranging */
+typedef struct {
+ /*
+ Interval in milli sec between two ranging measurements.
+ If the Awake DW intervals in NanEnable/Config are larger
+ than the ranging intervals priority is given to Awake DW
+ Intervals. Only on a match the ranging is initiated for the
+ peer
+ */
+ u32 ranging_interval_msec;
+ /*
+ Flags indicating the type of ranging event to be notified
+ NAN_RANGING_INDICATE_ MASKS are used to set these.
+ BIT0 - Continuous Ranging event notification.
+ BIT1 - Ingress distance is <=.
+ BIT2 - Egress distance is >=.
+ */
+ u32 config_ranging_indications;
+ /* Ingress distance in millimeters (optional) */
+ u32 distance_ingress_mm;
+ /* Egress distance in millmilliimeters (optional) */
+ u32 distance_egress_mm;
+} NanRangingCfg;
+
+/* NAN Ranging request's response */
+typedef struct {
+ /* Publish Id of an earlier Publisher */
+ u16 publish_id;
+ /*
+ A 32 bit Requestor instance Id which is sent to the Application.
+ This Id will be used in subsequent RangeResponse on Subscribe side.
+ */
+ u32 requestor_instance_id;
+ /* Peer MAC addr of Range Requestor */
+ u8 peer_addr[NAN_MAC_ADDR_LEN];
+ /* Response indicating ACCEPT/REJECT/CANCEL of Range Request */
+ NanRangeResponse ranging_response;
+} NanRangeResponseCfg;
+
+/* Structure of Post NAN Discovery attribute */
+typedef struct {
+ /* Connection type of the host */
+ NanConnectionType type;
+ /*
+ Device role of the host based on
+ the connection type
+ */
+ NanDeviceRole role;
+ /*
+ Flag to send the information as a single shot or repeated
+ for next 16 discovery windows
+ 0 - Single_shot
+ 1 - next 16 discovery windows
+ */
+ u8 transmit_freq;
+ /* Duration of the availability bitmask */
+ NanAvailDuration duration;
+ /* Availability interval bitmap based on duration */
+ u32 avail_interval_bitmap;
+ /*
+ Mac address depending on the conn type and device role
+ --------------------------------------------------
+ | Conn Type | Device Role | Mac address Usage |
+ --------------------------------------------------
+ | WLAN_INFRA | AP/STA | BSSID of the AP |
+ --------------------------------------------------
+ | P2P_OPER | GO | GO's address |
+ --------------------------------------------------
+ | P2P_OPER | P2P_DEVICE | Address of who |
+ | | | would become GO |
+ --------------------------------------------------
+ | WLAN_IBSS | NA | BSSID |
+ --------------------------------------------------
+ | WLAN_MESH | NA | BSSID |
+ --------------------------------------------------
+ */
+ u8 addr[NAN_MAC_ADDR_LEN];
+ /*
+ Mandatory mesh id value if connection type is WLAN_MESH
+ Mesh id contains 0-32 octet identifier and should be
+ as per IEEE Std.802.11-2012 spec.
+ */
+ u16 mesh_id_len;
+ u8 mesh_id[NAN_MAX_MESH_DATA_LEN];
+ /*
+ Optional infrastructure SSID if conn_type is set to
+ NAN_CONN_WLAN_INFRA
+ */
+ u16 infrastructure_ssid_len;
+ u8 infrastructure_ssid_val[NAN_MAX_INFRA_DATA_LEN];
+} NanTransmitPostDiscovery;
+
+/*
+ Discovery engine providing the structure of Post NAN
+ Discovery
+*/
+typedef struct {
+ /* Connection type of the host */
+ NanConnectionType type;
+ /*
+ Device role of the host based on
+ the connection type
+ */
+ NanDeviceRole role;
+ /* Duration of the availability bitmask */
+ NanAvailDuration duration;
+ /* Availability interval bitmap based on duration */
+ u32 avail_interval_bitmap;
+ /*
+ Map Id - 4 bit field which identifies the Further
+ availability map attribute.
+ */
+ u8 mapid;
+ /*
+ Mac address depending on the conn type and device role
+ --------------------------------------------------
+ | Conn Type | Device Role | Mac address Usage |
+ --------------------------------------------------
+ | WLAN_INFRA | AP/STA | BSSID of the AP |
+ --------------------------------------------------
+ | P2P_OPER | GO | GO's address |
+ --------------------------------------------------
+ | P2P_OPER | P2P_DEVICE | Address of who |
+ | | | would become GO |
+ --------------------------------------------------
+ | WLAN_IBSS | NA | BSSID |
+ --------------------------------------------------
+ | WLAN_MESH | NA | BSSID |
+ --------------------------------------------------
+ */
+ u8 addr[NAN_MAC_ADDR_LEN];
+ /*
+ Mandatory mesh id value if connection type is WLAN_MESH
+ Mesh id contains 0-32 octet identifier and should be
+ as per IEEE Std.802.11-2012 spec.
+ */
+ u16 mesh_id_len;
+ u8 mesh_id[NAN_MAX_MESH_DATA_LEN];
+ /*
+ Optional infrastructure SSID if conn_type is set to
+ NAN_CONN_WLAN_INFRA
+ */
+ u16 infrastructure_ssid_len;
+ u8 infrastructure_ssid_val[NAN_MAX_INFRA_DATA_LEN];
+} NanReceivePostDiscovery;
+
+/*
+ NAN device level configuration of SDF and Sync beacons in both
+ 2.4/5GHz bands
+*/
+typedef struct {
+ /* Configure 2.4GHz DW Band */
+ u8 config_2dot4g_dw_band;
+ /*
+ Indicates the interval for Sync beacons and SDF's in 2.4GHz band.
+ Valid values of DW Interval are: 1, 2, 3, 4 and 5, 0 is reserved.
+ The SDF includes in OTA when enabled. The publish/subscribe period
+ values don't override the device level configurations.
+ */
+ u32 dw_2dot4g_interval_val; // default value 1
+ /* Configure 5GHz DW Band */
+ u8 config_5g_dw_band;
+ /*
+ Indicates the interval for Sync beacons and SDF's in 5GHz band
+ Valid values of DW Interval are: 1, 2, 3, 4 and 5, 0 no wake up for
+ any interval. The SDF includes in OTA when enabled. The publish/subscribe
+ period values don't override the device level configurations.
+ */
+ u32 dw_5g_interval_val; // default value 1 when 5G is enabled
+} NanConfigDW;
+
+/*
+ Enable Request Message Structure
+ The NanEnableReq message instructs the Discovery Engine to enter an operational state
+*/
+typedef struct {
+ /* Mandatory parameters below */
+ u8 master_pref; // default value 0x02
+ /*
+ A cluster_low value matching cluster_high indicates a request to join
+ a cluster with that value. If the requested cluster is not found the
+ device will start its own cluster.
+ */
+ u16 cluster_low; // default value 0
+ u16 cluster_high; // default value 0xFFFF
+
+ /*
+ Optional configuration of Enable request.
+ Each of the optional parameters have configure flag which
+ determine whether configuration is to be passed or not.
+ */
+ u8 config_support_5g;
+ u8 support_5g_val; // default value 0; turned off by default
+ /*
+ BIT 0 is used to specify to include Service IDs in Sync/Discovery beacons
+ 0 - Do not include SIDs in any beacons
+ 1 - Include SIDs in all beacons.
+ Rest 7 bits are count field which allows control over the number of SIDs
+ included in the Beacon. 0 means to include as many SIDs that fit into
+ the maximum allow Beacon frame size
+ */
+ u8 config_sid_beacon;
+ u8 sid_beacon_val; // default value 0x01
+ /*
+ The rssi values below should be specified without sign.
+ For eg: -70dBm should be specified as 70.
+ */
+ u8 config_2dot4g_rssi_close;
+ u8 rssi_close_2dot4g_val; // default value -60 dBm
+
+ u8 config_2dot4g_rssi_middle;
+ u8 rssi_middle_2dot4g_val; // default value -70 dBm
+
+ u8 config_2dot4g_rssi_proximity;
+ u8 rssi_proximity_2dot4g_val; // default value -60dBm
+
+ u8 config_hop_count_limit;
+ u8 hop_count_limit_val; // default value 0x02
+
+ /*
+ Defines 2.4G channel access support
+ 0 - No Support
+ 1 - Supported
+ */
+ u8 config_2dot4g_support;
+ u8 support_2dot4g_val; // default value 0x01
+ /*
+ Defines 2.4G channels will be used for sync/discovery beacons
+ 0 - 2.4G channels not used for beacons
+ 1 - 2.4G channels used for beacons
+ */
+ u8 config_2dot4g_beacons;
+ u8 beacon_2dot4g_val; // default value 1
+ /*
+ Defines 2.4G channels will be used for Service Discovery frames
+ 0 - 2.4G channels not used for Service Discovery frames
+ 1 - 2.4G channels used for Service Discovery frames
+ */
+ u8 config_2dot4g_sdf;
+ u8 sdf_2dot4g_val; // default value 1
+ /*
+ Defines 5G channels will be used for sync/discovery beacons
+ 0 - 5G channels not used for beacons
+ 1 - 5G channels used for beacons
+ */
+ u8 config_5g_beacons;
+ u8 beacon_5g_val; // default value 1 when 5G is enabled
+ /*
+ Defines 5G channels will be used for Service Discovery frames
+ 0 - 5G channels not used for Service Discovery frames
+ 1 - 5G channels used for Service Discovery frames
+ */
+ u8 config_5g_sdf;
+ u8 sdf_5g_val; // default value is 0 when 5G is enabled
+ /*
+ 1 byte value which defines the RSSI in
+ dBm for a close by Peer in 5 Ghz channels.
+ The rssi values should be specified without sign.
+ For eg: -70dBm should be specified as 70.
+ */
+ u8 config_5g_rssi_close;
+ u8 rssi_close_5g_val; // default value -60dBm when 5G is enabled
+ /*
+ 1 byte value which defines the RSSI value in
+ dBm for a close by Peer in 5 Ghz channels.
+ The rssi values should be specified without sign.
+ For eg: -70dBm should be specified as 70.
+ */
+ u8 config_5g_rssi_middle;
+ u8 rssi_middle_5g_val; // default value -75dBm when 5G is enabled
+ /*
+ 1 byte value which defines the RSSI filter
+ threshold. Any Service Descriptors received above this
+ value that are configured for RSSI filtering will be dropped.
+ The rssi values should be specified without sign.
+ For eg: -70dBm should be specified as 70.
+ */
+ u8 config_5g_rssi_close_proximity;
+ u8 rssi_close_proximity_5g_val; // default value -60dBm when 5G is enabled
+ /*
+ 1 byte quantity which defines the window size over
+ which the “average RSSI” will be calculated over.
+ */
+ u8 config_rssi_window_size;
+ u8 rssi_window_size_val; // default value 0x08
+ /*
+ The 24 bit Organizationally Unique ID + the 8 bit Network Id.
+ */
+ u8 config_oui;
+ u32 oui_val; // default value {0x51, 0x6F, 0x9A, 0x01, 0x00, 0x00}
+ /*
+ NAN Interface Address, If not configured the Discovery Engine
+ will generate a 6 byte Random MAC.
+ */
+ u8 config_intf_addr;
+ u8 intf_addr_val[NAN_MAC_ADDR_LEN];
+ /*
+ If set to 1, the Discovery Engine will enclose the Cluster
+ Attribute only sent in Beacons in a Vendor Specific Attribute
+ and transmit in a Service Descriptor Frame.
+ */
+ u8 config_cluster_attribute_val;
+ /*
+ The periodicity in seconds between full scan’s to find any new
+ clusters available in the area. A Full scan should not be done
+ more than every 10 seconds and should not be done less than every
+ 30 seconds.
+ */
+ u8 config_scan_params;
+ NanSocialChannelScanParams scan_params_val;
+ /*
+ 1 byte quantity which forces the Random Factor to a particular
+ value for all transmitted Sync/Discovery beacons
+ */
+ u8 config_random_factor_force;
+ u8 random_factor_force_val; // default value off and set to 0x00
+ /*
+ 1 byte quantity which forces the HC for all transmitted Sync and
+ Discovery Beacon NO matter the real HC being received over the
+ air.
+ */
+ u8 config_hop_count_force;
+ u8 hop_count_force_val; // default value 0x00
+
+ /* channel frequency in MHz to enable Nan on */
+ u8 config_24g_channel;
+ wifi_channel channel_24g_val; // default value channel 0x6
+
+ u8 config_5g_channel;
+ wifi_channel channel_5g_val; // default value channel 44 or 149 regulatory
+ // domain
+ /* Configure 2.4/5GHz DW */
+ NanConfigDW config_dw;
+
+ /*
+ By default discovery MAC address randomization is enabled
+ and default interval value is 30 minutes i.e. 1800 seconds.
+ The value 0 is used to disable MAC addr randomization.
+ */
+ u8 config_disc_mac_addr_randomization;
+ u32 disc_mac_addr_rand_interval_sec; // default value 1800 sec
+
+ /*
+ Set/Enable corresponding bits to disable Discovery indications:
+ BIT0 - Disable Discovery MAC Address Event.
+ BIT1 - Disable Started Cluster Event.
+ BIT2 - Disable Joined Cluster Event.
+ */
+ u8 discovery_indication_cfg; // default value 0x0
+ /*
+ BIT 0 is used to specify to include Service IDs in Sync/Discovery beacons
+ 0 - Do not include SIDs in any beacons
+ 1 - Include SIDs in all beacons.
+ Rest 7 bits are count field which allows control over the number of SIDs
+ included in the Beacon. 0 means to include as many SIDs that fit into
+ the maximum allow Beacon frame size
+ */
+ u8 config_subscribe_sid_beacon;
+ u32 subscribe_sid_beacon_val; // default value 0x0
+ /*
+ Discovery Beacon Interval config.
+ Default value is 128 msec in 2G DW and 176 msec in 2G/5G DW.
+ When 0 value is passed it is reset to default value of 128 or 176 msec.
+ */
+ u8 config_discovery_beacon_int;
+ u32 discovery_beacon_interval;
+ /*
+ Enable Number of Spatial Streams.
+ This is NAN Power Optimization feature for NAN discovery.
+ */
+ u8 config_nss;
+ // default value is implementation specific and passing 0 sets it to default
+ u32 nss;
+ /*
+ Enable device level NAN Ranging feature.
+ 0 - Disable
+ 1 - Enable
+ */
+ u8 config_enable_ranging;
+ u32 enable_ranging;
+ /*
+ Enable/Disable DW Early termination.
+ 0 - Disable
+ 1 - Enable
+ */
+ u8 config_dw_early_termination;
+ u32 enable_dw_termination;
+ /*
+ Indicate whether to use NDPE attribute to bring-up TCP/IP connection.
+ If config_ndpe_attr is not configured, the default behavior is
+ not using NDPE attr, and the capability is not advertised.
+ 0 - Not use
+ 1 - Use
+ */
+ u8 config_ndpe_attr;
+ u32 use_ndpe_attr;
+ /*
+ Enable NAN v3.1 instant communication mode.
+ 0 - Disable
+ 1 - Enable
+ */
+ u8 config_enable_instant_mode;
+ u32 enable_instant_mode;
+ /*
+ Config NAN v3.1 instant communication channel frequency selected over NFC/OOB method.
+ If dual band is supported default channel is 149 or 44 as per regulatory domain,
+ else channel 6 (send frequency in MHz).
+ Sometimes depending on country code retrictions, even 149/44 may be restricted
+ in those cases instant channel will be operational only in 2.4GHz.
+ Use wifi_get_usable_channels() API to get supported bands/channels before
+ Instant mode NFC handshake is triggered
+ */
+ u8 config_instant_mode_channel;
+ wifi_channel instant_mode_channel;
+} NanEnableRequest;
+
+/*
+ Publish Msg Structure
+ Message is used to request the DE to publish the Service Name
+ using the parameters passed into the Discovery Window
+*/
+typedef struct {
+ u16 publish_id; /* id 0 means new publish, any other id is existing publish */
+ u16 ttl; /* how many seconds to run for. 0 means forever until canceled */
+ /*
+ period: Awake DW Interval for publish(service)
+ Indicates the interval between two Discovery Windows in which
+ the device supporting the service is awake to transmit or
+ receive the Service Discovery frames.
+ Valid values of Awake DW Interval are: 1, 2, 4, 8 and 16, value 0 will
+ default to 1.
+ */
+ u16 period;
+ NanPublishType publish_type; /* 0= unsolicited, solicited = 1, 2= both */
+ NanTxType tx_type; /* 0 = broadcast, 1= unicast if solicited publish */
+ u8 publish_count; /* number of OTA Publish, 0 means forever until canceled */
+ u16 service_name_len; /* length of service name */
+ u8 service_name[NAN_MAX_SERVICE_NAME_LEN]; /* UTF-8 encoded string identifying the service */
+ /*
+ Field which specifies how the matching indication to host is controlled.
+ 0 - Match and Indicate Once
+ 1 - Match and Indicate continuous
+ 2 - Match and Indicate never. This means don't indicate the match to the host.
+ 3 - Reserved
+ */
+ NanMatchAlg publish_match_indicator;
+
+ /*
+ Sequence of values
+ NAN Device that has invoked a Subscribe method corresponding to this Publish method
+ */
+ u16 service_specific_info_len;
+ u8 service_specific_info[NAN_MAX_SERVICE_SPECIFIC_INFO_LEN];
+
+ /*
+ Ordered sequence of <length, value> pairs which specify further response conditions
+ beyond the service name used to filter subscribe messages to respond to.
+ This is only needed when the PT is set to NAN_SOLICITED or NAN_SOLICITED_UNSOLICITED.
+ */
+ u16 rx_match_filter_len;
+ u8 rx_match_filter[NAN_MAX_MATCH_FILTER_LEN];
+
+ /*
+ Ordered sequence of <length, value> pairs to be included in the Discovery Frame.
+ If present it is always sent in a Discovery Frame
+ */
+ u16 tx_match_filter_len;
+ u8 tx_match_filter[NAN_MAX_MATCH_FILTER_LEN];
+
+ /*
+ flag which specifies that the Publish should use the configured RSSI
+ threshold and the received RSSI in order to filter requests
+ 0 – ignore the configured RSSI threshold when running a Service
+ Descriptor attribute or Service ID List Attribute through the DE matching logic.
+ 1 – use the configured RSSI threshold when running a Service
+ Descriptor attribute or Service ID List Attribute through the DE matching logic.
+
+ */
+ u8 rssi_threshold_flag;
+
+ /*
+ 8-bit bitmap which allows the Host to associate this publish
+ with a particular Post-NAN Connectivity attribute
+ which has been sent down in a NanConfigureRequest/NanEnableRequest
+ message. If the DE fails to find a configured Post-NAN
+ connectivity attributes referenced by the bitmap,
+ the DE will return an error code to the Host.
+ If the Publish is configured to use a Post-NAN Connectivity
+ attribute and the Host does not refresh the Post-NAN Connectivity
+ attribute the Publish will be canceled and the Host will be sent
+ a PublishTerminatedIndication message.
+ */
+ u8 connmap;
+ /*
+ Set/Enable corresponding bits to disable any indications that follow a publish.
+ BIT0 - Disable publish termination indication.
+ BIT1 - Disable match expired indication.
+ BIT2 - Disable followUp indication received (OTA).
+ BIT3 - Disable publishReplied indication.
+ */
+ u8 recv_indication_cfg;
+ /*
+ Nan accept policy for the specific service(publish)
+ */
+ NanServiceAcceptPolicy service_responder_policy;
+ /* NAN Cipher Suite Type */
+ u32 cipher_type;
+ /*
+ Nan Security Key Info is optional in Discovery phase.
+ PMK or passphrase info can be passed during
+ the NDP session.
+ */
+ NanSecurityKeyInfo key_info;
+
+ /* Security Context Identifiers length */
+ u32 scid_len;
+ /*
+ Security Context Identifier attribute contains PMKID
+ shall be included in NDP setup and response messages.
+ Security Context Identifier, Identifies the Security
+ Context. For NAN Shared Key Cipher Suite, this field
+ contains the 16 octet PMKID identifying the PMK used
+ for setting up the Secure Data Path.
+ */
+ u8 scid[NAN_MAX_SCID_BUF_LEN];
+
+ /* NAN configure service discovery extended attributes */
+ NanSdeaCtrlParams sdea_params;
+
+ /* NAN Ranging configuration */
+ NanRangingCfg ranging_cfg;
+
+ /* Enable/disable NAN serivce Ranging auto response mode */
+ NanRangingAutoResponse ranging_auto_response;
+
+ /*
+ When the ranging_auto_response_cfg is not set, NanRangeRequestInd is
+ received. Nan Range Response to Peer MAC Addr is notified to indicate
+ ACCEPT/REJECT/CANCEL to the requestor.
+ */
+ NanRangeResponseCfg range_response_cfg;
+
+ /*
+ Sequence of values indicating the service specific info in SDEA
+ */
+ u16 sdea_service_specific_info_len;
+ u8 sdea_service_specific_info[NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN];
+} NanPublishRequest;
+
+/*
+ Publish Cancel Msg Structure
+ The PublishServiceCancelReq Message is used to request the DE to stop publishing
+ the Service Name identified by the Publish Id in the message.
+*/
+typedef struct {
+ u16 publish_id;
+} NanPublishCancelRequest;
+
+/*
+ NAN Subscribe Structure
+ The SubscribeServiceReq message is sent to the Discovery Engine
+ whenever the Upper layers would like to listen for a Service Name
+*/
+typedef struct {
+ u16 subscribe_id; /* id 0 means new subscribe, non zero is existing subscribe */
+ u16 ttl; /* how many seconds to run for. 0 means forever until canceled */
+ /*
+ period: Awake DW Interval for subscribe(service)
+ Indicates the interval between two Discovery Windows in which
+ the device supporting the service is awake to transmit or
+ receive the Service Discovery frames.
+ Valid values of Awake DW Interval are: 1, 2, 4, 8 and 16, value 0 will
+ default to 1.
+ */
+ u16 period;
+
+ /* Flag which specifies how the Subscribe request shall be processed. */
+ NanSubscribeType subscribe_type; /* 0 - PASSIVE , 1- ACTIVE */
+
+ /* Flag which specifies on Active Subscribes how the Service Response Filter attribute is
+ * populated.*/
+ NanSRFType serviceResponseFilter; /* 0 - Bloom Filter, 1 - MAC Addr */
+
+ /* Flag which specifies how the Service Response Filter Include bit is populated.*/
+ NanSRFIncludeType
+ serviceResponseInclude; /* 0=Do not respond if in the Address Set, 1= Respond */
+
+ /* Flag which specifies if the Service Response Filter should be used when creating
+ * Subscribes.*/
+ NanSRFState useServiceResponseFilter; /* 0=Do not send the Service Response Filter,1= send */
+
+ /*
+ Flag which specifies if the Service Specific Info is needed in
+ the Publish message before creating the MatchIndication
+ */
+ NanSsiInMatchInd ssiRequiredForMatchIndication; /* 0=Not needed, 1= Required */
+
+ /*
+ Field which specifies how the matching indication to host is controlled.
+ 0 - Match and Indicate Once
+ 1 - Match and Indicate continuous
+ 2 - Match and Indicate never. This means don't indicate the match to the host.
+ 3 - Reserved
+ */
+ NanMatchAlg subscribe_match_indicator;
+
+ /*
+ The number of Subscribe Matches which should occur
+ before the Subscribe request is automatically terminated.
+ */
+ u8 subscribe_count; /* If this value is 0 this field is not used by the DE.*/
+
+ u16 service_name_len; /* length of service name */
+ u8 service_name[NAN_MAX_SERVICE_NAME_LEN]; /* UTF-8 encoded string identifying the service */
+
+ /* Sequence of values which further specify the published service beyond the service name*/
+ u16 service_specific_info_len;
+ u8 service_specific_info[NAN_MAX_SERVICE_SPECIFIC_INFO_LEN];
+
+ /*
+ Ordered sequence of <length, value> pairs used to filter out received publish discovery
+ messages. This can be sent both for a Passive or an Active Subscribe
+ */
+ u16 rx_match_filter_len;
+ u8 rx_match_filter[NAN_MAX_MATCH_FILTER_LEN];
+
+ /*
+ Ordered sequence of <length, value> pairs included in the
+ Discovery Frame when an Active Subscribe is used.
+ */
+ u16 tx_match_filter_len;
+ u8 tx_match_filter[NAN_MAX_MATCH_FILTER_LEN];
+
+ /*
+ Flag which specifies that the Subscribe should use the configured RSSI
+ threshold and the received RSSI in order to filter requests
+ 0 – ignore the configured RSSI threshold when running a Service
+ Descriptor attribute or Service ID List Attribute through the DE matching logic.
+ 1 – use the configured RSSI threshold when running a Service
+ Descriptor attribute or Service ID List Attribute through the DE matching logic.
+
+ */
+ u8 rssi_threshold_flag;
+
+ /*
+ 8-bit bitmap which allows the Host to associate this Active
+ Subscribe with a particular Post-NAN Connectivity attribute
+ which has been sent down in a NanConfigureRequest/NanEnableRequest
+ message. If the DE fails to find a configured Post-NAN
+ connectivity attributes referenced by the bitmap,
+ the DE will return an error code to the Host.
+ If the Subscribe is configured to use a Post-NAN Connectivity
+ attribute and the Host does not refresh the Post-NAN Connectivity
+ attribute the Subscribe will be canceled and the Host will be sent
+ a SubscribeTerminatedIndication message.
+ */
+ u8 connmap;
+ /*
+ NAN Interface Address, conforming to the format as described in
+ 8.2.4.3.2 of IEEE Std. 802.11-2012.
+ */
+ u8 num_intf_addr_present;
+ u8 intf_addr[NAN_MAX_SUBSCRIBE_MAX_ADDRESS][NAN_MAC_ADDR_LEN];
+ /*
+ Set/Enable corresponding bits to disable indications that follow a subscribe.
+ BIT0 - Disable subscribe termination indication.
+ BIT1 - Disable match expired indication.
+ BIT2 - Disable followUp indication received (OTA).
+ */
+ u8 recv_indication_cfg;
+
+ /* NAN Cipher Suite Type */
+ u32 cipher_type;
+ /*
+ Nan Security Key Info is optional in Discovery phase.
+ PMK or passphrase info can be passed during
+ the NDP session.
+ */
+ NanSecurityKeyInfo key_info;
+
+ /* Security Context Identifiers length */
+ u32 scid_len;
+ /*
+ Security Context Identifier attribute contains PMKID
+ shall be included in NDP setup and response messages.
+ Security Context Identifier, Identifies the Security
+ Context. For NAN Shared Key Cipher Suite, this field
+ contains the 16 octet PMKID identifying the PMK used
+ for setting up the Secure Data Path.
+ */
+ u8 scid[NAN_MAX_SCID_BUF_LEN];
+
+ /* NAN configure service discovery extended attributes */
+ NanSdeaCtrlParams sdea_params;
+
+ /* NAN Ranging configuration */
+ NanRangingCfg ranging_cfg;
+
+ /* Enable/disable NAN serivce Ranging auto response mode */
+ NanRangingAutoResponse ranging_auto_response;
+
+ /*
+ When the ranging_auto_response_cfg is not set, NanRangeRequestInd is
+ received. Nan Range Response to Peer MAC Addr is notified to indicate
+ ACCEPT/REJECT/CANCEL to the requestor.
+ */
+ NanRangeResponseCfg range_response_cfg;
+
+ /*
+ Sequence of values indicating the service specific info in SDEA
+ */
+ u16 sdea_service_specific_info_len;
+ u8 sdea_service_specific_info[NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN];
+} NanSubscribeRequest;
+
+/*
+ NAN Subscribe Cancel Structure
+ The SubscribeCancelReq Message is used to request the DE to stop looking for the Service Name.
+*/
+typedef struct {
+ u16 subscribe_id;
+} NanSubscribeCancelRequest;
+
+/*
+ Transmit follow up Structure
+ The TransmitFollowupReq message is sent to the DE to allow the sending of the
+ Service_Specific_Info to a particular MAC address.
+*/
+typedef struct {
+ /* Publish or Subscribe Id of an earlier Publish/Subscribe */
+ u16 publish_subscribe_id;
+
+ /*
+ This Id is the Requestor Instance that is passed as
+ part of earlier MatchInd/FollowupInd message.
+ */
+ u32 requestor_instance_id;
+ u8 addr[NAN_MAC_ADDR_LEN]; /* Unicast address */
+ NanTxPriority priority; /* priority of the request 2=high */
+ NanTransmitWindowType dw_or_faw; /* 0= send in a DW, 1=send in FAW */
+
+ /*
+ Sequence of values which further specify the published service beyond
+ the service name.
+ */
+ u16 service_specific_info_len;
+ u8 service_specific_info[NAN_MAX_SERVICE_SPECIFIC_INFO_LEN];
+ /*
+ Set/Enable corresponding bits to disable responses after followUp.
+ BIT0 - Disable followUp response from FW.
+ */
+ u8 recv_indication_cfg;
+
+ /*
+ Sequence of values indicating the service specific info in SDEA
+ */
+ u16 sdea_service_specific_info_len;
+ u8 sdea_service_specific_info[NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN];
+} NanTransmitFollowupRequest;
+
+/*
+ Stats Request structure
+ The Discovery Engine can be queried at runtime by the Host processor for statistics
+ concerning various parts of the Discovery Engine.
+*/
+typedef struct {
+ NanStatsType stats_type; /* NAN Statistics Request Type */
+ u8 clear; /* 0= Do not clear the stats and return the current contents , 1= Clear the associated
+ stats */
+} NanStatsRequest;
+
+/*
+ Config Structure
+ The NanConfigurationReq message is sent by the Host to the
+ Discovery Engine in order to configure the Discovery Engine during runtime.
+*/
+typedef struct {
+ u8 config_sid_beacon;
+ u8 sid_beacon;
+ u8 config_rssi_proximity;
+ u8 rssi_proximity; // default value -60dBm
+ u8 config_master_pref;
+ u8 master_pref; // default value 0x02
+ /*
+ 1 byte value which defines the RSSI filter threshold.
+ Any Service Descriptors received above this value
+ that are configured for RSSI filtering will be dropped.
+ The rssi values should be specified without sign.
+ For eg: -70dBm should be specified as 70.
+ */
+ u8 config_5g_rssi_close_proximity;
+ u8 rssi_close_proximity_5g_val; // default value -60dBm
+ /*
+ Optional configuration of Configure request.
+ Each of the optional parameters have configure flag which
+ determine whether configuration is to be passed or not.
+ */
+ /*
+ 1 byte quantity which defines the window size over
+ which the “average RSSI” will be calculated over.
+ */
+ u8 config_rssi_window_size;
+ u8 rssi_window_size_val; // default value 0x08
+ /*
+ If set to 1, the Discovery Engine will enclose the Cluster
+ Attribute only sent in Beacons in a Vendor Specific Attribute
+ and transmit in a Service Descriptor Frame.
+ */
+ u8 config_cluster_attribute_val;
+ /*
+ The periodicity in seconds between full scan’s to find any new
+ clusters available in the area. A Full scan should not be done
+ more than every 10 seconds and should not be done less than every
+ 30 seconds.
+ */
+ u8 config_scan_params;
+ NanSocialChannelScanParams scan_params_val;
+ /*
+ 1 byte quantity which forces the Random Factor to a particular
+ value for all transmitted Sync/Discovery beacons
+ */
+ u8 config_random_factor_force;
+ u8 random_factor_force_val; // default value 0x00
+ /*
+ 1 byte quantity which forces the HC for all transmitted Sync and
+ Discovery Beacon NO matter the real HC being received over the
+ air.
+ */
+ u8 config_hop_count_force;
+ u8 hop_count_force_val; // default value of 0
+ /* NAN Post Connectivity Capability */
+ u8 config_conn_capability;
+ NanTransmitPostConnectivityCapability conn_capability_val;
+ /* NAN Post Discover Capability */
+ u8 num_config_discovery_attr;
+ NanTransmitPostDiscovery discovery_attr_val[NAN_MAX_POSTDISCOVERY_LEN];
+ /* NAN Further availability Map */
+ u8 config_fam;
+ NanFurtherAvailabilityMap fam_val;
+ /* Configure 2.4/5GHz DW */
+ NanConfigDW config_dw;
+ /*
+ By default discovery MAC address randomization is enabled
+ and default interval value is 30 minutes i.e. 1800 seconds.
+ The value 0 is used to disable MAC addr randomization.
+ */
+ u8 config_disc_mac_addr_randomization;
+ u32 disc_mac_addr_rand_interval_sec; // default value of 30 minutes
+
+ /*
+ Set/Enable corresponding bits to disable Discovery indications:
+ BIT0 - Disable Discovery MAC Address Event.
+ BIT1 - Disable Started Cluster Event.
+ BIT2 - Disable Joined Cluster Event.
+ */
+ u8 discovery_indication_cfg; // default value of 0
+ /*
+ BIT 0 is used to specify to include Service IDs in Sync/Discovery beacons
+ 0 - Do not include SIDs in any beacons
+ 1 - Include SIDs in all beacons.
+ Rest 7 bits are count field which allows control over the number of SIDs
+ included in the Beacon. 0 means to include as many SIDs that fit into
+ the maximum allow Beacon frame size
+ */
+ u8 config_subscribe_sid_beacon;
+ u32 subscribe_sid_beacon_val; // default value 0x0
+ /*
+ Discovery Beacon Interval config.
+ Default value is 128 msec in 2G DW and 176 msec in 2G/5G DW.
+ When 0 value is passed it is reset to default value of 128 or 176 msec.
+ */
+ u8 config_discovery_beacon_int;
+ u32 discovery_beacon_interval;
+ /*
+ Enable Number of Spatial Streams.
+ This is NAN Power Optimization feature for NAN discovery.
+ */
+ u8 config_nss;
+ // default value is implementation specific and passing 0 sets it to default
+ u32 nss;
+ /*
+ Enable device level NAN Ranging feature.
+ 0 - Disable
+ 1 - Enable
+ */
+ u8 config_enable_ranging;
+ u32 enable_ranging;
+ /*
+ Enable/Disable DW Early termination.
+ 0 - Disable
+ 1 - Enable
+ */
+ u8 config_dw_early_termination;
+ u32 enable_dw_termination;
+ /*
+ Indicate whether to use NDPE attribute to bring-up TCP/IP connection
+ If config_ndpe_attr is not configured, the default behavior is
+ not using NDPE attr, and the capability is not advertised.
+ 0 - Not use
+ 1 - Use
+ */
+ u8 config_ndpe_attr;
+ u32 use_ndpe_attr;
+ /*
+ Enable NAN v3.1 instant communication mode.
+ 0 - Disable
+ 1 - Enable
+ */
+ u8 config_enable_instant_mode;
+ u32 enable_instant_mode;
+ /*
+ Config NAN v3.1 instant communication channel selected over NFC/OOB method.
+ If dual band is supported default channel is 149 or 44 as per regulatory domain,
+ else channel 6 (send frequency in MHz).
+ Sometimes depending on country code retrictions, even 149/44 may be restricted
+ in those cases instant channel will be operational only in 2.4GHz.
+ Use wifi_get_usable_channels() API to get supported bands/channels before
+ Instant mode NFC handshake is triggered
+ */
+ u8 config_instant_mode_channel;
+ wifi_channel instant_mode_channel;
+} NanConfigRequest;
+
+/*
+ TCA Structure
+ The Discovery Engine can be configured to send up Events whenever a configured
+ Threshold Crossing Alert (TCA) Type crosses an integral threshold in a particular direction.
+*/
+typedef struct {
+ NanTcaType tca_type; /* Nan Protocol Threshold Crossing Alert (TCA) Codes */
+
+ /* flag which control whether or not an event is generated for the Rising direction */
+ u8 rising_direction_evt_flag; /* 0 - no event, 1 - event */
+
+ /* flag which control whether or not an event is generated for the Falling direction */
+ u8 falling_direction_evt_flag; /* 0 - no event, 1 - event */
+
+ /* flag which requests a previous TCA request to be cleared from the DE */
+ u8 clear; /*0= Do not clear the TCA, 1=Clear the TCA */
+
+ /* 32 bit value which represents the threshold to be used.*/
+ u32 threshold;
+} NanTCARequest;
+
+/*
+ Beacon Sdf Payload Structure
+ The Discovery Engine can be configured to publish vendor specific attributes as part of
+ beacon or service discovery frame transmitted as part of this request..
+*/
+typedef struct {
+ /*
+ NanVendorAttribute will have the Vendor Specific Attribute which the
+ vendor wants to publish as part of Discovery or Sync or Service discovery frame
+ */
+ NanTransmitVendorSpecificAttribute vsa;
+} NanBeaconSdfPayloadRequest;
+
+/* Publish statistics. */
+typedef struct {
+ u32 validPublishServiceReqMsgs;
+ u32 validPublishServiceRspMsgs;
+ u32 validPublishServiceCancelReqMsgs;
+ u32 validPublishServiceCancelRspMsgs;
+ u32 validPublishRepliedIndMsgs;
+ u32 validPublishTerminatedIndMsgs;
+ u32 validActiveSubscribes;
+ u32 validMatches;
+ u32 validFollowups;
+ u32 invalidPublishServiceReqMsgs;
+ u32 invalidPublishServiceCancelReqMsgs;
+ u32 invalidActiveSubscribes;
+ u32 invalidMatches;
+ u32 invalidFollowups;
+ u32 publishCount;
+ u32 publishNewMatchCount;
+ u32 pubsubGlobalNewMatchCount;
+} NanPublishStats;
+
+/* Subscribe statistics. */
+typedef struct {
+ u32 validSubscribeServiceReqMsgs;
+ u32 validSubscribeServiceRspMsgs;
+ u32 validSubscribeServiceCancelReqMsgs;
+ u32 validSubscribeServiceCancelRspMsgs;
+ u32 validSubscribeTerminatedIndMsgs;
+ u32 validSubscribeMatchIndMsgs;
+ u32 validSubscribeUnmatchIndMsgs;
+ u32 validSolicitedPublishes;
+ u32 validMatches;
+ u32 validFollowups;
+ u32 invalidSubscribeServiceReqMsgs;
+ u32 invalidSubscribeServiceCancelReqMsgs;
+ u32 invalidSubscribeFollowupReqMsgs;
+ u32 invalidSolicitedPublishes;
+ u32 invalidMatches;
+ u32 invalidFollowups;
+ u32 subscribeCount;
+ u32 bloomFilterIndex;
+ u32 subscribeNewMatchCount;
+ u32 pubsubGlobalNewMatchCount;
+} NanSubscribeStats;
+
+/* NAN DW Statistics*/
+typedef struct {
+ /* RX stats */
+ u32 validFrames;
+ u32 validActionFrames;
+ u32 validBeaconFrames;
+ u32 ignoredActionFrames;
+ u32 ignoredBeaconFrames;
+ u32 invalidFrames;
+ u32 invalidActionFrames;
+ u32 invalidBeaconFrames;
+ u32 invalidMacHeaders;
+ u32 invalidPafHeaders;
+ u32 nonNanBeaconFrames;
+
+ u32 earlyActionFrames;
+ u32 inDwActionFrames;
+ u32 lateActionFrames;
+
+ /* TX stats */
+ u32 framesQueued;
+ u32 totalTRSpUpdates;
+ u32 completeByTRSp;
+ u32 completeByTp75DW;
+ u32 completeByTendDW;
+ u32 lateActionFramesTx;
+} NanDWStats;
+
+/* NAN MAC Statistics. */
+typedef struct {
+ /* RX stats */
+ u32 validFrames;
+ u32 validActionFrames;
+ u32 validBeaconFrames;
+ u32 ignoredActionFrames;
+ u32 ignoredBeaconFrames;
+ u32 invalidFrames;
+ u32 invalidActionFrames;
+ u32 invalidBeaconFrames;
+ u32 invalidMacHeaders;
+ u32 invalidPafHeaders;
+ u32 nonNanBeaconFrames;
+
+ u32 earlyActionFrames;
+ u32 inDwActionFrames;
+ u32 lateActionFrames;
+
+ /* TX stats */
+ u32 framesQueued;
+ u32 totalTRSpUpdates;
+ u32 completeByTRSp;
+ u32 completeByTp75DW;
+ u32 completeByTendDW;
+ u32 lateActionFramesTx;
+
+ u32 twIncreases;
+ u32 twDecreases;
+ u32 twChanges;
+ u32 twHighwater;
+ u32 bloomFilterIndex;
+} NanMacStats;
+
+/* NAN Sync Statistics*/
+typedef struct {
+ u64 currTsf;
+ u64 myRank;
+ u64 currAmRank;
+ u64 lastAmRank;
+ u32 currAmBTT;
+ u32 lastAmBTT;
+ u8 currAmHopCount;
+ u8 currRole;
+ u16 currClusterId;
+
+ u64 timeSpentInCurrRole;
+ u64 totalTimeSpentAsMaster;
+ u64 totalTimeSpentAsNonMasterSync;
+ u64 totalTimeSpentAsNonMasterNonSync;
+ u32 transitionsToAnchorMaster;
+ u32 transitionsToMaster;
+ u32 transitionsToNonMasterSync;
+ u32 transitionsToNonMasterNonSync;
+ u32 amrUpdateCount;
+ u32 amrUpdateRankChangedCount;
+ u32 amrUpdateBTTChangedCount;
+ u32 amrUpdateHcChangedCount;
+ u32 amrUpdateNewDeviceCount;
+ u32 amrExpireCount;
+ u32 mergeCount;
+ u32 beaconsAboveHcLimit;
+ u32 beaconsBelowRssiThresh;
+ u32 beaconsIgnoredNoSpace;
+ u32 beaconsForOurCluster;
+ u32 beaconsForOtherCluster;
+ u32 beaconCancelRequests;
+ u32 beaconCancelFailures;
+ u32 beaconUpdateRequests;
+ u32 beaconUpdateFailures;
+ u32 syncBeaconTxAttempts;
+ u32 syncBeaconTxFailures;
+ u32 discBeaconTxAttempts;
+ u32 discBeaconTxFailures;
+ u32 amHopCountExpireCount;
+ u32 ndpChannelFreq;
+ u32 ndpChannelFreq2;
+ u32 schedUpdateChannelFreq;
+} NanSyncStats;
+
+/* NAN Misc DE Statistics */
+typedef struct {
+ u32 validErrorRspMsgs;
+ u32 validTransmitFollowupReqMsgs;
+ u32 validTransmitFollowupRspMsgs;
+ u32 validFollowupIndMsgs;
+ u32 validConfigurationReqMsgs;
+ u32 validConfigurationRspMsgs;
+ u32 validStatsReqMsgs;
+ u32 validStatsRspMsgs;
+ u32 validEnableReqMsgs;
+ u32 validEnableRspMsgs;
+ u32 validDisableReqMsgs;
+ u32 validDisableRspMsgs;
+ u32 validDisableIndMsgs;
+ u32 validEventIndMsgs;
+ u32 validTcaReqMsgs;
+ u32 validTcaRspMsgs;
+ u32 validTcaIndMsgs;
+ u32 invalidTransmitFollowupReqMsgs;
+ u32 invalidConfigurationReqMsgs;
+ u32 invalidStatsReqMsgs;
+ u32 invalidEnableReqMsgs;
+ u32 invalidDisableReqMsgs;
+ u32 invalidTcaReqMsgs;
+} NanDeStats;
+
+/* Publish Response Message structure */
+typedef struct {
+ u16 publish_id;
+} NanPublishResponse;
+
+/* Subscribe Response Message structure */
+typedef struct {
+ u16 subscribe_id;
+} NanSubscribeResponse;
+
+/*
+ Stats Response Message structure
+ The Discovery Engine response to a request by the Host for statistics.
+*/
+typedef struct {
+ NanStatsType stats_type;
+ union {
+ NanPublishStats publish_stats;
+ NanSubscribeStats subscribe_stats;
+ NanMacStats mac_stats;
+ NanSyncStats sync_stats;
+ NanDeStats de_stats;
+ NanDWStats dw_stats;
+ } data;
+} NanStatsResponse;
+
+/* Response returned for Initiators Data request */
+typedef struct {
+ /*
+ Unique token Id generated on the initiator
+ side used for a NDP session between two NAN devices
+ */
+ NanDataPathId ndp_instance_id;
+} NanDataPathRequestResponse;
+
+/*
+ NAN Response messages
+*/
+typedef struct {
+ NanStatusType status; /* contains the result code */
+ char nan_error[NAN_ERROR_STR_LEN]; /* Describe the NAN error type */
+ NanResponseType response_type; /* NanResponseType Definitions */
+ union {
+ NanPublishResponse publish_response;
+ NanSubscribeResponse subscribe_response;
+ NanStatsResponse stats_response;
+ NanDataPathRequestResponse data_request_response;
+ NanCapabilities nan_capabilities;
+ } body;
+} NanResponseMsg;
+
+/*
+ Publish Replied Indication
+ The PublishRepliedInd Message is sent by the DE when an Active Subscribe is
+ received over the air and it matches a Solicited PublishServiceReq which had
+ been created with the replied_event_flag set.
+*/
+typedef struct {
+ /*
+ A 32 bit Requestor Instance Id which is sent to the Application.
+ This Id will be sent in any subsequent UnmatchInd/FollowupInd
+ messages
+ */
+ u32 requestor_instance_id;
+ u8 addr[NAN_MAC_ADDR_LEN];
+ /*
+ If RSSI filtering was configured in NanPublishRequest then this
+ field will contain the received RSSI value. 0 if not
+ */
+ u8 rssi_value;
+} NanPublishRepliedInd;
+
+/*
+ Publish Terminated
+ The PublishTerminatedInd message is sent by the DE whenever a Publish
+ terminates from a user-specified timeout or a unrecoverable error in the DE.
+*/
+typedef struct {
+ /* Id returned during the initial Publish */
+ u16 publish_id;
+ /*
+ For all user configured termination NAN_STATUS_SUCCESS
+ and no other reasons expected from firmware.
+ */
+ NanStatusType reason;
+ char nan_reason[NAN_ERROR_STR_LEN]; /* Describe the NAN reason type */
+} NanPublishTerminatedInd;
+
+/*
+ Match Indication
+ The MatchInd message is sent once per responding MAC address whenever
+ the Discovery Engine detects a match for a previous SubscribeServiceReq
+ or PublishServiceReq.
+*/
+typedef struct {
+ /* Publish or Subscribe Id of an earlier Publish/Subscribe */
+ u16 publish_subscribe_id;
+ /*
+ A 32 bit Requestor Instance Id which is sent to the Application.
+ This Id will be sent in any subsequent UnmatchInd/FollowupInd
+ messages
+ */
+ u32 requestor_instance_id;
+ u8 addr[NAN_MAC_ADDR_LEN];
+
+ /*
+ Sequence of octets which were received in a Discovery Frame matching the
+ Subscribe Request.
+ */
+ u16 service_specific_info_len;
+ u8 service_specific_info[NAN_MAX_SERVICE_SPECIFIC_INFO_LEN];
+
+ /*
+ Ordered sequence of <length, value> pairs received in the Discovery Frame
+ matching the Subscribe Request.
+ */
+ u16 sdf_match_filter_len;
+ u8 sdf_match_filter[NAN_MAX_MATCH_FILTER_LEN];
+
+ /*
+ flag to indicate if the Match occurred in a Beacon Frame or in a
+ Service Discovery Frame.
+ 0 - Match occured in a Service Discovery Frame
+ 1 - Match occured in a Beacon Frame
+ */
+ u8 match_occured_flag;
+
+ /*
+ flag to indicate FW is out of resource and that it can no longer
+ track this Service Name. The Host still need to send the received
+ Match_Handle but duplicate MatchInd messages may be received on
+ this Handle until the resource frees up.
+ 0 - FW is caching this match
+ 1 - FW is unable to cache this match
+ */
+ u8 out_of_resource_flag;
+
+ /*
+ If RSSI filtering was configured in NanSubscribeRequest then this
+ field will contain the received RSSI value. 0 if not.
+ All rssi values should be specified without sign.
+ For eg: -70dBm should be specified as 70.
+ */
+ u8 rssi_value;
+
+ /*
+ optional attributes. Each optional attribute is associated with a flag
+ which specifies whether the attribute is valid or not
+ */
+ /* NAN Post Connectivity Capability received */
+ u8 is_conn_capability_valid;
+ NanReceivePostConnectivityCapability conn_capability;
+
+ /* NAN Post Discover Capability */
+ u8 num_rx_discovery_attr;
+ NanReceivePostDiscovery discovery_attr[NAN_MAX_POSTDISCOVERY_LEN];
+
+ /* NAN Further availability Map */
+ u8 num_chans;
+ NanFurtherAvailabilityChannel famchan[NAN_MAX_FAM_CHANNELS];
+
+ /* NAN Cluster Attribute */
+ u8 cluster_attribute_len;
+ u8 cluster_attribute[NAN_MAX_CLUSTER_ATTRIBUTE_LEN];
+
+ /* NAN Cipher Suite */
+ u32 peer_cipher_type;
+
+ /* Security Context Identifiers length */
+ u32 scid_len;
+ /*
+ Security Context Identifier attribute contains PMKID
+ shall be included in NDP setup and response messages.
+ Security Context Identifier, Identifies the Security
+ Context. For NAN Shared Key Cipher Suite, this field
+ contains the 16 octet PMKID identifying the PMK used
+ for setting up the Secure Data Path.
+ */
+ u8 scid[NAN_MAX_SCID_BUF_LEN];
+
+ /* Peer service discovery extended attributes */
+ NanSdeaCtrlParams peer_sdea_params;
+
+ /*
+ Ranging indication and NanMatchAlg are not tied.
+ Ex: NanMatchAlg can indicate Match_ONCE, but ranging
+ indications can be continuous. All ranging indications
+ depend on SDEA control parameters of ranging required for
+ continuous, and ingress/egress values in the ranging config.
+ Ranging indication data is notified if:
+ 1) Ranging required is enabled in SDEA.
+ range info notified continuous.
+ 2) if range_limit ingress/egress MASKS are enabled
+ notify once for ingress >= ingress_distance
+ and egress <= egress_distance, same for ingress_egress_both
+ 3) if the Awake DW intervals are higher than the ranging intervals,
+ priority is given to the device DW intervalsi.
+ */
+ /*
+ Range Info includes:
+ 1) distance to the NAN device with the MAC address indicated
+ with ranged mac address.
+ 2) Ranging event matching the configuration of continuous/ingress/egress.
+ */
+ NanRangeInfo range_info;
+
+ /*
+ Sequence of values indicating the service specific info in SDEA
+ */
+ u16 sdea_service_specific_info_len;
+ u8 sdea_service_specific_info[NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN];
+} NanMatchInd;
+
+/*
+ MatchExpired Indication
+ The MatchExpiredInd message is sent whenever the Discovery Engine detects that
+ a previously Matched Service has been gone for too long. If the previous
+ MatchInd message for this Publish/Subscribe Id had the out_of_resource_flag
+ set then this message will not be received
+*/
+typedef struct {
+ /* Publish or Subscribe Id of an earlier Publish/Subscribe */
+ u16 publish_subscribe_id;
+ /*
+ 32 bit value sent by the DE in a previous
+ MatchInd/FollowupInd to the application.
+ */
+ u32 requestor_instance_id;
+} NanMatchExpiredInd;
+
+/*
+ Subscribe Terminated
+ The SubscribeTerminatedInd message is sent by the DE whenever a
+ Subscribe terminates from a user-specified timeout or a unrecoverable error in the DE.
+*/
+typedef struct {
+ /* Id returned during initial Subscribe */
+ u16 subscribe_id;
+ /*
+ For all user configured termination NAN_STATUS_SUCCESS
+ and no other reasons expected from firmware.
+ */
+ NanStatusType reason;
+ char nan_reason[NAN_ERROR_STR_LEN]; /* Describe the NAN reason type */
+} NanSubscribeTerminatedInd;
+
+/*
+ Followup Indication Message
+ The FollowupInd message is sent by the DE to the Host whenever it receives a
+ Followup message from another peer.
+*/
+typedef struct {
+ /* Publish or Subscribe Id of an earlier Publish/Subscribe */
+ u16 publish_subscribe_id;
+ /*
+ A 32 bit Requestor instance Id which is sent to the Application.
+ This Id will be used in subsequent UnmatchInd/FollowupInd messages.
+ */
+ u32 requestor_instance_id;
+ u8 addr[NAN_MAC_ADDR_LEN];
+
+ /* Flag which the DE uses to decide if received in a DW or a FAW*/
+ u8 dw_or_faw; /* 0=Received in a DW, 1 = Received in a FAW*/
+
+ /*
+ Sequence of values which further specify the published service beyond
+ the service name
+ */
+ u16 service_specific_info_len;
+ u8 service_specific_info[NAN_MAX_SERVICE_SPECIFIC_INFO_LEN];
+
+ /*
+ Sequence of values indicating the service specific info in SDEA
+ */
+ u16 sdea_service_specific_info_len;
+ u8 sdea_service_specific_info[NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN];
+} NanFollowupInd;
+
+/*
+ Event data notifying the Mac address of the Discovery engine.
+ which is reported as one of the Discovery engine event
+*/
+typedef struct {
+ u8 addr[NAN_MAC_ADDR_LEN];
+} NanMacAddressEvent;
+
+/*
+ Event data notifying the Cluster address of the cluster
+ which is reported as one of the Discovery engine event
+*/
+typedef struct {
+ u8 addr[NAN_MAC_ADDR_LEN];
+} NanClusterEvent;
+
+/*
+ Discovery Engine Event Indication
+ The Discovery Engine can inform the Host when significant events occur
+ The data following the EventId is dependent upon the EventId type.
+ In other words, each new event defined will carry a different
+ structure of information back to the host.
+*/
+typedef struct {
+ NanDiscEngEventType event_type; /* NAN Protocol Event Codes */
+ union {
+ /*
+ MacAddressEvent which will have 6 byte mac address
+ of the Discovery engine.
+ */
+ NanMacAddressEvent mac_addr;
+ /*
+ Cluster Event Data which will be obtained when the
+ device starts a new cluster or joins a cluster.
+ The event data will have 6 byte octet string of the
+ cluster started or joined.
+ */
+ NanClusterEvent cluster;
+ } data;
+} NanDiscEngEventInd;
+
+/* Cluster size TCA event*/
+typedef struct {
+ /* size of the cluster*/
+ u32 cluster_size;
+} NanTcaClusterEvent;
+
+/*
+ NAN TCA Indication
+ The Discovery Engine can inform the Host when significant events occur.
+ The data following the TcaId is dependent upon the TcaId type.
+ In other words, each new event defined will carry a different structure
+ of information back to the host.
+*/
+typedef struct {
+ NanTcaType tca_type;
+ /* flag which defines if the configured Threshold has risen above the threshold */
+ u8 rising_direction_evt_flag; /* 0 - no event, 1 - event */
+
+ /* flag which defines if the configured Threshold has fallen below the threshold */
+ u8 falling_direction_evt_flag; /* 0 - no event, 1 - event */
+ union {
+ /*
+ This event in obtained when the cluser size threshold
+ is crossed. Event will have the cluster size
+ */
+ NanTcaClusterEvent cluster;
+ } data;
+} NanTCAInd;
+
+/*
+ NAN Disabled Indication
+ The NanDisableInd message indicates to the upper layers that the Discovery
+ Engine has flushed all state and has been shutdown. When this message is received
+ the DE is guaranteed to have left the NAN cluster it was part of and will have terminated
+ any in progress Publishes or Subscribes.
+*/
+typedef struct {
+ /*
+ Following reasons expected:
+ NAN_STATUS_SUCCESS
+ NAN_STATUS_UNSUPPORTED_CONCURRENCY_NAN_DISABLED
+ */
+ NanStatusType reason;
+ char nan_reason[NAN_ERROR_STR_LEN]; /* Describe the NAN reason type */
+} NanDisabledInd;
+
+/*
+ NAN Beacon or SDF Payload Indication
+ The NanBeaconSdfPayloadInd message indicates to the upper layers that information
+ elements were received either in a Beacon or SDF which needs to be delivered
+ outside of a Publish/Subscribe Handle.
+*/
+typedef struct {
+ /* The MAC address of the peer which sent the attributes.*/
+ u8 addr[NAN_MAC_ADDR_LEN];
+ /*
+ Optional attributes. Each optional attribute is associated with a flag
+ which specifies whether the attribute is valid or not
+ */
+ /* NAN Receive Vendor Specific Attribute*/
+ u8 is_vsa_received;
+ NanReceiveVendorSpecificAttribute vsa;
+
+ /* NAN Beacon or SDF Payload Received*/
+ u8 is_beacon_sdf_payload_received;
+ NanBeaconSdfPayloadReceive data;
+} NanBeaconSdfPayloadInd;
+
+/*
+ Event Indication notifying the
+ transmit followup in progress
+*/
+typedef struct {
+ transaction_id id;
+ /*
+ Following reason codes returned:
+ NAN_STATUS_SUCCESS
+ NAN_STATUS_NO_OTA_ACK
+ NAN_STATUS_PROTOCOL_FAILURE
+ */
+ NanStatusType reason;
+ char nan_reason[NAN_ERROR_STR_LEN]; /* Describe the NAN reason type */
+} NanTransmitFollowupInd;
+
+/*
+ Data request Initiator/Responder
+ app/service related info
+*/
+typedef struct {
+ u16 ndp_app_info_len;
+ u8 ndp_app_info[NAN_DP_MAX_APP_INFO_LEN];
+} NanDataPathAppInfo;
+
+/* QoS configuration */
+typedef enum { NAN_DP_CONFIG_NO_QOS = 0, NAN_DP_CONFIG_QOS } NanDataPathQosCfg;
+
+/* Configuration params of Data request Initiator/Responder */
+typedef struct {
+ /* Status Indicating Security/No Security */
+ NanDataPathSecurityCfgStatus security_cfg;
+ NanDataPathQosCfg qos_cfg;
+} NanDataPathCfg;
+
+/* Nan Data Path Initiator requesting a data session */
+typedef struct {
+ /*
+ Unique Instance Id identifying the Responder's service.
+ This is same as publish_id notified on the subscribe side
+ in a publish/subscribe scenario
+ */
+ u32 requestor_instance_id; /* Value 0 for no publish/subscribe */
+
+ /* Config flag for channel request */
+ NanDataPathChannelCfg channel_request_type;
+ /* Channel frequency in MHz to start data-path */
+ wifi_channel channel;
+ /*
+ Discovery MAC addr of the publisher/peer
+ */
+ u8 peer_disc_mac_addr[NAN_MAC_ADDR_LEN];
+ /*
+ Interface name on which this NDP session is to be started.
+ This will be the same interface name provided during interface
+ create.
+ */
+ char ndp_iface[IFNAMSIZ + 1];
+ /* Initiator/Responder Security/QoS configuration */
+ NanDataPathCfg ndp_cfg;
+ /* App/Service information of the Initiator */
+ NanDataPathAppInfo app_info;
+ /* NAN Cipher Suite Type */
+ u32 cipher_type;
+ /*
+ Nan Security Key Info is optional in Discovery phase.
+ PMK or passphrase info can be passed during
+ the NDP session.
+ */
+ NanSecurityKeyInfo key_info;
+ /* length of service name */
+ u32 service_name_len;
+ /*
+ UTF-8 encoded string identifying the service name.
+ The service name field is only used if a Nan discovery
+ is not associated with the NDP (out-of-band discovery).
+ */
+ u8 service_name[NAN_MAX_SERVICE_NAME_LEN];
+
+ /* Security Context Identifiers length */
+ u32 scid_len;
+ /*
+ Security Context Identifier attribute contains PMKID
+ shall be included in NDP setup and response messages.
+ Security Context Identifier, Identifies the Security
+ Context. For NAN Shared Key Cipher Suite, this field
+ contains the 16 octet PMKID identifying the PMK used
+ for setting up the Secure Data Path.
+ */
+ u8 scid[NAN_MAX_SCID_BUF_LEN];
+} NanDataPathInitiatorRequest;
+
+/*
+ Data struct to initiate a data response on the responder side
+ for an indication received with a data request
+*/
+typedef struct {
+ /*
+ Unique token Id generated on the initiator/responder
+ side used for a NDP session between two NAN devices
+ */
+ NanDataPathId ndp_instance_id;
+ /*
+ Interface name on which this NDP session is to be started.
+ This will be the same interface name provided during interface
+ create.
+ */
+ char ndp_iface[IFNAMSIZ + 1];
+ /* Initiator/Responder Security/QoS configuration */
+ NanDataPathCfg ndp_cfg;
+ /* App/Service information of the responder */
+ NanDataPathAppInfo app_info;
+ /* Response Code indicating ACCEPT/REJECT/DEFER */
+ NanDataPathResponseCode rsp_code;
+ /* NAN Cipher Suite Type */
+ u32 cipher_type;
+ /*
+ Nan Security Key Info is optional in Discovery phase.
+ PMK or passphrase info can be passed during
+ the NDP session.
+ */
+ NanSecurityKeyInfo key_info;
+ /* length of service name */
+ u32 service_name_len;
+ /*
+ UTF-8 encoded string identifying the service name.
+ The service name field is only used if a Nan discovery
+ is not associated with the NDP (out-of-band discovery).
+ */
+ u8 service_name[NAN_MAX_SERVICE_NAME_LEN];
+
+ /* Security Context Identifiers length */
+ u32 scid_len;
+ /*
+ Security Context Identifier attribute contains PMKID
+ shall be included in NDP setup and response messages.
+ Security Context Identifier, Identifies the Security
+ Context. For NAN Shared Key Cipher Suite, this field
+ contains the 16 octet PMKID identifying the PMK used
+ for setting up the Secure Data Path.
+ */
+ u8 scid[NAN_MAX_SCID_BUF_LEN];
+} NanDataPathIndicationResponse;
+
+/* NDP termination info */
+typedef struct {
+ u8 num_ndp_instances;
+ /*
+ Unique token Id generated on the initiator/responder side
+ used for a NDP session between two NAN devices
+ */
+ NanDataPathId ndp_instance_id[];
+} NanDataPathEndRequest;
+
+/*
+ Event indication received on the
+ responder side when a Nan Data request or
+ NDP session is initiated on the Initiator side
+*/
+typedef struct {
+ /*
+ Unique Instance Id corresponding to a service/session.
+ This is similar to the publish_id generated on the
+ publisher side
+ */
+ u16 service_instance_id;
+ /* Discovery MAC addr of the peer/initiator */
+ u8 peer_disc_mac_addr[NAN_MAC_ADDR_LEN];
+ /*
+ Unique token Id generated on the initiator/responder side
+ used for a NDP session between two NAN devices
+ */
+ NanDataPathId ndp_instance_id;
+ /* Initiator/Responder Security/QoS configuration */
+ NanDataPathCfg ndp_cfg;
+ /* App/Service information of the initiator */
+ NanDataPathAppInfo app_info;
+
+ /* Security Context Identifiers length */
+ u32 scid_len;
+ /*
+ Security Context Identifier attribute contains PMKID
+ shall be included in NDP setup and response messages.
+ Security Context Identifier, Identifies the Security
+ Context. For NAN Shared Key Cipher Suite, this field
+ contains the 16 octet PMKID identifying the PMK used
+ for setting up the Secure Data Path.
+ */
+ u8 scid[NAN_MAX_SCID_BUF_LEN];
+} NanDataPathRequestInd;
+
+/*
+ Event indication of data confirm is received on both
+ initiator and responder side confirming a NDP session
+*/
+typedef struct {
+ /*
+ Unique token Id generated on the initiator/responder side
+ used for a NDP session between two NAN devices
+ */
+ NanDataPathId ndp_instance_id;
+ /*
+ NDI mac address of the peer
+ (required to derive target ipv6 address)
+ */
+ u8 peer_ndi_mac_addr[NAN_MAC_ADDR_LEN];
+ /* App/Service information of Initiator/Responder */
+ NanDataPathAppInfo app_info;
+ /* Response code indicating ACCEPT/REJECT/DEFER */
+ NanDataPathResponseCode rsp_code;
+ /*
+ Reason code indicating the cause for REJECT.
+ NAN_STATUS_SUCCESS and NAN_STATUS_PROTOCOL_FAILURE are
+ expected reason codes.
+ */
+ NanStatusType reason_code;
+ /* Number of channels for which info is indicated */
+ u32 num_channels;
+ /*
+ Data indicating the Channel list and BW of the channel.
+ */
+ NanChannelInfo channel_info[NAN_MAX_CHANNEL_INFO_SUPPORTED];
+} NanDataPathConfirmInd;
+
+/*
+ Event indication of schedule update is received on both
+ initiator and responder when a schedule change occurs
+*/
+typedef struct {
+ /*
+ NMI mac address
+ */
+ u8 peer_mac_addr[NAN_MAC_ADDR_LEN];
+ /*
+ Reason code indicating the cause of schedule update.
+ BIT_0 NSS Update
+ BIT_1 Channel list update
+ */
+ u32 schedule_update_reason_code;
+ /* Number of channels for which info is indicated */
+ u32 num_channels;
+ /*
+ Data indicating the Channel list and BW of the channel.
+ */
+ NanChannelInfo channel_info[NAN_MAX_CHANNEL_INFO_SUPPORTED];
+ /* Number of NDP instance Ids */
+ u8 num_ndp_instances;
+ /*
+ Unique token Id generated on the initiator/responder side
+ used for a NDP session between two NAN devices
+ */
+ NanDataPathId ndp_instance_id[];
+} NanDataPathScheduleUpdateInd;
+
+/*
+ Event indication received on the
+ initiator/responder side terminating
+ a NDP session
+*/
+typedef struct {
+ u8 num_ndp_instances;
+ /*
+ Unique token Id generated on the initiator/responder side
+ used for a NDP session between two NAN devices
+ */
+ NanDataPathId ndp_instance_id[];
+} NanDataPathEndInd;
+
+/*
+ Event indicating Range Request received on the
+ Published side.
+*/
+typedef struct {
+ u16 publish_id; /* id is existing publish */
+ /* Range Requestor's MAC address */
+ u8 range_req_intf_addr[NAN_MAC_ADDR_LEN];
+} NanRangeRequestInd;
+
+/*
+ Event indicating Range report on the
+ Published side.
+*/
+typedef struct {
+ u16 publish_id; /* id is existing publish */
+ /* Range Requestor's MAC address */
+ u8 range_req_intf_addr[NAN_MAC_ADDR_LEN];
+ /*
+ Distance to the NAN device with the MAC address indicated
+ with ranged mac address.
+ */
+ u32 range_measurement_mm;
+} NanRangeReportInd;
+
+/* Response and Event Callbacks */
+typedef struct {
+ /* NotifyResponse invoked to notify the status of the Request */
+ void (*NotifyResponse)(transaction_id id, NanResponseMsg* rsp_data);
+ /* Callbacks for various Events */
+ void (*EventPublishReplied)(NanPublishRepliedInd* event);
+ void (*EventPublishTerminated)(NanPublishTerminatedInd* event);
+ void (*EventMatch)(NanMatchInd* event);
+ void (*EventMatchExpired)(NanMatchExpiredInd* event);
+ void (*EventSubscribeTerminated)(NanSubscribeTerminatedInd* event);
+ void (*EventFollowup)(NanFollowupInd* event);
+ void (*EventDiscEngEvent)(NanDiscEngEventInd* event);
+ void (*EventDisabled)(NanDisabledInd* event);
+ void (*EventTca)(NanTCAInd* event);
+ void (*EventBeaconSdfPayload)(NanBeaconSdfPayloadInd* event);
+ void (*EventDataRequest)(NanDataPathRequestInd* event);
+ void (*EventDataConfirm)(NanDataPathConfirmInd* event);
+ void (*EventDataEnd)(NanDataPathEndInd* event);
+ void (*EventTransmitFollowup)(NanTransmitFollowupInd* event);
+ void (*EventRangeRequest)(NanRangeRequestInd* event);
+ void (*EventRangeReport)(NanRangeReportInd* event);
+ void (*EventScheduleUpdate)(NanDataPathScheduleUpdateInd* event);
+} NanCallbackHandler;
+
+/**@brief nan_enable_request
+ * Enable NAN functionality
+ *
+ * @param transaction_id:
+ * @param wifi_interface_handle:
+ * @param NanEnableRequest:
+ * @return Synchronous wifi_error
+ * @return Asynchronous NotifyResponse CB return
+ * NAN_STATUS_SUCCESS
+ * NAN_STATUS_ALREADY_ENABLED
+ * NAN_STATUS_INVALID_PARAM
+ * NAN_STATUS_INTERNAL_FAILURE
+ * NAN_STATUS_PROTOCOL_FAILURE
+ * NAN_STATUS_NAN_NOT_ALLOWED
+ */
+wifi_error nan_enable_request(transaction_id id, wifi_interface_handle iface,
+ NanEnableRequest* msg);
+
+/**@brief nan_disbale_request
+ * Disable NAN functionality.
+ *
+ * @param transaction_id:
+ * @param wifi_interface_handle:
+ * @param NanDisableRequest:
+ * @return Synchronous wifi_error
+ * @return Asynchronous NotifyResponse CB return
+ * NAN_STATUS_SUCCESS
+ * NAN_STATUS_PROTOCOL_FAILURE
+ *
+ */
+wifi_error nan_disable_request(transaction_id id, wifi_interface_handle iface);
+
+/**@brief nan_publish_request
+ * Publish request to advertize a service
+ *
+ * @param transaction_id:
+ * @param wifi_interface_handle:
+ * @param NanPublishRequest:
+ * @return Synchronous wifi_error
+ * @return Asynchronous NotifyResponse CB return
+ * NAN_STATUS_SUCCESS
+ * NAN_STATUS_INVALID_PARAM
+ * NAN_STATUS_PROTOCOL_FAILURE
+ * NAN_STATUS_NO_RESOURCE_AVAILABLE
+ * NAN_STATUS_INVALID_PUBLISH_SUBSCRIBE_ID
+ */
+wifi_error nan_publish_request(transaction_id id, wifi_interface_handle iface,
+ NanPublishRequest* msg);
+
+/**@brief nan_publish_cancel_request
+ * Cancel previous publish request
+ *
+ * @param transaction_id:
+ * @param wifi_interface_handle:
+ * @param NanPublishCancelRequest:
+ * @return Synchronous wifi_error
+ * @return Asynchronous NotifyResponse CB return
+ * NAN_STATUS_SUCCESS
+ * NAN_STATUS_INVALID_PUBLISH_SUBSCRIBE_ID
+ * NAN_STATUS_INTERNAL_FAILURE
+ */
+wifi_error nan_publish_cancel_request(transaction_id id, wifi_interface_handle iface,
+ NanPublishCancelRequest* msg);
+
+/**@brief nan_subscribe_request
+ * Subscribe request to search for a service
+ *
+ * @param transaction_id:
+ * @param wifi_interface_handle:
+ * @param NanSubscribeRequest:
+ * @return Synchronous wifi_error
+ * @return Asynchronous NotifyResponse CB return
+ * NAN_STATUS_SUCCESS
+ * NAN_STATUS_INVALID_PARAM
+ * NAN_STATUS_PROTOCOL_FAILURE
+ * NAN_STATUS_INTERNAL_FAILURE
+ * NAN_STATUS_NO_SPACE_AVAILABLE
+ * NAN_STATUS_INVALID_PUBLISH_SUBSCRIBE_ID
+ */
+wifi_error nan_subscribe_request(transaction_id id, wifi_interface_handle iface,
+ NanSubscribeRequest* msg);
+
+/**@brief nan_subscribe_cancel_request
+ * Cancel previous subscribe requests.
+ *
+ * @param transaction_id:
+ * @param wifi_interface_handle:
+ * @param NanSubscribeRequest:
+ * @return Synchronous wifi_error
+ * @return Asynchronous NotifyResponse CB return
+ * NAN_STATUS_SUCCESS
+ * NAN_STATUS_INVALID_PUBLISH_SUBSCRIBE_ID
+ * NAN_STATUS_INTERNAL_FAILURE
+ */
+wifi_error nan_subscribe_cancel_request(transaction_id id, wifi_interface_handle iface,
+ NanSubscribeCancelRequest* msg);
+
+/**@brief nan_transmit_followup_request
+ * NAN transmit follow up request
+ *
+ * @param transaction_id:
+ * @param wifi_interface_handle:
+ * @param NanTransmitFollowupRequest:
+ * @return Synchronous wifi_error
+ * @return Asynchronous NotifyResponse CB return
+ * NAN_STATUS_SUCCESS
+ * NAN_STATUS_INVALID_PARAM
+ * NAN_STATUS_INTERNAL_FAILURE
+ * NAN_STATUS_INVALID_PUBLISH_SUBSCRIBE_ID
+ * NAN_STATUS_INVALID_REQUESTOR_INSTANCE_ID
+ * NAN_STATUS_FOLLOWUP_QUEUE_FULL
+ * @return Asynchronous TransmitFollowupInd CB return
+ * NAN_STATUS_SUCCESS
+ * NAN_STATUS_PROTOCOL_FAILURE
+ * NAN_STATUS_NO_OTA_ACK
+ */
+wifi_error nan_transmit_followup_request(transaction_id id, wifi_interface_handle iface,
+ NanTransmitFollowupRequest* msg);
+
+/**@brief nan_stats_request
+ * Request NAN statistics from Discovery Engine.
+ *
+ * @param transaction_id:
+ * @param wifi_interface_handle:
+ * @param NanStatsRequest:
+ * @return Synchronous wifi_error
+ * @return Asynchronous NotifyResponse CB return
+ * NAN_STATUS_SUCCESS
+ * NAN_STATUS_INTERNAL_FAILURE
+ * NAN_STATUS_INVALID_PARAM
+ */
+wifi_error nan_stats_request(transaction_id id, wifi_interface_handle iface, NanStatsRequest* msg);
+
+/**@brief nan_config_request
+ * NAN configuration request.
+ *
+ * @param transaction_id:
+ * @param wifi_interface_handle:
+ * @param NanConfigRequest:
+ * @return Synchronous wifi_error
+ * @return Asynchronous NotifyResponse CB return
+ * NAN_STATUS_SUCCESS
+ * NAN_STATUS_INVALID_PARAM
+ * NAN_STATUS_PROTOCOL_FAILURE
+ * NAN_STATUS_INTERNAL_FAILURE
+ */
+wifi_error nan_config_request(transaction_id id, wifi_interface_handle iface,
+ NanConfigRequest* msg);
+
+/**@brief nan_tca_request
+ * Configure the various Threshold crossing alerts
+ *
+ * @param transaction_id:
+ * @param wifi_interface_handle:
+ * @param NanStatsRequest:
+ * @return Synchronous wifi_error
+ * @return Asynchronous NotifyResponse CB return
+ * NAN_STATUS_SUCCESS
+ * NAN_STATUS_INVALID_PARAM
+ * NAN_STATUS_INTERNAL_FAILURE
+ */
+wifi_error nan_tca_request(transaction_id id, wifi_interface_handle iface, NanTCARequest* msg);
+
+/**@brief nan_beacon_sdf_payload_request
+ * Set NAN Beacon or sdf payload to discovery engine.
+ * This instructs the Discovery Engine to begin publishing the
+ * received payload in any Beacon or Service Discovery Frame transmitted
+ *
+ * @param transaction_id:
+ * @param wifi_interface_handle:
+ * @param NanStatsRequest:
+ * @return Synchronous wifi_error
+ * @return Asynchronous NotifyResponse CB return
+ * NAN_STATUS_SUCCESS
+ * NAN_STATUS_INVALID_PARAM
+ * NAN_STATUS_INTERNAL_FAILURE
+ */
+wifi_error nan_beacon_sdf_payload_request(transaction_id id, wifi_interface_handle iface,
+ NanBeaconSdfPayloadRequest* msg);
+
+/* Register NAN callbacks. */
+wifi_error nan_register_handler(wifi_interface_handle iface, NanCallbackHandler handlers);
+
+/* Get NAN HAL version. */
+wifi_error nan_get_version(wifi_handle handle, NanVersion* version);
+
+/**@brief nan_get_capabilities
+ * Get NAN Capabilities
+ *
+ * @param transaction_id:
+ * @param wifi_interface_handle:
+ * @return Synchronous wifi_error
+ * @return Asynchronous NotifyResponse CB return
+ * NAN_STATUS_SUCCESS
+ */
+/* Get NAN capabilities. */
+wifi_error nan_get_capabilities(transaction_id id, wifi_interface_handle iface);
+
+/* ========== Nan Data Path APIs ================ */
+/**@brief nan_data_interface_create
+ * Create NAN Data Interface.
+ *
+ * @param transaction_id:
+ * @param wifi_interface_handle:
+ * @param iface_name:
+ * @return Synchronous wifi_error
+ * @return Asynchronous NotifyResponse CB return
+ * NAN_STATUS_SUCCESS
+ * NAN_STATUS_INVALID_PARAM
+ * NAN_STATUS_INTERNAL_FAILURE
+ */
+wifi_error nan_data_interface_create(transaction_id id, wifi_interface_handle iface,
+ char* iface_name);
+
+/**@brief nan_data_interface_delete
+ * Delete NAN Data Interface.
+ *
+ * @param transaction_id:
+ * @param wifi_interface_handle:
+ * @param iface_name:
+ * @return Synchronous wifi_error
+ * @return Asynchronous NotifyResponse CB return
+ * NAN_STATUS_SUCCESS
+ * NAN_STATUS_INVALID_PARAM
+ * NAN_STATUS_INTERNAL_FAILURE
+ */
+wifi_error nan_data_interface_delete(transaction_id id, wifi_interface_handle iface,
+ char* iface_name);
+
+/**@brief nan_data_request_initiator
+ * Initiate a NAN Data Path session.
+ *
+ * @param transaction_id:
+ * @param wifi_interface_handle:
+ * @param NanDataPathInitiatorRequest:
+ * @return Synchronous wifi_error
+ * @return Asynchronous NotifyResponse CB return
+ * NAN_STATUS_SUCCESS
+ * NAN_STATUS_INVALID_PARAM
+ * NAN_STATUS_INTERNAL_FAILURE
+ * NAN_STATUS_PROTOCOL_FAILURE
+ * NAN_STATUS_INVALID_REQUESTOR_INSTANCE_ID
+ */
+wifi_error nan_data_request_initiator(transaction_id id, wifi_interface_handle iface,
+ NanDataPathInitiatorRequest* msg);
+
+/**@brief nan_data_indication_response
+ * Response to a data indication received
+ * corresponding to a NDP session. An indication
+ * is received with a data request and the responder
+ * will send a data response
+ *
+ * @param transaction_id:
+ * @param wifi_interface_handle:
+ * @param NanDataPathIndicationResponse:
+ * @return Synchronous wifi_error
+ * @return Asynchronous NotifyResponse CB return
+ * NAN_STATUS_SUCCESS
+ * NAN_STATUS_INVALID_PARAM
+ * NAN_STATUS_INTERNAL_FAILURE
+ * NAN_STATUS_PROTOCOL_FAILURE
+ * NAN_STATUS_INVALID_NDP_ID
+ */
+wifi_error nan_data_indication_response(transaction_id id, wifi_interface_handle iface,
+ NanDataPathIndicationResponse* msg);
+
+/**@brief nan_data_end
+ * NDL termination request: from either Initiator/Responder
+ *
+ * @param transaction_id:
+ * @param wifi_interface_handle:
+ * @param NanDataPathEndRequest:
+ * @return Synchronous wifi_error
+ * @return Asynchronous NotifyResponse CB return
+ * NAN_STATUS_SUCCESS
+ * NAN_STATUS_INVALID_PARAM
+ * NAN_STATUS_INTERNAL_FAILURE
+ * NAN_STATUS_PROTOCOL_FAILURE
+ * NAN_STATUS_INVALID_NDP_ID
+ */
+wifi_error nan_data_end(transaction_id id, wifi_interface_handle iface, NanDataPathEndRequest* msg);
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __NAN_H__ */
diff --git a/wifi/1.6/default/hal_legacy/wifi_offload.h b/wifi/1.6/default/hal_legacy/wifi_offload.h
new file mode 100644
index 0000000..0c69e39
--- /dev/null
+++ b/wifi/1.6/default/hal_legacy/wifi_offload.h
@@ -0,0 +1,30 @@
+#include "wifi_hal.h"
+
+#ifndef __WIFI_HAL_OFFLOAD_H
+#define __WIFI_HAL_OFFLOAD_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define ETHER_ADDR_LEN 6 // Ethernet frame address length
+#define N_AVAIL_ID 3 // available mkeep_alive IDs from 1 to 3
+#define MKEEP_ALIVE_IP_PKT_MAX 256 // max size of IP packet for keep alive
+
+/**
+ * Send specified keep alive packet periodically.
+ */
+wifi_error wifi_start_sending_offloaded_packet(wifi_request_id id, wifi_interface_handle iface,
+ u16 ether_type, u8* ip_packet, u16 ip_packet_len,
+ u8* src_mac_addr, u8* dst_mac_addr, u32 period_msec);
+
+/**
+ * Stop sending keep alive packet.
+ */
+wifi_error wifi_stop_sending_offloaded_packet(wifi_request_id id, wifi_interface_handle iface);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /*__WIFI_HAL_OFFLOAD_H */
diff --git a/wifi/1.6/default/hal_legacy/wifi_twt.h b/wifi/1.6/default/hal_legacy/wifi_twt.h
new file mode 100644
index 0000000..994bb18
--- /dev/null
+++ b/wifi/1.6/default/hal_legacy/wifi_twt.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __WIFI_HAL_TWT_H__
+#define __WIFI_HAL_TWT_H__
+
+#include "wifi_hal.h"
+
+typedef struct {
+ u8 requester_supported; // 0 for not supporting requester
+ u8 responder_supported; // 0 for not supporting responder
+ u8 broadcast_twt_supported; // 0 for not supporting broadcast TWT
+ u8 flexibile_twt_supported; // 0 for not supporting flexible TWT
+} TwtCapability;
+
+typedef struct {
+ TwtCapability device_capability;
+ TwtCapability peer_capability;
+} TwtCapabilitySet;
+
+// For all optional fields below, if no value specify -1
+typedef struct {
+ u8 config_id; // An unique ID for an individual TWT request
+ u8 negotiation_type; // 0 for individual TWT, 1 for broadcast TWT
+ u8 trigger_type; // 0 for non-triggered TWT, 1 for triggered TWT
+ s32 wake_dur_us; // Proposed wake duration in us
+ s32 wake_int_us; // Average wake interval in us
+ s32 wake_int_min_us; // Min wake interval in us. Optional.
+ s32 wake_int_max_us; // Max wake interval in us. Optional.
+ s32 wake_dur_min_us; // Min wake duration in us. Optional.
+ s32 wake_dur_max_us; // Max wake duration in us. Optional.
+ s32 avg_pkt_size; // Average bytes of each packet to send in each wake
+ // duration. Optional.
+ s32 avg_pkt_num; // Average number of packets to send in each wake
+ // duration. Optional.
+ s32 wake_time_off_us; // First wake duration time offset in us. Optional.
+} TwtSetupRequest;
+
+typedef enum {
+ TWT_SETUP_SUCCESS = 0, // TWT setup is accepted.
+ TWT_SETUP_REJECT = 1, // TWT setup is rejected by AP.
+ TWT_SETUP_TIMEOUT = 2, // TWT setup response from AP times out.
+ TWT_SETUP_IE = 3, // AP sent TWT Setup IE parsing failure.
+ TWT_SETUP_PARAMS = 4, // AP sent TWT Setup IE Parameters invalid.
+ TWT_SETUP_ERROR = 255, // Generic error
+} TwtSetupReasonCode;
+
+typedef struct {
+ u8 config_id; // An unique ID for an individual TWT request
+ u8 status; // 0 for success, non-zero for failure
+ TwtSetupReasonCode reason_code;
+ u8 negotiation_type; // 0 for individual TWT, 1 for broadcast TWT
+ u8 trigger_type; // 0 for non-triggered TWT, 1 for triggered TWT
+ s32 wake_dur_us; // Proposed wake duration in us
+ s32 wake_int_us; // Average wake interval in us
+ s32 wake_time_off_us; // First wake duration time offset in us.
+} TwtSetupResponse;
+
+typedef struct {
+ u8 config_id; // An unique ID for an individual TWT request
+ u8 all_twt; // 0 for individual setp request, 1 for all TWT
+ u8 negotiation_type; // 0 for individual TWT, 1 for broadcast TWT
+} TwtTeardownRequest;
+
+typedef enum {
+ TWT_TD_RC_HOST = 0, // Teardown triggered by Host
+ TWT_TD_RC_PEER = 1, // Peer initiated teardown
+ TWT_TD_RC_MCHAN = 2, // Teardown due to MCHAN Active
+ TWT_TD_RC_MCNX = 3, // Teardown due to MultiConnection
+ TWT_TD_RC_CSA = 4, // Teardown due to CSA
+ TWT_TD_RC_BTCX = 5, // Teardown due to BT Coex
+ TWT_TD_RC_SETUP_FAIL = 6, // Setup fails midway. Teardown all connections
+ TWT_TD_RC_SCHED = 7, // Teardown by TWT Scheduler
+ TWT_TD_RC_ERROR = 255, // Generic error cases
+} TwtTeardownReason;
+
+typedef struct {
+ u8 config_id; // An unique ID for an individual TWT request
+ u8 all_twt; // 0 for individual setp request, 1 for all TWT
+ u8 status; // 0 for success, non-zero for failure
+ TwtTeardownReason reason;
+} TwtTeardownCompletion;
+
+typedef struct {
+ u8 config_id; // An unique ID for an individual TWT request
+ u8 all_twt; // 0 for individual setup request, 1 for all TWT
+ s32 resume_time_us; // If -1, TWT is suspended for indefinite time.
+ // Otherwise, TWT is suspended for resume_time_us
+} TwtInfoFrameRequest;
+
+typedef enum {
+ TWT_INFO_RC_HOST = 0, // Host initiated TWT Info frame */
+ TWT_INFO_RC_PEER = 1, // Peer initiated TWT Info frame
+ TWT_INFO_RC_ERROR = 2, // Generic error conditions */
+} TwtInfoFrameReason;
+
+// TWT Info frame triggered externally.
+// Device should not send TwtInfoFrameReceived to Host for internally
+// triggered TWT Info frame during SCAN, MCHAN operations.
+typedef struct {
+ u8 config_id; // An unique ID for an individual TWT request
+ u8 all_twt; // 0 for individual setup request, 1 for all TWT
+ u8 status; // 0 for success, non-zero for failure
+ TwtInfoFrameReason reason;
+ u8 twt_resumed; // 1 - TWT resumed, 0 - TWT suspended
+} TwtInfoFrameReceived;
+
+typedef struct {
+ u8 config_id;
+ u32 avg_pkt_num_tx; // Average number of Tx packets in each wake duration.
+ u32 avg_pkt_num_rx; // Average number of Rx packets in each wake duration.
+ u32 avg_tx_pkt_size; // Average bytes per Rx packet in each wake duration.
+ u32 avg_rx_pkt_size; // Average bytes per Rx packet in each wake duration.
+ u32 avg_eosp_dur_us; // Average duration of early terminated SP
+ u32 eosp_count; // Count of early terminations
+ u32 num_sp; // Count of service period (SP), also known as wake duration.
+} TwtStats;
+
+// Asynchronous notification from the device.
+// For example, TWT was torn down by the device and later when the device is
+// ready, it can send this async notification.
+// This can be expandable in future.
+typedef enum {
+ TWT_NOTIF_ALLOW_TWT = 1, // Device ready to process TWT Setup request
+} TwtNotification;
+
+typedef struct {
+ TwtNotification notification;
+} TwtDeviceNotify;
+
+// Callbacks for various TWT responses and events
+typedef struct {
+ // Callback for TWT setup response
+ void (*EventTwtSetupResponse)(TwtSetupResponse* event);
+ // Callback for TWT teardown completion
+ void (*EventTwtTeardownCompletion)(TwtTeardownCompletion* event);
+ // Callback for TWT info frame received event
+ void (*EventTwtInfoFrameReceived)(TwtInfoFrameReceived* event);
+ // Callback for TWT notification from the device
+ void (*EventTwtDeviceNotify)(TwtDeviceNotify* event);
+} TwtCallbackHandler;
+
+#endif /* __WIFI_HAL_TWT_H__ */
diff --git a/wifi/1.6/default/hidl_callback_util.h b/wifi/1.6/default/hidl_callback_util.h
new file mode 100644
index 0000000..aab0ae5
--- /dev/null
+++ b/wifi/1.6/default/hidl_callback_util.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HIDL_CALLBACK_UTIL_H_
+#define HIDL_CALLBACK_UTIL_H_
+
+#include <set>
+
+#include <hidl/HidlSupport.h>
+#include <hidl/HidlTransportSupport.h>
+
+namespace {
+// Type of callback invoked by the death handler.
+using on_death_cb_function = std::function<void(uint64_t)>;
+
+// Private class used to keep track of death of individual
+// callbacks stored in HidlCallbackHandler.
+template <typename CallbackType>
+class HidlDeathHandler : public android::hardware::hidl_death_recipient {
+ public:
+ HidlDeathHandler(const on_death_cb_function& user_cb_function)
+ : cb_function_(user_cb_function) {}
+ ~HidlDeathHandler() = default;
+
+ // Death notification for callbacks.
+ void serviceDied(uint64_t cookie,
+ const android::wp<android::hidl::base::V1_0::IBase>& /* who */) override {
+ cb_function_(cookie);
+ }
+
+ private:
+ on_death_cb_function cb_function_;
+
+ DISALLOW_COPY_AND_ASSIGN(HidlDeathHandler);
+};
+} // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace hidl_callback_util {
+template <typename CallbackType>
+// Provides a class to manage callbacks for the various HIDL interfaces and
+// handle the death of the process hosting each callback.
+class HidlCallbackHandler {
+ public:
+ HidlCallbackHandler()
+ : death_handler_(new HidlDeathHandler<CallbackType>(
+ std::bind(&HidlCallbackHandler::onObjectDeath, this, std::placeholders::_1))) {}
+ ~HidlCallbackHandler() = default;
+
+ bool addCallback(const sp<CallbackType>& cb) {
+ // TODO(b/33818800): Can't compare proxies yet. So, use the cookie
+ // (callback proxy's raw pointer) to track the death of individual
+ // clients.
+ uint64_t cookie = reinterpret_cast<uint64_t>(cb.get());
+ for (const auto& s : cb_set_) {
+ if (interfacesEqual(cb, s)) {
+ LOG(ERROR) << "Duplicate death notification registration";
+ return true;
+ }
+ }
+ if (!cb->linkToDeath(death_handler_, cookie)) {
+ LOG(ERROR) << "Failed to register death notification";
+ return false;
+ }
+ cb_set_.insert(cb);
+ return true;
+ }
+
+ const std::set<android::sp<CallbackType>>& getCallbacks() { return cb_set_; }
+
+ // Death notification for callbacks.
+ void onObjectDeath(uint64_t cookie) {
+ CallbackType* cb = reinterpret_cast<CallbackType*>(cookie);
+ const auto& iter = cb_set_.find(cb);
+ if (iter == cb_set_.end()) {
+ LOG(ERROR) << "Unknown callback death notification received";
+ return;
+ }
+ cb_set_.erase(iter);
+ LOG(DEBUG) << "Dead callback removed from list";
+ }
+
+ void invalidate() {
+ for (const sp<CallbackType>& cb : cb_set_) {
+ if (!cb->unlinkToDeath(death_handler_)) {
+ LOG(ERROR) << "Failed to deregister death notification";
+ }
+ }
+ cb_set_.clear();
+ }
+
+ private:
+ std::set<sp<CallbackType>> cb_set_;
+ sp<HidlDeathHandler<CallbackType>> death_handler_;
+
+ DISALLOW_COPY_AND_ASSIGN(HidlCallbackHandler);
+};
+
+} // namespace hidl_callback_util
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+#endif // HIDL_CALLBACK_UTIL_H_
diff --git a/wifi/1.6/default/hidl_return_util.h b/wifi/1.6/default/hidl_return_util.h
new file mode 100644
index 0000000..a0efac2
--- /dev/null
+++ b/wifi/1.6/default/hidl_return_util.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HIDL_RETURN_UTIL_H_
+#define HIDL_RETURN_UTIL_H_
+
+#include "hidl_sync_util.h"
+#include "wifi_status_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace hidl_return_util {
+using namespace android::hardware::wifi::V1_0;
+
+/**
+ * These utility functions are used to invoke a method on the provided
+ * HIDL interface object.
+ * These functions checks if the provided HIDL interface object is valid.
+ * a) if valid, Invokes the corresponding internal implementation function of
+ * the HIDL method. It then invokes the HIDL continuation callback with
+ * the status and any returned values.
+ * b) if invalid, invokes the HIDL continuation callback with the
+ * provided error status and default values.
+ */
+// Use for HIDL methods which return only an instance of WifiStatus.
+template <typename ObjT, typename WorkFuncT, typename... Args>
+Return<void> validateAndCall(ObjT* obj, WifiStatusCode status_code_if_invalid, WorkFuncT&& work,
+ const std::function<void(const WifiStatus&)>& hidl_cb,
+ Args&&... args) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (obj->isValid()) {
+ hidl_cb((obj->*work)(std::forward<Args>(args)...));
+ } else {
+ hidl_cb(createWifiStatus(status_code_if_invalid));
+ }
+ return Void();
+}
+
+// Use for HIDL methods which return only an instance of WifiStatus.
+// This version passes the global lock acquired to the body of the method.
+// Note: Only used by IWifi::stop() currently.
+template <typename ObjT, typename WorkFuncT, typename... Args>
+Return<void> validateAndCallWithLock(ObjT* obj, WifiStatusCode status_code_if_invalid,
+ WorkFuncT&& work,
+ const std::function<void(const WifiStatus&)>& hidl_cb,
+ Args&&... args) {
+ auto lock = hidl_sync_util::acquireGlobalLock();
+ if (obj->isValid()) {
+ hidl_cb((obj->*work)(&lock, std::forward<Args>(args)...));
+ } else {
+ hidl_cb(createWifiStatus(status_code_if_invalid));
+ }
+ return Void();
+}
+
+// Use for HIDL methods which return instance of WifiStatus and a single return
+// value.
+template <typename ObjT, typename WorkFuncT, typename ReturnT, typename... Args>
+Return<void> validateAndCall(ObjT* obj, WifiStatusCode status_code_if_invalid, WorkFuncT&& work,
+ const std::function<void(const WifiStatus&, ReturnT)>& hidl_cb,
+ Args&&... args) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (obj->isValid()) {
+ const auto& ret_pair = (obj->*work)(std::forward<Args>(args)...);
+ const WifiStatus& status = std::get<0>(ret_pair);
+ const auto& ret_value = std::get<1>(ret_pair);
+ hidl_cb(status, ret_value);
+ } else {
+ hidl_cb(createWifiStatus(status_code_if_invalid),
+ typename std::remove_reference<ReturnT>::type());
+ }
+ return Void();
+}
+
+// Use for HIDL methods which return instance of WifiStatus and 2 return
+// values.
+template <typename ObjT, typename WorkFuncT, typename ReturnT1, typename ReturnT2, typename... Args>
+Return<void> validateAndCall(
+ ObjT* obj, WifiStatusCode status_code_if_invalid, WorkFuncT&& work,
+ const std::function<void(const WifiStatus&, ReturnT1, ReturnT2)>& hidl_cb, Args&&... args) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (obj->isValid()) {
+ const auto& ret_tuple = (obj->*work)(std::forward<Args>(args)...);
+ const WifiStatus& status = std::get<0>(ret_tuple);
+ const auto& ret_value1 = std::get<1>(ret_tuple);
+ const auto& ret_value2 = std::get<2>(ret_tuple);
+ hidl_cb(status, ret_value1, ret_value2);
+ } else {
+ hidl_cb(createWifiStatus(status_code_if_invalid),
+ typename std::remove_reference<ReturnT1>::type(),
+ typename std::remove_reference<ReturnT2>::type());
+ }
+ return Void();
+}
+
+} // namespace hidl_return_util
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+#endif // HIDL_RETURN_UTIL_H_
diff --git a/wifi/1.6/default/hidl_struct_util.cpp b/wifi/1.6/default/hidl_struct_util.cpp
new file mode 100644
index 0000000..2112b26
--- /dev/null
+++ b/wifi/1.6/default/hidl_struct_util.cpp
@@ -0,0 +1,3007 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <utils/SystemClock.h>
+
+#include "hidl_struct_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace hidl_struct_util {
+
+using V1_6::NanConfigRequestSupplemental;
+
+WifiChannelWidthInMhz convertLegacyWifiChannelWidthToHidl(legacy_hal::wifi_channel_width type);
+
+hidl_string safeConvertChar(const char* str, size_t max_len) {
+ const char* c = str;
+ size_t size = 0;
+ while (*c && (unsigned char)*c < 128 && size < max_len) {
+ ++size;
+ ++c;
+ }
+ return hidl_string(str, size);
+}
+
+IWifiChip::ChipCapabilityMask convertLegacyLoggerFeatureToHidlChipCapability(uint32_t feature) {
+ using HidlChipCaps = IWifiChip::ChipCapabilityMask;
+ switch (feature) {
+ case legacy_hal::WIFI_LOGGER_MEMORY_DUMP_SUPPORTED:
+ return HidlChipCaps::DEBUG_MEMORY_FIRMWARE_DUMP;
+ case legacy_hal::WIFI_LOGGER_DRIVER_DUMP_SUPPORTED:
+ return HidlChipCaps::DEBUG_MEMORY_DRIVER_DUMP;
+ case legacy_hal::WIFI_LOGGER_CONNECT_EVENT_SUPPORTED:
+ return HidlChipCaps::DEBUG_RING_BUFFER_CONNECT_EVENT;
+ case legacy_hal::WIFI_LOGGER_POWER_EVENT_SUPPORTED:
+ return HidlChipCaps::DEBUG_RING_BUFFER_POWER_EVENT;
+ case legacy_hal::WIFI_LOGGER_WAKE_LOCK_SUPPORTED:
+ return HidlChipCaps::DEBUG_RING_BUFFER_WAKELOCK_EVENT;
+ };
+ CHECK(false) << "Unknown legacy feature: " << feature;
+ return {};
+}
+
+IWifiStaIface::StaIfaceCapabilityMask convertLegacyLoggerFeatureToHidlStaIfaceCapability(
+ uint32_t feature) {
+ using HidlStaIfaceCaps = IWifiStaIface::StaIfaceCapabilityMask;
+ switch (feature) {
+ case legacy_hal::WIFI_LOGGER_PACKET_FATE_SUPPORTED:
+ return HidlStaIfaceCaps::DEBUG_PACKET_FATE;
+ };
+ CHECK(false) << "Unknown legacy feature: " << feature;
+ return {};
+}
+
+V1_5::IWifiChip::ChipCapabilityMask convertLegacyFeatureToHidlChipCapability(uint64_t feature) {
+ using HidlChipCaps = V1_5::IWifiChip::ChipCapabilityMask;
+ switch (feature) {
+ case WIFI_FEATURE_SET_TX_POWER_LIMIT:
+ return HidlChipCaps::SET_TX_POWER_LIMIT;
+ case WIFI_FEATURE_USE_BODY_HEAD_SAR:
+ return HidlChipCaps::USE_BODY_HEAD_SAR;
+ case WIFI_FEATURE_D2D_RTT:
+ return HidlChipCaps::D2D_RTT;
+ case WIFI_FEATURE_D2AP_RTT:
+ return HidlChipCaps::D2AP_RTT;
+ case WIFI_FEATURE_INFRA_60G:
+ return HidlChipCaps::WIGIG;
+ case WIFI_FEATURE_SET_LATENCY_MODE:
+ return HidlChipCaps::SET_LATENCY_MODE;
+ case WIFI_FEATURE_P2P_RAND_MAC:
+ return HidlChipCaps::P2P_RAND_MAC;
+ };
+ CHECK(false) << "Unknown legacy feature: " << feature;
+ return {};
+}
+
+IWifiStaIface::StaIfaceCapabilityMask convertLegacyFeatureToHidlStaIfaceCapability(
+ uint64_t feature) {
+ using HidlStaIfaceCaps = IWifiStaIface::StaIfaceCapabilityMask;
+ switch (feature) {
+ case WIFI_FEATURE_GSCAN:
+ return HidlStaIfaceCaps::BACKGROUND_SCAN;
+ case WIFI_FEATURE_LINK_LAYER_STATS:
+ return HidlStaIfaceCaps::LINK_LAYER_STATS;
+ case WIFI_FEATURE_RSSI_MONITOR:
+ return HidlStaIfaceCaps::RSSI_MONITOR;
+ case WIFI_FEATURE_CONTROL_ROAMING:
+ return HidlStaIfaceCaps::CONTROL_ROAMING;
+ case WIFI_FEATURE_IE_WHITELIST:
+ return HidlStaIfaceCaps::PROBE_IE_WHITELIST;
+ case WIFI_FEATURE_SCAN_RAND:
+ return HidlStaIfaceCaps::SCAN_RAND;
+ case WIFI_FEATURE_INFRA_5G:
+ return HidlStaIfaceCaps::STA_5G;
+ case WIFI_FEATURE_HOTSPOT:
+ return HidlStaIfaceCaps::HOTSPOT;
+ case WIFI_FEATURE_PNO:
+ return HidlStaIfaceCaps::PNO;
+ case WIFI_FEATURE_TDLS:
+ return HidlStaIfaceCaps::TDLS;
+ case WIFI_FEATURE_TDLS_OFFCHANNEL:
+ return HidlStaIfaceCaps::TDLS_OFFCHANNEL;
+ case WIFI_FEATURE_CONFIG_NDO:
+ return HidlStaIfaceCaps::ND_OFFLOAD;
+ case WIFI_FEATURE_MKEEP_ALIVE:
+ return HidlStaIfaceCaps::KEEP_ALIVE;
+ };
+ CHECK(false) << "Unknown legacy feature: " << feature;
+ return {};
+}
+
+bool convertLegacyFeaturesToHidlChipCapabilities(uint64_t legacy_feature_set,
+ uint32_t legacy_logger_feature_set,
+ uint32_t* hidl_caps) {
+ if (!hidl_caps) {
+ return false;
+ }
+ *hidl_caps = {};
+ using HidlChipCaps = IWifiChip::ChipCapabilityMask;
+ for (const auto feature : {legacy_hal::WIFI_LOGGER_MEMORY_DUMP_SUPPORTED,
+ legacy_hal::WIFI_LOGGER_DRIVER_DUMP_SUPPORTED,
+ legacy_hal::WIFI_LOGGER_CONNECT_EVENT_SUPPORTED,
+ legacy_hal::WIFI_LOGGER_POWER_EVENT_SUPPORTED,
+ legacy_hal::WIFI_LOGGER_WAKE_LOCK_SUPPORTED}) {
+ if (feature & legacy_logger_feature_set) {
+ *hidl_caps |= convertLegacyLoggerFeatureToHidlChipCapability(feature);
+ }
+ }
+ std::vector<uint64_t> features = {WIFI_FEATURE_SET_TX_POWER_LIMIT,
+ WIFI_FEATURE_USE_BODY_HEAD_SAR,
+ WIFI_FEATURE_D2D_RTT,
+ WIFI_FEATURE_D2AP_RTT,
+ WIFI_FEATURE_INFRA_60G,
+ WIFI_FEATURE_SET_LATENCY_MODE,
+ WIFI_FEATURE_P2P_RAND_MAC};
+ for (const auto feature : features) {
+ if (feature & legacy_feature_set) {
+ *hidl_caps |= convertLegacyFeatureToHidlChipCapability(feature);
+ }
+ }
+
+ // There are no flags for these 3 in the legacy feature set. Adding them to
+ // the set because all the current devices support it.
+ *hidl_caps |= HidlChipCaps::DEBUG_RING_BUFFER_VENDOR_DATA;
+ *hidl_caps |= HidlChipCaps::DEBUG_HOST_WAKE_REASON_STATS;
+ *hidl_caps |= HidlChipCaps::DEBUG_ERROR_ALERTS;
+ return true;
+}
+
+WifiDebugRingBufferFlags convertLegacyDebugRingBufferFlagsToHidl(uint32_t flag) {
+ switch (flag) {
+ case WIFI_RING_BUFFER_FLAG_HAS_BINARY_ENTRIES:
+ return WifiDebugRingBufferFlags::HAS_BINARY_ENTRIES;
+ case WIFI_RING_BUFFER_FLAG_HAS_ASCII_ENTRIES:
+ return WifiDebugRingBufferFlags::HAS_ASCII_ENTRIES;
+ };
+ CHECK(false) << "Unknown legacy flag: " << flag;
+ return {};
+}
+
+bool convertLegacyDebugRingBufferStatusToHidl(
+ const legacy_hal::wifi_ring_buffer_status& legacy_status,
+ WifiDebugRingBufferStatus* hidl_status) {
+ if (!hidl_status) {
+ return false;
+ }
+ *hidl_status = {};
+ hidl_status->ringName = safeConvertChar(reinterpret_cast<const char*>(legacy_status.name),
+ sizeof(legacy_status.name));
+ hidl_status->flags = 0;
+ for (const auto flag :
+ {WIFI_RING_BUFFER_FLAG_HAS_BINARY_ENTRIES, WIFI_RING_BUFFER_FLAG_HAS_ASCII_ENTRIES}) {
+ if (flag & legacy_status.flags) {
+ hidl_status->flags |= static_cast<std::underlying_type<WifiDebugRingBufferFlags>::type>(
+ convertLegacyDebugRingBufferFlagsToHidl(flag));
+ }
+ }
+ hidl_status->ringId = legacy_status.ring_id;
+ hidl_status->sizeInBytes = legacy_status.ring_buffer_byte_size;
+ // Calculate free size of the ring the buffer. We don't need to send the
+ // exact read/write pointers that were there in the legacy HAL interface.
+ if (legacy_status.written_bytes >= legacy_status.read_bytes) {
+ hidl_status->freeSizeInBytes = legacy_status.ring_buffer_byte_size -
+ (legacy_status.written_bytes - legacy_status.read_bytes);
+ } else {
+ hidl_status->freeSizeInBytes = legacy_status.read_bytes - legacy_status.written_bytes;
+ }
+ hidl_status->verboseLevel = legacy_status.verbose_level;
+ return true;
+}
+
+bool convertLegacyVectorOfDebugRingBufferStatusToHidl(
+ const std::vector<legacy_hal::wifi_ring_buffer_status>& legacy_status_vec,
+ std::vector<WifiDebugRingBufferStatus>* hidl_status_vec) {
+ if (!hidl_status_vec) {
+ return false;
+ }
+ *hidl_status_vec = {};
+ for (const auto& legacy_status : legacy_status_vec) {
+ WifiDebugRingBufferStatus hidl_status;
+ if (!convertLegacyDebugRingBufferStatusToHidl(legacy_status, &hidl_status)) {
+ return false;
+ }
+ hidl_status_vec->push_back(hidl_status);
+ }
+ return true;
+}
+
+bool convertLegacyWakeReasonStatsToHidl(const legacy_hal::WakeReasonStats& legacy_stats,
+ WifiDebugHostWakeReasonStats* hidl_stats) {
+ if (!hidl_stats) {
+ return false;
+ }
+ *hidl_stats = {};
+ hidl_stats->totalCmdEventWakeCnt = legacy_stats.wake_reason_cnt.total_cmd_event_wake;
+ hidl_stats->cmdEventWakeCntPerType = legacy_stats.cmd_event_wake_cnt;
+ hidl_stats->totalDriverFwLocalWakeCnt = legacy_stats.wake_reason_cnt.total_driver_fw_local_wake;
+ hidl_stats->driverFwLocalWakeCntPerType = legacy_stats.driver_fw_local_wake_cnt;
+ hidl_stats->totalRxPacketWakeCnt = legacy_stats.wake_reason_cnt.total_rx_data_wake;
+ hidl_stats->rxPktWakeDetails.rxUnicastCnt =
+ legacy_stats.wake_reason_cnt.rx_wake_details.rx_unicast_cnt;
+ hidl_stats->rxPktWakeDetails.rxMulticastCnt =
+ legacy_stats.wake_reason_cnt.rx_wake_details.rx_multicast_cnt;
+ hidl_stats->rxPktWakeDetails.rxBroadcastCnt =
+ legacy_stats.wake_reason_cnt.rx_wake_details.rx_broadcast_cnt;
+ hidl_stats->rxMulticastPkWakeDetails.ipv4RxMulticastAddrCnt =
+ legacy_stats.wake_reason_cnt.rx_multicast_wake_pkt_info.ipv4_rx_multicast_addr_cnt;
+ hidl_stats->rxMulticastPkWakeDetails.ipv6RxMulticastAddrCnt =
+ legacy_stats.wake_reason_cnt.rx_multicast_wake_pkt_info.ipv6_rx_multicast_addr_cnt;
+ hidl_stats->rxMulticastPkWakeDetails.otherRxMulticastAddrCnt =
+ legacy_stats.wake_reason_cnt.rx_multicast_wake_pkt_info.other_rx_multicast_addr_cnt;
+ hidl_stats->rxIcmpPkWakeDetails.icmpPkt =
+ legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp_pkt;
+ hidl_stats->rxIcmpPkWakeDetails.icmp6Pkt =
+ legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_pkt;
+ hidl_stats->rxIcmpPkWakeDetails.icmp6Ra =
+ legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_ra;
+ hidl_stats->rxIcmpPkWakeDetails.icmp6Na =
+ legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_na;
+ hidl_stats->rxIcmpPkWakeDetails.icmp6Ns =
+ legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_ns;
+ return true;
+}
+
+legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy(
+ V1_1::IWifiChip::TxPowerScenario hidl_scenario) {
+ switch (hidl_scenario) {
+ // This is the only supported scenario for V1_1
+ case V1_1::IWifiChip::TxPowerScenario::VOICE_CALL:
+ return legacy_hal::WIFI_POWER_SCENARIO_VOICE_CALL;
+ };
+ CHECK(false);
+}
+
+legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy_1_2(
+ V1_2::IWifiChip::TxPowerScenario hidl_scenario) {
+ switch (hidl_scenario) {
+ // This is the only supported scenario for V1_1
+ case V1_2::IWifiChip::TxPowerScenario::VOICE_CALL:
+ return legacy_hal::WIFI_POWER_SCENARIO_VOICE_CALL;
+ // Those are the supported scenarios for V1_2
+ case V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF:
+ return legacy_hal::WIFI_POWER_SCENARIO_ON_HEAD_CELL_OFF;
+ case V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_ON:
+ return legacy_hal::WIFI_POWER_SCENARIO_ON_HEAD_CELL_ON;
+ case V1_2::IWifiChip::TxPowerScenario::ON_BODY_CELL_OFF:
+ return legacy_hal::WIFI_POWER_SCENARIO_ON_BODY_CELL_OFF;
+ case V1_2::IWifiChip::TxPowerScenario::ON_BODY_CELL_ON:
+ return legacy_hal::WIFI_POWER_SCENARIO_ON_BODY_CELL_ON;
+ };
+ CHECK(false);
+}
+
+legacy_hal::wifi_latency_mode convertHidlLatencyModeToLegacy(
+ V1_3::IWifiChip::LatencyMode hidl_latency_mode) {
+ switch (hidl_latency_mode) {
+ case V1_3::IWifiChip::LatencyMode::NORMAL:
+ return legacy_hal::WIFI_LATENCY_MODE_NORMAL;
+ case V1_3::IWifiChip::LatencyMode::LOW:
+ return legacy_hal::WIFI_LATENCY_MODE_LOW;
+ }
+ CHECK(false);
+}
+
+bool convertLegacyWifiMacInfoToHidl(
+ const legacy_hal::WifiMacInfo& legacy_mac_info,
+ V1_4::IWifiChipEventCallback::RadioModeInfo* hidl_radio_mode_info) {
+ if (!hidl_radio_mode_info) {
+ return false;
+ }
+ *hidl_radio_mode_info = {};
+
+ hidl_radio_mode_info->radioId = legacy_mac_info.wlan_mac_id;
+ // Convert from bitmask of bands in the legacy HAL to enum value in
+ // the HIDL interface.
+ if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_6_0_BAND &&
+ legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND &&
+ legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_2_4_BAND) {
+ hidl_radio_mode_info->bandInfo = V1_4::WifiBand::BAND_24GHZ_5GHZ_6GHZ;
+ } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_6_0_BAND &&
+ legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND) {
+ hidl_radio_mode_info->bandInfo = V1_4::WifiBand::BAND_5GHZ_6GHZ;
+ } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_6_0_BAND) {
+ hidl_radio_mode_info->bandInfo = V1_4::WifiBand::BAND_6GHZ;
+ } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_2_4_BAND &&
+ legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND) {
+ hidl_radio_mode_info->bandInfo = V1_4::WifiBand::BAND_24GHZ_5GHZ;
+ } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_2_4_BAND) {
+ hidl_radio_mode_info->bandInfo = V1_4::WifiBand::BAND_24GHZ;
+ } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND) {
+ hidl_radio_mode_info->bandInfo = V1_4::WifiBand::BAND_5GHZ;
+ } else {
+ hidl_radio_mode_info->bandInfo = V1_4::WifiBand::BAND_UNSPECIFIED;
+ }
+ std::vector<V1_2::IWifiChipEventCallback::IfaceInfo> iface_info_vec;
+ for (const auto& legacy_iface_info : legacy_mac_info.iface_infos) {
+ V1_2::IWifiChipEventCallback::IfaceInfo iface_info;
+ iface_info.name = legacy_iface_info.name;
+ iface_info.channel = legacy_iface_info.channel;
+ iface_info_vec.push_back(iface_info);
+ }
+ hidl_radio_mode_info->ifaceInfos = iface_info_vec;
+ return true;
+}
+
+uint32_t convertHidlWifiBandToLegacyMacBand(V1_5::WifiBand hidl_band) {
+ switch (hidl_band) {
+ case V1_5::WifiBand::BAND_24GHZ:
+ return legacy_hal::WLAN_MAC_2_4_BAND;
+ case V1_5::WifiBand::BAND_5GHZ:
+ case V1_5::WifiBand::BAND_5GHZ_DFS:
+ case V1_5::WifiBand::BAND_5GHZ_WITH_DFS:
+ return legacy_hal::WLAN_MAC_5_0_BAND;
+ case V1_5::WifiBand::BAND_24GHZ_5GHZ:
+ case V1_5::WifiBand::BAND_24GHZ_5GHZ_WITH_DFS:
+ return (legacy_hal::WLAN_MAC_2_4_BAND | legacy_hal::WLAN_MAC_5_0_BAND);
+ case V1_5::WifiBand::BAND_6GHZ:
+ return legacy_hal::WLAN_MAC_6_0_BAND;
+ case V1_5::WifiBand::BAND_5GHZ_6GHZ:
+ return (legacy_hal::WLAN_MAC_5_0_BAND | legacy_hal::WLAN_MAC_6_0_BAND);
+ case V1_5::WifiBand::BAND_24GHZ_5GHZ_6GHZ:
+ case V1_5::WifiBand::BAND_24GHZ_5GHZ_WITH_DFS_6GHZ:
+ return (legacy_hal::WLAN_MAC_2_4_BAND | legacy_hal::WLAN_MAC_5_0_BAND |
+ legacy_hal::WLAN_MAC_6_0_BAND);
+ case V1_5::WifiBand::BAND_60GHZ:
+ return legacy_hal::WLAN_MAC_60_0_BAND;
+ default:
+ return (legacy_hal::WLAN_MAC_2_4_BAND | legacy_hal::WLAN_MAC_5_0_BAND |
+ legacy_hal::WLAN_MAC_6_0_BAND | legacy_hal::WLAN_MAC_60_0_BAND);
+ }
+}
+
+V1_5::WifiBand convertLegacyMacBandToHidlWifiBand(uint32_t band) {
+ switch (band) {
+ case legacy_hal::WLAN_MAC_2_4_BAND:
+ return V1_5::WifiBand::BAND_24GHZ;
+ case legacy_hal::WLAN_MAC_5_0_BAND:
+ return V1_5::WifiBand::BAND_5GHZ;
+ case legacy_hal::WLAN_MAC_6_0_BAND:
+ return V1_5::WifiBand::BAND_6GHZ;
+ case legacy_hal::WLAN_MAC_60_0_BAND:
+ return V1_5::WifiBand::BAND_60GHZ;
+ default:
+ return V1_5::WifiBand::BAND_UNSPECIFIED;
+ }
+}
+
+uint32_t convertHidlWifiIfaceModeToLegacy(uint32_t hidl_iface_mask) {
+ uint32_t legacy_iface_mask = 0;
+ if (hidl_iface_mask & V1_5::WifiIfaceMode::IFACE_MODE_STA) {
+ legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_STA);
+ }
+ if (hidl_iface_mask & V1_5::WifiIfaceMode::IFACE_MODE_SOFTAP) {
+ legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_SOFTAP);
+ }
+ if (hidl_iface_mask & V1_5::WifiIfaceMode::IFACE_MODE_P2P_CLIENT) {
+ legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_P2P_CLIENT);
+ }
+ if (hidl_iface_mask & V1_5::WifiIfaceMode::IFACE_MODE_P2P_GO) {
+ legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_P2P_GO);
+ }
+ if (hidl_iface_mask & V1_5::WifiIfaceMode::IFACE_MODE_NAN) {
+ legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_NAN);
+ }
+ if (hidl_iface_mask & V1_5::WifiIfaceMode::IFACE_MODE_TDLS) {
+ legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_TDLS);
+ }
+ if (hidl_iface_mask & V1_5::WifiIfaceMode::IFACE_MODE_MESH) {
+ legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_MESH);
+ }
+ if (hidl_iface_mask & V1_5::WifiIfaceMode::IFACE_MODE_IBSS) {
+ legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_IBSS);
+ }
+ return legacy_iface_mask;
+}
+
+uint32_t convertLegacyWifiInterfaceModeToHidl(uint32_t legacy_iface_mask) {
+ uint32_t hidl_iface_mask = 0;
+ if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_STA)) {
+ hidl_iface_mask |= V1_5::WifiIfaceMode::IFACE_MODE_STA;
+ }
+ if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_SOFTAP)) {
+ hidl_iface_mask |= V1_5::WifiIfaceMode::IFACE_MODE_SOFTAP;
+ }
+ if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_P2P_CLIENT)) {
+ hidl_iface_mask |= V1_5::WifiIfaceMode::IFACE_MODE_P2P_CLIENT;
+ }
+ if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_P2P_GO)) {
+ hidl_iface_mask |= V1_5::WifiIfaceMode::IFACE_MODE_P2P_GO;
+ }
+ if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_NAN)) {
+ hidl_iface_mask |= V1_5::WifiIfaceMode::IFACE_MODE_NAN;
+ }
+ if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_TDLS)) {
+ hidl_iface_mask |= V1_5::WifiIfaceMode::IFACE_MODE_TDLS;
+ }
+ if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_MESH)) {
+ hidl_iface_mask |= V1_5::WifiIfaceMode::IFACE_MODE_MESH;
+ }
+ if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_IBSS)) {
+ hidl_iface_mask |= V1_5::WifiIfaceMode::IFACE_MODE_IBSS;
+ }
+ return hidl_iface_mask;
+}
+
+uint32_t convertHidlUsableChannelFilterToLegacy(uint32_t hidl_filter_mask) {
+ uint32_t legacy_filter_mask = 0;
+ if (hidl_filter_mask & V1_5::IWifiChip::UsableChannelFilter::CELLULAR_COEXISTENCE) {
+ legacy_filter_mask |= legacy_hal::WIFI_USABLE_CHANNEL_FILTER_CELLULAR_COEXISTENCE;
+ }
+ if (hidl_filter_mask & V1_5::IWifiChip::UsableChannelFilter::CONCURRENCY) {
+ legacy_filter_mask |= legacy_hal::WIFI_USABLE_CHANNEL_FILTER_CONCURRENCY;
+ }
+ if (hidl_filter_mask & V1_6::IWifiChip::UsableChannelFilter::NAN_INSTANT_MODE) {
+ legacy_filter_mask |= WIFI_USABLE_CHANNEL_FILTER_NAN_INSTANT_MODE;
+ }
+ return legacy_filter_mask;
+}
+
+bool convertLegacyWifiUsableChannelToHidl(
+ const legacy_hal::wifi_usable_channel& legacy_usable_channel,
+ V1_6::WifiUsableChannel* hidl_usable_channel) {
+ if (!hidl_usable_channel) {
+ return false;
+ }
+ *hidl_usable_channel = {};
+ hidl_usable_channel->channel = legacy_usable_channel.freq;
+ hidl_usable_channel->channelBandwidth =
+ convertLegacyWifiChannelWidthToHidl(legacy_usable_channel.width);
+ hidl_usable_channel->ifaceModeMask =
+ convertLegacyWifiInterfaceModeToHidl(legacy_usable_channel.iface_mode_mask);
+
+ return true;
+}
+
+bool convertLegacyWifiUsableChannelsToHidl(
+ const std::vector<legacy_hal::wifi_usable_channel>& legacy_usable_channels,
+ std::vector<V1_6::WifiUsableChannel>* hidl_usable_channels) {
+ if (!hidl_usable_channels) {
+ return false;
+ }
+ *hidl_usable_channels = {};
+ for (const auto& legacy_usable_channel : legacy_usable_channels) {
+ V1_6::WifiUsableChannel hidl_usable_channel;
+ if (!convertLegacyWifiUsableChannelToHidl(legacy_usable_channel, &hidl_usable_channel)) {
+ return false;
+ }
+ hidl_usable_channels->push_back(hidl_usable_channel);
+ }
+ return true;
+}
+
+bool convertLegacyWifiMacInfosToHidl(
+ const std::vector<legacy_hal::WifiMacInfo>& legacy_mac_infos,
+ std::vector<V1_4::IWifiChipEventCallback::RadioModeInfo>* hidl_radio_mode_infos) {
+ if (!hidl_radio_mode_infos) {
+ return false;
+ }
+ *hidl_radio_mode_infos = {};
+
+ for (const auto& legacy_mac_info : legacy_mac_infos) {
+ V1_4::IWifiChipEventCallback::RadioModeInfo hidl_radio_mode_info;
+ if (!convertLegacyWifiMacInfoToHidl(legacy_mac_info, &hidl_radio_mode_info)) {
+ return false;
+ }
+ hidl_radio_mode_infos->push_back(hidl_radio_mode_info);
+ }
+ return true;
+}
+
+bool convertLegacyFeaturesToHidlStaCapabilities(uint64_t legacy_feature_set,
+ uint32_t legacy_logger_feature_set,
+ uint32_t* hidl_caps) {
+ if (!hidl_caps) {
+ return false;
+ }
+ *hidl_caps = {};
+ using HidlStaIfaceCaps = IWifiStaIface::StaIfaceCapabilityMask;
+ for (const auto feature : {legacy_hal::WIFI_LOGGER_PACKET_FATE_SUPPORTED}) {
+ if (feature & legacy_logger_feature_set) {
+ *hidl_caps |= convertLegacyLoggerFeatureToHidlStaIfaceCapability(feature);
+ }
+ }
+ for (const auto feature :
+ {WIFI_FEATURE_GSCAN, WIFI_FEATURE_LINK_LAYER_STATS, WIFI_FEATURE_RSSI_MONITOR,
+ WIFI_FEATURE_CONTROL_ROAMING, WIFI_FEATURE_IE_WHITELIST, WIFI_FEATURE_SCAN_RAND,
+ WIFI_FEATURE_INFRA_5G, WIFI_FEATURE_HOTSPOT, WIFI_FEATURE_PNO, WIFI_FEATURE_TDLS,
+ WIFI_FEATURE_TDLS_OFFCHANNEL, WIFI_FEATURE_CONFIG_NDO, WIFI_FEATURE_MKEEP_ALIVE}) {
+ if (feature & legacy_feature_set) {
+ *hidl_caps |= convertLegacyFeatureToHidlStaIfaceCapability(feature);
+ }
+ }
+ // There is no flag for this one in the legacy feature set. Adding it to the
+ // set because all the current devices support it.
+ *hidl_caps |= HidlStaIfaceCaps::APF;
+ return true;
+}
+
+bool convertLegacyApfCapabilitiesToHidl(const legacy_hal::PacketFilterCapabilities& legacy_caps,
+ StaApfPacketFilterCapabilities* hidl_caps) {
+ if (!hidl_caps) {
+ return false;
+ }
+ *hidl_caps = {};
+ hidl_caps->version = legacy_caps.version;
+ hidl_caps->maxLength = legacy_caps.max_len;
+ return true;
+}
+
+uint8_t convertHidlGscanReportEventFlagToLegacy(
+ StaBackgroundScanBucketEventReportSchemeMask hidl_flag) {
+ using HidlFlag = StaBackgroundScanBucketEventReportSchemeMask;
+ switch (hidl_flag) {
+ case HidlFlag::EACH_SCAN:
+ return REPORT_EVENTS_EACH_SCAN;
+ case HidlFlag::FULL_RESULTS:
+ return REPORT_EVENTS_FULL_RESULTS;
+ case HidlFlag::NO_BATCH:
+ return REPORT_EVENTS_NO_BATCH;
+ };
+ CHECK(false);
+}
+
+StaScanDataFlagMask convertLegacyGscanDataFlagToHidl(uint8_t legacy_flag) {
+ switch (legacy_flag) {
+ case legacy_hal::WIFI_SCAN_FLAG_INTERRUPTED:
+ return StaScanDataFlagMask::INTERRUPTED;
+ };
+ CHECK(false) << "Unknown legacy flag: " << legacy_flag;
+ // To silence the compiler warning about reaching the end of non-void
+ // function.
+ return {};
+}
+
+bool convertLegacyGscanCapabilitiesToHidl(const legacy_hal::wifi_gscan_capabilities& legacy_caps,
+ StaBackgroundScanCapabilities* hidl_caps) {
+ if (!hidl_caps) {
+ return false;
+ }
+ *hidl_caps = {};
+ hidl_caps->maxCacheSize = legacy_caps.max_scan_cache_size;
+ hidl_caps->maxBuckets = legacy_caps.max_scan_buckets;
+ hidl_caps->maxApCachePerScan = legacy_caps.max_ap_cache_per_scan;
+ hidl_caps->maxReportingThreshold = legacy_caps.max_scan_reporting_threshold;
+ return true;
+}
+
+legacy_hal::wifi_band convertHidlWifiBandToLegacy(V1_0::WifiBand band) {
+ switch (band) {
+ case V1_0::WifiBand::BAND_UNSPECIFIED:
+ return legacy_hal::WIFI_BAND_UNSPECIFIED;
+ case V1_0::WifiBand::BAND_24GHZ:
+ return legacy_hal::WIFI_BAND_BG;
+ case V1_0::WifiBand::BAND_5GHZ:
+ return legacy_hal::WIFI_BAND_A;
+ case V1_0::WifiBand::BAND_5GHZ_DFS:
+ return legacy_hal::WIFI_BAND_A_DFS;
+ case V1_0::WifiBand::BAND_5GHZ_WITH_DFS:
+ return legacy_hal::WIFI_BAND_A_WITH_DFS;
+ case V1_0::WifiBand::BAND_24GHZ_5GHZ:
+ return legacy_hal::WIFI_BAND_ABG;
+ case V1_0::WifiBand::BAND_24GHZ_5GHZ_WITH_DFS:
+ return legacy_hal::WIFI_BAND_ABG_WITH_DFS;
+ };
+ CHECK(false);
+}
+
+bool convertHidlGscanParamsToLegacy(const StaBackgroundScanParameters& hidl_scan_params,
+ legacy_hal::wifi_scan_cmd_params* legacy_scan_params) {
+ if (!legacy_scan_params) {
+ return false;
+ }
+ *legacy_scan_params = {};
+ legacy_scan_params->base_period = hidl_scan_params.basePeriodInMs;
+ legacy_scan_params->max_ap_per_scan = hidl_scan_params.maxApPerScan;
+ legacy_scan_params->report_threshold_percent = hidl_scan_params.reportThresholdPercent;
+ legacy_scan_params->report_threshold_num_scans = hidl_scan_params.reportThresholdNumScans;
+ if (hidl_scan_params.buckets.size() > MAX_BUCKETS) {
+ return false;
+ }
+ legacy_scan_params->num_buckets = hidl_scan_params.buckets.size();
+ for (uint32_t bucket_idx = 0; bucket_idx < hidl_scan_params.buckets.size(); bucket_idx++) {
+ const StaBackgroundScanBucketParameters& hidl_bucket_spec =
+ hidl_scan_params.buckets[bucket_idx];
+ legacy_hal::wifi_scan_bucket_spec& legacy_bucket_spec =
+ legacy_scan_params->buckets[bucket_idx];
+ if (hidl_bucket_spec.bucketIdx >= MAX_BUCKETS) {
+ return false;
+ }
+ legacy_bucket_spec.bucket = hidl_bucket_spec.bucketIdx;
+ legacy_bucket_spec.band = convertHidlWifiBandToLegacy(hidl_bucket_spec.band);
+ legacy_bucket_spec.period = hidl_bucket_spec.periodInMs;
+ legacy_bucket_spec.max_period = hidl_bucket_spec.exponentialMaxPeriodInMs;
+ legacy_bucket_spec.base = hidl_bucket_spec.exponentialBase;
+ legacy_bucket_spec.step_count = hidl_bucket_spec.exponentialStepCount;
+ legacy_bucket_spec.report_events = 0;
+ using HidlFlag = StaBackgroundScanBucketEventReportSchemeMask;
+ for (const auto flag : {HidlFlag::EACH_SCAN, HidlFlag::FULL_RESULTS, HidlFlag::NO_BATCH}) {
+ if (hidl_bucket_spec.eventReportScheme &
+ static_cast<std::underlying_type<HidlFlag>::type>(flag)) {
+ legacy_bucket_spec.report_events |= convertHidlGscanReportEventFlagToLegacy(flag);
+ }
+ }
+ if (hidl_bucket_spec.frequencies.size() > MAX_CHANNELS) {
+ return false;
+ }
+ legacy_bucket_spec.num_channels = hidl_bucket_spec.frequencies.size();
+ for (uint32_t freq_idx = 0; freq_idx < hidl_bucket_spec.frequencies.size(); freq_idx++) {
+ legacy_bucket_spec.channels[freq_idx].channel = hidl_bucket_spec.frequencies[freq_idx];
+ }
+ }
+ return true;
+}
+
+bool convertLegacyIeToHidl(const legacy_hal::wifi_information_element& legacy_ie,
+ WifiInformationElement* hidl_ie) {
+ if (!hidl_ie) {
+ return false;
+ }
+ *hidl_ie = {};
+ hidl_ie->id = legacy_ie.id;
+ hidl_ie->data = std::vector<uint8_t>(legacy_ie.data, legacy_ie.data + legacy_ie.len);
+ return true;
+}
+
+bool convertLegacyIeBlobToHidl(const uint8_t* ie_blob, uint32_t ie_blob_len,
+ std::vector<WifiInformationElement>* hidl_ies) {
+ if (!ie_blob || !hidl_ies) {
+ return false;
+ }
+ *hidl_ies = {};
+ const uint8_t* ies_begin = ie_blob;
+ const uint8_t* ies_end = ie_blob + ie_blob_len;
+ const uint8_t* next_ie = ies_begin;
+ using wifi_ie = legacy_hal::wifi_information_element;
+ constexpr size_t kIeHeaderLen = sizeof(wifi_ie);
+ // Each IE should atleast have the header (i.e |id| & |len| fields).
+ while (next_ie + kIeHeaderLen <= ies_end) {
+ const wifi_ie& legacy_ie = (*reinterpret_cast<const wifi_ie*>(next_ie));
+ uint32_t curr_ie_len = kIeHeaderLen + legacy_ie.len;
+ if (next_ie + curr_ie_len > ies_end) {
+ LOG(ERROR) << "Error parsing IE blob. Next IE: " << (void*)next_ie
+ << ", Curr IE len: " << curr_ie_len << ", IEs End: " << (void*)ies_end;
+ break;
+ }
+ WifiInformationElement hidl_ie;
+ if (!convertLegacyIeToHidl(legacy_ie, &hidl_ie)) {
+ LOG(ERROR) << "Error converting IE. Id: " << legacy_ie.id << ", len: " << legacy_ie.len;
+ break;
+ }
+ hidl_ies->push_back(std::move(hidl_ie));
+ next_ie += curr_ie_len;
+ }
+ // Check if the blob has been fully consumed.
+ if (next_ie != ies_end) {
+ LOG(ERROR) << "Failed to fully parse IE blob. Next IE: " << (void*)next_ie
+ << ", IEs End: " << (void*)ies_end;
+ }
+ return true;
+}
+
+bool convertLegacyGscanResultToHidl(const legacy_hal::wifi_scan_result& legacy_scan_result,
+ bool has_ie_data, StaScanResult* hidl_scan_result) {
+ if (!hidl_scan_result) {
+ return false;
+ }
+ *hidl_scan_result = {};
+ hidl_scan_result->timeStampInUs = legacy_scan_result.ts;
+ hidl_scan_result->ssid = std::vector<uint8_t>(
+ legacy_scan_result.ssid,
+ legacy_scan_result.ssid +
+ strnlen(legacy_scan_result.ssid, sizeof(legacy_scan_result.ssid) - 1));
+ memcpy(hidl_scan_result->bssid.data(), legacy_scan_result.bssid,
+ hidl_scan_result->bssid.size());
+ hidl_scan_result->frequency = legacy_scan_result.channel;
+ hidl_scan_result->rssi = legacy_scan_result.rssi;
+ hidl_scan_result->beaconPeriodInMs = legacy_scan_result.beacon_period;
+ hidl_scan_result->capability = legacy_scan_result.capability;
+ if (has_ie_data) {
+ std::vector<WifiInformationElement> ies;
+ if (!convertLegacyIeBlobToHidl(reinterpret_cast<const uint8_t*>(legacy_scan_result.ie_data),
+ legacy_scan_result.ie_length, &ies)) {
+ return false;
+ }
+ hidl_scan_result->informationElements = std::move(ies);
+ }
+ return true;
+}
+
+bool convertLegacyCachedGscanResultsToHidl(
+ const legacy_hal::wifi_cached_scan_results& legacy_cached_scan_result,
+ StaScanData* hidl_scan_data) {
+ if (!hidl_scan_data) {
+ return false;
+ }
+ *hidl_scan_data = {};
+ hidl_scan_data->flags = 0;
+ for (const auto flag : {legacy_hal::WIFI_SCAN_FLAG_INTERRUPTED}) {
+ if (legacy_cached_scan_result.flags & flag) {
+ hidl_scan_data->flags |= static_cast<std::underlying_type<StaScanDataFlagMask>::type>(
+ convertLegacyGscanDataFlagToHidl(flag));
+ }
+ }
+ hidl_scan_data->bucketsScanned = legacy_cached_scan_result.buckets_scanned;
+
+ CHECK(legacy_cached_scan_result.num_results >= 0 &&
+ legacy_cached_scan_result.num_results <= MAX_AP_CACHE_PER_SCAN);
+ std::vector<StaScanResult> hidl_scan_results;
+ for (int32_t result_idx = 0; result_idx < legacy_cached_scan_result.num_results; result_idx++) {
+ StaScanResult hidl_scan_result;
+ if (!convertLegacyGscanResultToHidl(legacy_cached_scan_result.results[result_idx], false,
+ &hidl_scan_result)) {
+ return false;
+ }
+ hidl_scan_results.push_back(hidl_scan_result);
+ }
+ hidl_scan_data->results = std::move(hidl_scan_results);
+ return true;
+}
+
+bool convertLegacyVectorOfCachedGscanResultsToHidl(
+ const std::vector<legacy_hal::wifi_cached_scan_results>& legacy_cached_scan_results,
+ std::vector<StaScanData>* hidl_scan_datas) {
+ if (!hidl_scan_datas) {
+ return false;
+ }
+ *hidl_scan_datas = {};
+ for (const auto& legacy_cached_scan_result : legacy_cached_scan_results) {
+ StaScanData hidl_scan_data;
+ if (!convertLegacyCachedGscanResultsToHidl(legacy_cached_scan_result, &hidl_scan_data)) {
+ return false;
+ }
+ hidl_scan_datas->push_back(hidl_scan_data);
+ }
+ return true;
+}
+
+WifiDebugTxPacketFate convertLegacyDebugTxPacketFateToHidl(legacy_hal::wifi_tx_packet_fate fate) {
+ switch (fate) {
+ case legacy_hal::TX_PKT_FATE_ACKED:
+ return WifiDebugTxPacketFate::ACKED;
+ case legacy_hal::TX_PKT_FATE_SENT:
+ return WifiDebugTxPacketFate::SENT;
+ case legacy_hal::TX_PKT_FATE_FW_QUEUED:
+ return WifiDebugTxPacketFate::FW_QUEUED;
+ case legacy_hal::TX_PKT_FATE_FW_DROP_INVALID:
+ return WifiDebugTxPacketFate::FW_DROP_INVALID;
+ case legacy_hal::TX_PKT_FATE_FW_DROP_NOBUFS:
+ return WifiDebugTxPacketFate::FW_DROP_NOBUFS;
+ case legacy_hal::TX_PKT_FATE_FW_DROP_OTHER:
+ return WifiDebugTxPacketFate::FW_DROP_OTHER;
+ case legacy_hal::TX_PKT_FATE_DRV_QUEUED:
+ return WifiDebugTxPacketFate::DRV_QUEUED;
+ case legacy_hal::TX_PKT_FATE_DRV_DROP_INVALID:
+ return WifiDebugTxPacketFate::DRV_DROP_INVALID;
+ case legacy_hal::TX_PKT_FATE_DRV_DROP_NOBUFS:
+ return WifiDebugTxPacketFate::DRV_DROP_NOBUFS;
+ case legacy_hal::TX_PKT_FATE_DRV_DROP_OTHER:
+ return WifiDebugTxPacketFate::DRV_DROP_OTHER;
+ };
+ CHECK(false) << "Unknown legacy fate type: " << fate;
+}
+
+WifiDebugRxPacketFate convertLegacyDebugRxPacketFateToHidl(legacy_hal::wifi_rx_packet_fate fate) {
+ switch (fate) {
+ case legacy_hal::RX_PKT_FATE_SUCCESS:
+ return WifiDebugRxPacketFate::SUCCESS;
+ case legacy_hal::RX_PKT_FATE_FW_QUEUED:
+ return WifiDebugRxPacketFate::FW_QUEUED;
+ case legacy_hal::RX_PKT_FATE_FW_DROP_FILTER:
+ return WifiDebugRxPacketFate::FW_DROP_FILTER;
+ case legacy_hal::RX_PKT_FATE_FW_DROP_INVALID:
+ return WifiDebugRxPacketFate::FW_DROP_INVALID;
+ case legacy_hal::RX_PKT_FATE_FW_DROP_NOBUFS:
+ return WifiDebugRxPacketFate::FW_DROP_NOBUFS;
+ case legacy_hal::RX_PKT_FATE_FW_DROP_OTHER:
+ return WifiDebugRxPacketFate::FW_DROP_OTHER;
+ case legacy_hal::RX_PKT_FATE_DRV_QUEUED:
+ return WifiDebugRxPacketFate::DRV_QUEUED;
+ case legacy_hal::RX_PKT_FATE_DRV_DROP_FILTER:
+ return WifiDebugRxPacketFate::DRV_DROP_FILTER;
+ case legacy_hal::RX_PKT_FATE_DRV_DROP_INVALID:
+ return WifiDebugRxPacketFate::DRV_DROP_INVALID;
+ case legacy_hal::RX_PKT_FATE_DRV_DROP_NOBUFS:
+ return WifiDebugRxPacketFate::DRV_DROP_NOBUFS;
+ case legacy_hal::RX_PKT_FATE_DRV_DROP_OTHER:
+ return WifiDebugRxPacketFate::DRV_DROP_OTHER;
+ };
+ CHECK(false) << "Unknown legacy fate type: " << fate;
+}
+
+WifiDebugPacketFateFrameType convertLegacyDebugPacketFateFrameTypeToHidl(
+ legacy_hal::frame_type type) {
+ switch (type) {
+ case legacy_hal::FRAME_TYPE_UNKNOWN:
+ return WifiDebugPacketFateFrameType::UNKNOWN;
+ case legacy_hal::FRAME_TYPE_ETHERNET_II:
+ return WifiDebugPacketFateFrameType::ETHERNET_II;
+ case legacy_hal::FRAME_TYPE_80211_MGMT:
+ return WifiDebugPacketFateFrameType::MGMT_80211;
+ };
+ CHECK(false) << "Unknown legacy frame type: " << type;
+}
+
+bool convertLegacyDebugPacketFateFrameToHidl(const legacy_hal::frame_info& legacy_frame,
+ WifiDebugPacketFateFrameInfo* hidl_frame) {
+ if (!hidl_frame) {
+ return false;
+ }
+ *hidl_frame = {};
+ hidl_frame->frameType = convertLegacyDebugPacketFateFrameTypeToHidl(legacy_frame.payload_type);
+ hidl_frame->frameLen = legacy_frame.frame_len;
+ hidl_frame->driverTimestampUsec = legacy_frame.driver_timestamp_usec;
+ hidl_frame->firmwareTimestampUsec = legacy_frame.firmware_timestamp_usec;
+ const uint8_t* frame_begin =
+ reinterpret_cast<const uint8_t*>(legacy_frame.frame_content.ethernet_ii_bytes);
+ hidl_frame->frameContent =
+ std::vector<uint8_t>(frame_begin, frame_begin + legacy_frame.frame_len);
+ return true;
+}
+
+bool convertLegacyDebugTxPacketFateToHidl(const legacy_hal::wifi_tx_report& legacy_fate,
+ WifiDebugTxPacketFateReport* hidl_fate) {
+ if (!hidl_fate) {
+ return false;
+ }
+ *hidl_fate = {};
+ hidl_fate->fate = convertLegacyDebugTxPacketFateToHidl(legacy_fate.fate);
+ return convertLegacyDebugPacketFateFrameToHidl(legacy_fate.frame_inf, &hidl_fate->frameInfo);
+}
+
+bool convertLegacyVectorOfDebugTxPacketFateToHidl(
+ const std::vector<legacy_hal::wifi_tx_report>& legacy_fates,
+ std::vector<WifiDebugTxPacketFateReport>* hidl_fates) {
+ if (!hidl_fates) {
+ return false;
+ }
+ *hidl_fates = {};
+ for (const auto& legacy_fate : legacy_fates) {
+ WifiDebugTxPacketFateReport hidl_fate;
+ if (!convertLegacyDebugTxPacketFateToHidl(legacy_fate, &hidl_fate)) {
+ return false;
+ }
+ hidl_fates->push_back(hidl_fate);
+ }
+ return true;
+}
+
+bool convertLegacyDebugRxPacketFateToHidl(const legacy_hal::wifi_rx_report& legacy_fate,
+ WifiDebugRxPacketFateReport* hidl_fate) {
+ if (!hidl_fate) {
+ return false;
+ }
+ *hidl_fate = {};
+ hidl_fate->fate = convertLegacyDebugRxPacketFateToHidl(legacy_fate.fate);
+ return convertLegacyDebugPacketFateFrameToHidl(legacy_fate.frame_inf, &hidl_fate->frameInfo);
+}
+
+bool convertLegacyVectorOfDebugRxPacketFateToHidl(
+ const std::vector<legacy_hal::wifi_rx_report>& legacy_fates,
+ std::vector<WifiDebugRxPacketFateReport>* hidl_fates) {
+ if (!hidl_fates) {
+ return false;
+ }
+ *hidl_fates = {};
+ for (const auto& legacy_fate : legacy_fates) {
+ WifiDebugRxPacketFateReport hidl_fate;
+ if (!convertLegacyDebugRxPacketFateToHidl(legacy_fate, &hidl_fate)) {
+ return false;
+ }
+ hidl_fates->push_back(hidl_fate);
+ }
+ return true;
+}
+
+bool convertLegacyLinkLayerRadioStatsToHidl(
+ const legacy_hal::LinkLayerRadioStats& legacy_radio_stat,
+ V1_6::StaLinkLayerRadioStats* hidl_radio_stat) {
+ if (!hidl_radio_stat) {
+ return false;
+ }
+ *hidl_radio_stat = {};
+
+ hidl_radio_stat->radioId = legacy_radio_stat.stats.radio;
+ hidl_radio_stat->V1_0.onTimeInMs = legacy_radio_stat.stats.on_time;
+ hidl_radio_stat->V1_0.txTimeInMs = legacy_radio_stat.stats.tx_time;
+ hidl_radio_stat->V1_0.rxTimeInMs = legacy_radio_stat.stats.rx_time;
+ hidl_radio_stat->V1_0.onTimeInMsForScan = legacy_radio_stat.stats.on_time_scan;
+ hidl_radio_stat->V1_0.txTimeInMsPerLevel = legacy_radio_stat.tx_time_per_levels;
+ hidl_radio_stat->onTimeInMsForNanScan = legacy_radio_stat.stats.on_time_nbd;
+ hidl_radio_stat->onTimeInMsForBgScan = legacy_radio_stat.stats.on_time_gscan;
+ hidl_radio_stat->onTimeInMsForRoamScan = legacy_radio_stat.stats.on_time_roam_scan;
+ hidl_radio_stat->onTimeInMsForPnoScan = legacy_radio_stat.stats.on_time_pno_scan;
+ hidl_radio_stat->onTimeInMsForHs20Scan = legacy_radio_stat.stats.on_time_hs20;
+
+ std::vector<V1_6::WifiChannelStats> hidl_channel_stats;
+
+ for (const auto& channel_stat : legacy_radio_stat.channel_stats) {
+ V1_6::WifiChannelStats hidl_channel_stat;
+ hidl_channel_stat.onTimeInMs = channel_stat.on_time;
+ hidl_channel_stat.ccaBusyTimeInMs = channel_stat.cca_busy_time;
+ /*
+ * TODO once b/119142899 is fixed,
+ * replace below code with convertLegacyWifiChannelInfoToHidl()
+ */
+ hidl_channel_stat.channel.width = WifiChannelWidthInMhz::WIDTH_20;
+ hidl_channel_stat.channel.centerFreq = channel_stat.channel.center_freq;
+ hidl_channel_stat.channel.centerFreq0 = channel_stat.channel.center_freq0;
+ hidl_channel_stat.channel.centerFreq1 = channel_stat.channel.center_freq1;
+ hidl_channel_stats.push_back(hidl_channel_stat);
+ }
+
+ hidl_radio_stat->channelStats = hidl_channel_stats;
+
+ return true;
+}
+
+bool convertLegacyLinkLayerStatsToHidl(const legacy_hal::LinkLayerStats& legacy_stats,
+ V1_6::StaLinkLayerStats* hidl_stats) {
+ if (!hidl_stats) {
+ return false;
+ }
+ *hidl_stats = {};
+ // iface legacy_stats conversion.
+ hidl_stats->iface.V1_0.beaconRx = legacy_stats.iface.beacon_rx;
+ hidl_stats->iface.V1_0.avgRssiMgmt = legacy_stats.iface.rssi_mgmt;
+ hidl_stats->iface.V1_0.wmeBePktStats.rxMpdu =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu;
+ hidl_stats->iface.V1_0.wmeBePktStats.txMpdu =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].tx_mpdu;
+ hidl_stats->iface.V1_0.wmeBePktStats.lostMpdu =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].mpdu_lost;
+ hidl_stats->iface.V1_0.wmeBePktStats.retries =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].retries;
+ hidl_stats->iface.wmeBeContentionTimeStats.contentionTimeMinInUsec =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_min;
+ hidl_stats->iface.wmeBeContentionTimeStats.contentionTimeMaxInUsec =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_max;
+ hidl_stats->iface.wmeBeContentionTimeStats.contentionTimeAvgInUsec =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_avg;
+ hidl_stats->iface.wmeBeContentionTimeStats.contentionNumSamples =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_num_samples;
+ hidl_stats->iface.V1_0.wmeBkPktStats.rxMpdu =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].rx_mpdu;
+ hidl_stats->iface.V1_0.wmeBkPktStats.txMpdu =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].tx_mpdu;
+ hidl_stats->iface.V1_0.wmeBkPktStats.lostMpdu =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].mpdu_lost;
+ hidl_stats->iface.V1_0.wmeBkPktStats.retries =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].retries;
+ hidl_stats->iface.wmeBkContentionTimeStats.contentionTimeMinInUsec =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_min;
+ hidl_stats->iface.wmeBkContentionTimeStats.contentionTimeMaxInUsec =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_max;
+ hidl_stats->iface.wmeBkContentionTimeStats.contentionTimeAvgInUsec =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_avg;
+ hidl_stats->iface.wmeBkContentionTimeStats.contentionNumSamples =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_num_samples;
+ hidl_stats->iface.V1_0.wmeViPktStats.rxMpdu =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].rx_mpdu;
+ hidl_stats->iface.V1_0.wmeViPktStats.txMpdu =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].tx_mpdu;
+ hidl_stats->iface.V1_0.wmeViPktStats.lostMpdu =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].mpdu_lost;
+ hidl_stats->iface.V1_0.wmeViPktStats.retries =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].retries;
+ hidl_stats->iface.wmeViContentionTimeStats.contentionTimeMinInUsec =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_min;
+ hidl_stats->iface.wmeViContentionTimeStats.contentionTimeMaxInUsec =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_max;
+ hidl_stats->iface.wmeViContentionTimeStats.contentionTimeAvgInUsec =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_avg;
+ hidl_stats->iface.wmeViContentionTimeStats.contentionNumSamples =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_num_samples;
+ hidl_stats->iface.V1_0.wmeVoPktStats.rxMpdu =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].rx_mpdu;
+ hidl_stats->iface.V1_0.wmeVoPktStats.txMpdu =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].tx_mpdu;
+ hidl_stats->iface.V1_0.wmeVoPktStats.lostMpdu =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost;
+ hidl_stats->iface.V1_0.wmeVoPktStats.retries =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries;
+ hidl_stats->iface.wmeVoContentionTimeStats.contentionTimeMinInUsec =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_min;
+ hidl_stats->iface.wmeVoContentionTimeStats.contentionTimeMaxInUsec =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_max;
+ hidl_stats->iface.wmeVoContentionTimeStats.contentionTimeAvgInUsec =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_avg;
+ hidl_stats->iface.wmeVoContentionTimeStats.contentionNumSamples =
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_num_samples;
+ hidl_stats->iface.timeSliceDutyCycleInPercent =
+ legacy_stats.iface.info.time_slicing_duty_cycle_percent;
+ // peer info legacy_stats conversion.
+ std::vector<V1_6::StaPeerInfo> hidl_peers_info_stats;
+ for (const auto& legacy_peer_info_stats : legacy_stats.peers) {
+ V1_6::StaPeerInfo hidl_peer_info_stats;
+ if (!convertLegacyPeerInfoStatsToHidl(legacy_peer_info_stats, &hidl_peer_info_stats)) {
+ return false;
+ }
+ hidl_peers_info_stats.push_back(hidl_peer_info_stats);
+ }
+ hidl_stats->iface.peers = hidl_peers_info_stats;
+ // radio legacy_stats conversion.
+ std::vector<V1_6::StaLinkLayerRadioStats> hidl_radios_stats;
+ for (const auto& legacy_radio_stats : legacy_stats.radios) {
+ V1_6::StaLinkLayerRadioStats hidl_radio_stats;
+ if (!convertLegacyLinkLayerRadioStatsToHidl(legacy_radio_stats, &hidl_radio_stats)) {
+ return false;
+ }
+ hidl_radios_stats.push_back(hidl_radio_stats);
+ }
+ hidl_stats->radios = hidl_radios_stats;
+ // Timestamp in the HAL wrapper here since it's not provided in the legacy
+ // HAL API.
+ hidl_stats->timeStampInMs = uptimeMillis();
+ return true;
+}
+
+bool convertLegacyPeerInfoStatsToHidl(const legacy_hal::WifiPeerInfo& legacy_peer_info_stats,
+ V1_6::StaPeerInfo* hidl_peer_info_stats) {
+ if (!hidl_peer_info_stats) {
+ return false;
+ }
+ *hidl_peer_info_stats = {};
+ hidl_peer_info_stats->staCount = legacy_peer_info_stats.peer_info.bssload.sta_count;
+ hidl_peer_info_stats->chanUtil = legacy_peer_info_stats.peer_info.bssload.chan_util;
+
+ std::vector<V1_6::StaRateStat> hidlRateStats;
+ for (const auto& legacy_rate_stats : legacy_peer_info_stats.rate_stats) {
+ V1_6::StaRateStat rateStat;
+ if (!convertLegacyWifiRateInfoToHidl(legacy_rate_stats.rate, &rateStat.rateInfo)) {
+ return false;
+ }
+ rateStat.txMpdu = legacy_rate_stats.tx_mpdu;
+ rateStat.rxMpdu = legacy_rate_stats.rx_mpdu;
+ rateStat.mpduLost = legacy_rate_stats.mpdu_lost;
+ rateStat.retries = legacy_rate_stats.retries;
+ hidlRateStats.push_back(rateStat);
+ }
+ hidl_peer_info_stats->rateStats = hidlRateStats;
+ return true;
+}
+
+bool convertLegacyRoamingCapabilitiesToHidl(
+ const legacy_hal::wifi_roaming_capabilities& legacy_caps,
+ StaRoamingCapabilities* hidl_caps) {
+ if (!hidl_caps) {
+ return false;
+ }
+ *hidl_caps = {};
+ hidl_caps->maxBlacklistSize = legacy_caps.max_blacklist_size;
+ hidl_caps->maxWhitelistSize = legacy_caps.max_whitelist_size;
+ return true;
+}
+
+bool convertHidlRoamingConfigToLegacy(const StaRoamingConfig& hidl_config,
+ legacy_hal::wifi_roaming_config* legacy_config) {
+ if (!legacy_config) {
+ return false;
+ }
+ *legacy_config = {};
+ if (hidl_config.bssidBlacklist.size() > MAX_BLACKLIST_BSSID ||
+ hidl_config.ssidWhitelist.size() > MAX_WHITELIST_SSID) {
+ return false;
+ }
+ legacy_config->num_blacklist_bssid = hidl_config.bssidBlacklist.size();
+ uint32_t i = 0;
+ for (const auto& bssid : hidl_config.bssidBlacklist) {
+ CHECK(bssid.size() == sizeof(legacy_hal::mac_addr));
+ memcpy(legacy_config->blacklist_bssid[i++], bssid.data(), bssid.size());
+ }
+ legacy_config->num_whitelist_ssid = hidl_config.ssidWhitelist.size();
+ i = 0;
+ for (const auto& ssid : hidl_config.ssidWhitelist) {
+ CHECK(ssid.size() <= sizeof(legacy_hal::ssid_t::ssid_str));
+ legacy_config->whitelist_ssid[i].length = ssid.size();
+ memcpy(legacy_config->whitelist_ssid[i].ssid_str, ssid.data(), ssid.size());
+ i++;
+ }
+ return true;
+}
+
+legacy_hal::fw_roaming_state_t convertHidlRoamingStateToLegacy(StaRoamingState state) {
+ switch (state) {
+ case StaRoamingState::ENABLED:
+ return legacy_hal::ROAMING_ENABLE;
+ case StaRoamingState::DISABLED:
+ return legacy_hal::ROAMING_DISABLE;
+ };
+ CHECK(false);
+}
+
+legacy_hal::NanMatchAlg convertHidlNanMatchAlgToLegacy(NanMatchAlg type) {
+ switch (type) {
+ case NanMatchAlg::MATCH_ONCE:
+ return legacy_hal::NAN_MATCH_ALG_MATCH_ONCE;
+ case NanMatchAlg::MATCH_CONTINUOUS:
+ return legacy_hal::NAN_MATCH_ALG_MATCH_CONTINUOUS;
+ case NanMatchAlg::MATCH_NEVER:
+ return legacy_hal::NAN_MATCH_ALG_MATCH_NEVER;
+ }
+ CHECK(false);
+}
+
+legacy_hal::NanPublishType convertHidlNanPublishTypeToLegacy(NanPublishType type) {
+ switch (type) {
+ case NanPublishType::UNSOLICITED:
+ return legacy_hal::NAN_PUBLISH_TYPE_UNSOLICITED;
+ case NanPublishType::SOLICITED:
+ return legacy_hal::NAN_PUBLISH_TYPE_SOLICITED;
+ case NanPublishType::UNSOLICITED_SOLICITED:
+ return legacy_hal::NAN_PUBLISH_TYPE_UNSOLICITED_SOLICITED;
+ }
+ CHECK(false);
+}
+
+legacy_hal::NanTxType convertHidlNanTxTypeToLegacy(NanTxType type) {
+ switch (type) {
+ case NanTxType::BROADCAST:
+ return legacy_hal::NAN_TX_TYPE_BROADCAST;
+ case NanTxType::UNICAST:
+ return legacy_hal::NAN_TX_TYPE_UNICAST;
+ }
+ CHECK(false);
+}
+
+legacy_hal::NanSubscribeType convertHidlNanSubscribeTypeToLegacy(NanSubscribeType type) {
+ switch (type) {
+ case NanSubscribeType::PASSIVE:
+ return legacy_hal::NAN_SUBSCRIBE_TYPE_PASSIVE;
+ case NanSubscribeType::ACTIVE:
+ return legacy_hal::NAN_SUBSCRIBE_TYPE_ACTIVE;
+ }
+ CHECK(false);
+}
+
+legacy_hal::NanSRFType convertHidlNanSrfTypeToLegacy(NanSrfType type) {
+ switch (type) {
+ case NanSrfType::BLOOM_FILTER:
+ return legacy_hal::NAN_SRF_ATTR_BLOOM_FILTER;
+ case NanSrfType::PARTIAL_MAC_ADDR:
+ return legacy_hal::NAN_SRF_ATTR_PARTIAL_MAC_ADDR;
+ }
+ CHECK(false);
+}
+
+legacy_hal::NanDataPathChannelCfg convertHidlNanDataPathChannelCfgToLegacy(
+ NanDataPathChannelCfg type) {
+ switch (type) {
+ case NanDataPathChannelCfg::CHANNEL_NOT_REQUESTED:
+ return legacy_hal::NAN_DP_CHANNEL_NOT_REQUESTED;
+ case NanDataPathChannelCfg::REQUEST_CHANNEL_SETUP:
+ return legacy_hal::NAN_DP_REQUEST_CHANNEL_SETUP;
+ case NanDataPathChannelCfg::FORCE_CHANNEL_SETUP:
+ return legacy_hal::NAN_DP_FORCE_CHANNEL_SETUP;
+ }
+ CHECK(false);
+}
+
+NanStatusType convertLegacyNanStatusTypeToHidl(legacy_hal::NanStatusType type) {
+ switch (type) {
+ case legacy_hal::NAN_STATUS_SUCCESS:
+ return NanStatusType::SUCCESS;
+ case legacy_hal::NAN_STATUS_INTERNAL_FAILURE:
+ return NanStatusType::INTERNAL_FAILURE;
+ case legacy_hal::NAN_STATUS_PROTOCOL_FAILURE:
+ return NanStatusType::PROTOCOL_FAILURE;
+ case legacy_hal::NAN_STATUS_INVALID_PUBLISH_SUBSCRIBE_ID:
+ return NanStatusType::INVALID_SESSION_ID;
+ case legacy_hal::NAN_STATUS_NO_RESOURCE_AVAILABLE:
+ return NanStatusType::NO_RESOURCES_AVAILABLE;
+ case legacy_hal::NAN_STATUS_INVALID_PARAM:
+ return NanStatusType::INVALID_ARGS;
+ case legacy_hal::NAN_STATUS_INVALID_REQUESTOR_INSTANCE_ID:
+ return NanStatusType::INVALID_PEER_ID;
+ case legacy_hal::NAN_STATUS_INVALID_NDP_ID:
+ return NanStatusType::INVALID_NDP_ID;
+ case legacy_hal::NAN_STATUS_NAN_NOT_ALLOWED:
+ return NanStatusType::NAN_NOT_ALLOWED;
+ case legacy_hal::NAN_STATUS_NO_OTA_ACK:
+ return NanStatusType::NO_OTA_ACK;
+ case legacy_hal::NAN_STATUS_ALREADY_ENABLED:
+ return NanStatusType::ALREADY_ENABLED;
+ case legacy_hal::NAN_STATUS_FOLLOWUP_QUEUE_FULL:
+ return NanStatusType::FOLLOWUP_TX_QUEUE_FULL;
+ case legacy_hal::NAN_STATUS_UNSUPPORTED_CONCURRENCY_NAN_DISABLED:
+ return NanStatusType::UNSUPPORTED_CONCURRENCY_NAN_DISABLED;
+ }
+ CHECK(false);
+}
+
+void convertToWifiNanStatus(legacy_hal::NanStatusType type, const char* str, size_t max_len,
+ WifiNanStatus* wifiNanStatus) {
+ wifiNanStatus->status = convertLegacyNanStatusTypeToHidl(type);
+ wifiNanStatus->description = safeConvertChar(str, max_len);
+}
+
+bool convertHidlNanEnableRequestToLegacy(const V1_4::NanEnableRequest& hidl_request,
+ legacy_hal::NanEnableRequest* legacy_request) {
+ if (!legacy_request) {
+ LOG(ERROR) << "convertHidlNanEnableRequestToLegacy: null legacy_request";
+ return false;
+ }
+ *legacy_request = {};
+
+ legacy_request->config_2dot4g_support = 1;
+ legacy_request->support_2dot4g_val =
+ hidl_request.operateInBand[(size_t)NanBandIndex::NAN_BAND_24GHZ];
+ legacy_request->config_support_5g = 1;
+ legacy_request->support_5g_val =
+ hidl_request.operateInBand[(size_t)NanBandIndex::NAN_BAND_5GHZ];
+ legacy_request->config_hop_count_limit = 1;
+ legacy_request->hop_count_limit_val = hidl_request.hopCountMax;
+ legacy_request->master_pref = hidl_request.configParams.masterPref;
+ legacy_request->discovery_indication_cfg = 0;
+ legacy_request->discovery_indication_cfg |=
+ hidl_request.configParams.disableDiscoveryAddressChangeIndication ? 0x1 : 0x0;
+ legacy_request->discovery_indication_cfg |=
+ hidl_request.configParams.disableStartedClusterIndication ? 0x2 : 0x0;
+ legacy_request->discovery_indication_cfg |=
+ hidl_request.configParams.disableJoinedClusterIndication ? 0x4 : 0x0;
+ legacy_request->config_sid_beacon = 1;
+ if (hidl_request.configParams.numberOfPublishServiceIdsInBeacon > 127) {
+ LOG(ERROR) << "convertHidlNanEnableRequestToLegacy: "
+ "numberOfPublishServiceIdsInBeacon > 127";
+ return false;
+ }
+ legacy_request->sid_beacon_val =
+ (hidl_request.configParams.includePublishServiceIdsInBeacon ? 0x1 : 0x0) |
+ (hidl_request.configParams.numberOfPublishServiceIdsInBeacon << 1);
+ legacy_request->config_subscribe_sid_beacon = 1;
+ if (hidl_request.configParams.numberOfSubscribeServiceIdsInBeacon > 127) {
+ LOG(ERROR) << "convertHidlNanEnableRequestToLegacy: "
+ "numberOfSubscribeServiceIdsInBeacon > 127";
+ return false;
+ }
+ legacy_request->subscribe_sid_beacon_val =
+ (hidl_request.configParams.includeSubscribeServiceIdsInBeacon ? 0x1 : 0x0) |
+ (hidl_request.configParams.numberOfSubscribeServiceIdsInBeacon << 1);
+ legacy_request->config_rssi_window_size = 1;
+ legacy_request->rssi_window_size_val = hidl_request.configParams.rssiWindowSize;
+ legacy_request->config_disc_mac_addr_randomization = 1;
+ legacy_request->disc_mac_addr_rand_interval_sec =
+ hidl_request.configParams.macAddressRandomizationIntervalSec;
+ legacy_request->config_2dot4g_rssi_close = 1;
+ if (hidl_request.configParams.bandSpecificConfig.size() != 3) {
+ LOG(ERROR) << "convertHidlNanEnableRequestToLegacy: "
+ "bandSpecificConfig.size() != 3";
+ return false;
+ }
+ legacy_request->rssi_close_2dot4g_val =
+ hidl_request.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+ .rssiClose;
+ legacy_request->config_2dot4g_rssi_middle = 1;
+ legacy_request->rssi_middle_2dot4g_val =
+ hidl_request.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+ .rssiMiddle;
+ legacy_request->config_2dot4g_rssi_proximity = 1;
+ legacy_request->rssi_proximity_2dot4g_val =
+ hidl_request.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+ .rssiCloseProximity;
+ legacy_request->config_scan_params = 1;
+ legacy_request->scan_params_val.dwell_time[legacy_hal::NAN_CHANNEL_24G_BAND] =
+ hidl_request.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+ .dwellTimeMs;
+ legacy_request->scan_params_val.scan_period[legacy_hal::NAN_CHANNEL_24G_BAND] =
+ hidl_request.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+ .scanPeriodSec;
+ legacy_request->config_dw.config_2dot4g_dw_band =
+ hidl_request.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+ .validDiscoveryWindowIntervalVal;
+ legacy_request->config_dw.dw_2dot4g_interval_val =
+ hidl_request.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+ .discoveryWindowIntervalVal;
+ legacy_request->config_5g_rssi_close = 1;
+ legacy_request->rssi_close_5g_val =
+ hidl_request.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+ .rssiClose;
+ legacy_request->config_5g_rssi_middle = 1;
+ legacy_request->rssi_middle_5g_val =
+ hidl_request.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+ .rssiMiddle;
+ legacy_request->config_5g_rssi_close_proximity = 1;
+ legacy_request->rssi_close_proximity_5g_val =
+ hidl_request.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+ .rssiCloseProximity;
+ legacy_request->scan_params_val.dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] =
+ hidl_request.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+ .dwellTimeMs;
+ legacy_request->scan_params_val.scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] =
+ hidl_request.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+ .scanPeriodSec;
+ legacy_request->scan_params_val.dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] =
+ hidl_request.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+ .dwellTimeMs;
+ legacy_request->scan_params_val.scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] =
+ hidl_request.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+ .scanPeriodSec;
+ legacy_request->config_dw.config_5g_dw_band =
+ hidl_request.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+ .validDiscoveryWindowIntervalVal;
+ legacy_request->config_dw.dw_5g_interval_val =
+ hidl_request.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+ .discoveryWindowIntervalVal;
+ if (hidl_request.debugConfigs.validClusterIdVals) {
+ legacy_request->cluster_low = hidl_request.debugConfigs.clusterIdBottomRangeVal;
+ legacy_request->cluster_high = hidl_request.debugConfigs.clusterIdTopRangeVal;
+ } else { // need 'else' since not configurable in legacy HAL
+ legacy_request->cluster_low = 0x0000;
+ legacy_request->cluster_high = 0xFFFF;
+ }
+ legacy_request->config_intf_addr = hidl_request.debugConfigs.validIntfAddrVal;
+ memcpy(legacy_request->intf_addr_val, hidl_request.debugConfigs.intfAddrVal.data(), 6);
+ legacy_request->config_oui = hidl_request.debugConfigs.validOuiVal;
+ legacy_request->oui_val = hidl_request.debugConfigs.ouiVal;
+ legacy_request->config_random_factor_force =
+ hidl_request.debugConfigs.validRandomFactorForceVal;
+ legacy_request->random_factor_force_val = hidl_request.debugConfigs.randomFactorForceVal;
+ legacy_request->config_hop_count_force = hidl_request.debugConfigs.validHopCountForceVal;
+ legacy_request->hop_count_force_val = hidl_request.debugConfigs.hopCountForceVal;
+ legacy_request->config_24g_channel = hidl_request.debugConfigs.validDiscoveryChannelVal;
+ legacy_request->channel_24g_val =
+ hidl_request.debugConfigs.discoveryChannelMhzVal[(size_t)NanBandIndex::NAN_BAND_24GHZ];
+ legacy_request->config_5g_channel = hidl_request.debugConfigs.validDiscoveryChannelVal;
+ legacy_request->channel_5g_val =
+ hidl_request.debugConfigs.discoveryChannelMhzVal[(size_t)NanBandIndex::NAN_BAND_5GHZ];
+ legacy_request->config_2dot4g_beacons = hidl_request.debugConfigs.validUseBeaconsInBandVal;
+ legacy_request->beacon_2dot4g_val =
+ hidl_request.debugConfigs.useBeaconsInBandVal[(size_t)NanBandIndex::NAN_BAND_24GHZ];
+ legacy_request->config_5g_beacons = hidl_request.debugConfigs.validUseBeaconsInBandVal;
+ legacy_request->beacon_5g_val =
+ hidl_request.debugConfigs.useBeaconsInBandVal[(size_t)NanBandIndex::NAN_BAND_5GHZ];
+ legacy_request->config_2dot4g_sdf = hidl_request.debugConfigs.validUseSdfInBandVal;
+ legacy_request->sdf_2dot4g_val =
+ hidl_request.debugConfigs.useSdfInBandVal[(size_t)NanBandIndex::NAN_BAND_24GHZ];
+ legacy_request->config_5g_sdf = hidl_request.debugConfigs.validUseSdfInBandVal;
+ legacy_request->sdf_5g_val =
+ hidl_request.debugConfigs.useSdfInBandVal[(size_t)NanBandIndex::NAN_BAND_5GHZ];
+
+ /* TODO: b/145609058
+ * Missing updates needed to legacy_hal::NanEnableRequest and conversion to
+ * it for 6GHz band */
+
+ return true;
+}
+
+bool convertHidlNanEnableRequest_1_6ToLegacy(const V1_4::NanEnableRequest& hidl_request1,
+ const NanConfigRequestSupplemental& hidl_request2,
+ legacy_hal::NanEnableRequest* legacy_request) {
+ if (!legacy_request) {
+ LOG(ERROR) << "convertHidlNanEnableRequest_1_6ToLegacy: null legacy_request";
+ return false;
+ }
+
+ *legacy_request = {};
+ if (!convertHidlNanEnableRequestToLegacy(hidl_request1, legacy_request)) {
+ return false;
+ }
+
+ legacy_request->config_discovery_beacon_int = 1;
+ legacy_request->discovery_beacon_interval = hidl_request2.V1_5.V1_2.discoveryBeaconIntervalMs;
+ legacy_request->config_nss = 1;
+ legacy_request->nss = hidl_request2.V1_5.V1_2.numberOfSpatialStreamsInDiscovery;
+ legacy_request->config_dw_early_termination = 1;
+ legacy_request->enable_dw_termination =
+ hidl_request2.V1_5.V1_2.enableDiscoveryWindowEarlyTermination;
+ legacy_request->config_enable_ranging = 1;
+ legacy_request->enable_ranging = hidl_request2.V1_5.V1_2.enableRanging;
+
+ legacy_request->config_enable_instant_mode = 1;
+ legacy_request->enable_instant_mode = hidl_request2.V1_5.enableInstantCommunicationMode;
+ legacy_request->config_instant_mode_channel = 1;
+ legacy_request->instant_mode_channel = hidl_request2.instantModeChannel;
+
+ return true;
+}
+
+bool convertHidlNanConfigRequest_1_6ToLegacy(const V1_4::NanConfigRequest& hidl_request1,
+ const NanConfigRequestSupplemental& hidl_request2,
+ legacy_hal::NanConfigRequest* legacy_request) {
+ if (!legacy_request) {
+ LOG(ERROR) << "convertHidlNanConfigRequest_1_6ToLegacy: null legacy_request";
+ return false;
+ }
+
+ *legacy_request = {};
+ if (!convertHidlNanConfigRequestToLegacy(hidl_request1, legacy_request)) {
+ return false;
+ }
+
+ legacy_request->config_discovery_beacon_int = 1;
+ legacy_request->discovery_beacon_interval = hidl_request2.V1_5.V1_2.discoveryBeaconIntervalMs;
+ legacy_request->config_nss = 1;
+ legacy_request->nss = hidl_request2.V1_5.V1_2.numberOfSpatialStreamsInDiscovery;
+ legacy_request->config_dw_early_termination = 1;
+ legacy_request->enable_dw_termination =
+ hidl_request2.V1_5.V1_2.enableDiscoveryWindowEarlyTermination;
+ legacy_request->config_enable_ranging = 1;
+ legacy_request->enable_ranging = hidl_request2.V1_5.V1_2.enableRanging;
+
+ legacy_request->config_enable_instant_mode = 1;
+ legacy_request->enable_instant_mode = hidl_request2.V1_5.enableInstantCommunicationMode;
+ legacy_request->config_instant_mode_channel = 1;
+ legacy_request->instant_mode_channel = hidl_request2.instantModeChannel;
+
+ return true;
+}
+
+bool convertHidlNanPublishRequestToLegacy(const V1_6::NanPublishRequest& hidl_request,
+ legacy_hal::NanPublishRequest* legacy_request) {
+ if (!legacy_request) {
+ LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: null legacy_request";
+ return false;
+ }
+ *legacy_request = {};
+
+ legacy_request->publish_id = hidl_request.baseConfigs.sessionId;
+ legacy_request->ttl = hidl_request.baseConfigs.ttlSec;
+ legacy_request->period = hidl_request.baseConfigs.discoveryWindowPeriod;
+ legacy_request->publish_count = hidl_request.baseConfigs.discoveryCount;
+ legacy_request->service_name_len = hidl_request.baseConfigs.serviceName.size();
+ if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
+ LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: service_name_len "
+ "too large";
+ return false;
+ }
+ memcpy(legacy_request->service_name, hidl_request.baseConfigs.serviceName.data(),
+ legacy_request->service_name_len);
+ legacy_request->publish_match_indicator =
+ convertHidlNanMatchAlgToLegacy(hidl_request.baseConfigs.discoveryMatchIndicator);
+ legacy_request->service_specific_info_len = hidl_request.baseConfigs.serviceSpecificInfo.size();
+ if (legacy_request->service_specific_info_len > NAN_MAX_SERVICE_SPECIFIC_INFO_LEN) {
+ LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
+ "service_specific_info_len too large";
+ return false;
+ }
+ memcpy(legacy_request->service_specific_info,
+ hidl_request.baseConfigs.serviceSpecificInfo.data(),
+ legacy_request->service_specific_info_len);
+ legacy_request->sdea_service_specific_info_len =
+ hidl_request.baseConfigs.extendedServiceSpecificInfo.size();
+ if (legacy_request->sdea_service_specific_info_len > NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN) {
+ LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
+ "sdea_service_specific_info_len too large";
+ return false;
+ }
+ memcpy(legacy_request->sdea_service_specific_info,
+ hidl_request.baseConfigs.extendedServiceSpecificInfo.data(),
+ legacy_request->sdea_service_specific_info_len);
+ legacy_request->rx_match_filter_len = hidl_request.baseConfigs.rxMatchFilter.size();
+ if (legacy_request->rx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) {
+ LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
+ "rx_match_filter_len too large";
+ return false;
+ }
+ memcpy(legacy_request->rx_match_filter, hidl_request.baseConfigs.rxMatchFilter.data(),
+ legacy_request->rx_match_filter_len);
+ legacy_request->tx_match_filter_len = hidl_request.baseConfigs.txMatchFilter.size();
+ if (legacy_request->tx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) {
+ LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
+ "tx_match_filter_len too large";
+ return false;
+ }
+ memcpy(legacy_request->tx_match_filter, hidl_request.baseConfigs.txMatchFilter.data(),
+ legacy_request->tx_match_filter_len);
+ legacy_request->rssi_threshold_flag = hidl_request.baseConfigs.useRssiThreshold;
+ legacy_request->recv_indication_cfg = 0;
+ legacy_request->recv_indication_cfg |=
+ hidl_request.baseConfigs.disableDiscoveryTerminationIndication ? 0x1 : 0x0;
+ legacy_request->recv_indication_cfg |=
+ hidl_request.baseConfigs.disableMatchExpirationIndication ? 0x2 : 0x0;
+ legacy_request->recv_indication_cfg |=
+ hidl_request.baseConfigs.disableFollowupReceivedIndication ? 0x4 : 0x0;
+ legacy_request->recv_indication_cfg |= 0x8;
+ legacy_request->cipher_type = (unsigned int)hidl_request.baseConfigs.securityConfig.cipherType;
+
+ legacy_request->scid_len = hidl_request.baseConfigs.securityConfig.scid.size();
+ if (legacy_request->scid_len > NAN_MAX_SCID_BUF_LEN) {
+ LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: scid_len too large";
+ return false;
+ }
+ memcpy(legacy_request->scid, hidl_request.baseConfigs.securityConfig.scid.data(),
+ legacy_request->scid_len);
+
+ if (hidl_request.baseConfigs.securityConfig.securityType == NanDataPathSecurityType::PMK) {
+ legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
+ legacy_request->key_info.body.pmk_info.pmk_len =
+ hidl_request.baseConfigs.securityConfig.pmk.size();
+ if (legacy_request->key_info.body.pmk_info.pmk_len != NAN_PMK_INFO_LEN) {
+ LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: invalid pmk_len";
+ return false;
+ }
+ memcpy(legacy_request->key_info.body.pmk_info.pmk,
+ hidl_request.baseConfigs.securityConfig.pmk.data(),
+ legacy_request->key_info.body.pmk_info.pmk_len);
+ }
+ if (hidl_request.baseConfigs.securityConfig.securityType ==
+ NanDataPathSecurityType::PASSPHRASE) {
+ legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
+ legacy_request->key_info.body.passphrase_info.passphrase_len =
+ hidl_request.baseConfigs.securityConfig.passphrase.size();
+ if (legacy_request->key_info.body.passphrase_info.passphrase_len <
+ NAN_SECURITY_MIN_PASSPHRASE_LEN) {
+ LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
+ "passphrase_len too small";
+ return false;
+ }
+ if (legacy_request->key_info.body.passphrase_info.passphrase_len >
+ NAN_SECURITY_MAX_PASSPHRASE_LEN) {
+ LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
+ "passphrase_len too large";
+ return false;
+ }
+ memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
+ hidl_request.baseConfigs.securityConfig.passphrase.data(),
+ legacy_request->key_info.body.passphrase_info.passphrase_len);
+ }
+ legacy_request->sdea_params.security_cfg =
+ (hidl_request.baseConfigs.securityConfig.securityType != NanDataPathSecurityType::OPEN)
+ ? legacy_hal::NAN_DP_CONFIG_SECURITY
+ : legacy_hal::NAN_DP_CONFIG_NO_SECURITY;
+
+ legacy_request->sdea_params.ranging_state = hidl_request.baseConfigs.rangingRequired
+ ? legacy_hal::NAN_RANGING_ENABLE
+ : legacy_hal::NAN_RANGING_DISABLE;
+ legacy_request->ranging_cfg.ranging_interval_msec =
+ hidl_request.baseConfigs.rangingIntervalMsec;
+ legacy_request->ranging_cfg.config_ranging_indications =
+ hidl_request.baseConfigs.configRangingIndications;
+ legacy_request->ranging_cfg.distance_ingress_mm =
+ hidl_request.baseConfigs.distanceIngressCm * 10;
+ legacy_request->ranging_cfg.distance_egress_mm = hidl_request.baseConfigs.distanceEgressCm * 10;
+ legacy_request->ranging_auto_response = hidl_request.baseConfigs.rangingRequired
+ ? legacy_hal::NAN_RANGING_AUTO_RESPONSE_ENABLE
+ : legacy_hal::NAN_RANGING_AUTO_RESPONSE_DISABLE;
+ legacy_request->sdea_params.range_report = legacy_hal::NAN_DISABLE_RANGE_REPORT;
+ legacy_request->publish_type = convertHidlNanPublishTypeToLegacy(hidl_request.publishType);
+ legacy_request->tx_type = convertHidlNanTxTypeToLegacy(hidl_request.txType);
+ legacy_request->service_responder_policy = hidl_request.autoAcceptDataPathRequests
+ ? legacy_hal::NAN_SERVICE_ACCEPT_POLICY_ALL
+ : legacy_hal::NAN_SERVICE_ACCEPT_POLICY_NONE;
+
+ return true;
+}
+
+bool convertHidlNanSubscribeRequestToLegacy(const V1_0::NanSubscribeRequest& hidl_request,
+ legacy_hal::NanSubscribeRequest* legacy_request) {
+ if (!legacy_request) {
+ LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: legacy_request is null";
+ return false;
+ }
+ *legacy_request = {};
+
+ legacy_request->subscribe_id = hidl_request.baseConfigs.sessionId;
+ legacy_request->ttl = hidl_request.baseConfigs.ttlSec;
+ legacy_request->period = hidl_request.baseConfigs.discoveryWindowPeriod;
+ legacy_request->subscribe_count = hidl_request.baseConfigs.discoveryCount;
+ legacy_request->service_name_len = hidl_request.baseConfigs.serviceName.size();
+ if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
+ LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
+ "service_name_len too large";
+ return false;
+ }
+ memcpy(legacy_request->service_name, hidl_request.baseConfigs.serviceName.data(),
+ legacy_request->service_name_len);
+ legacy_request->subscribe_match_indicator =
+ convertHidlNanMatchAlgToLegacy(hidl_request.baseConfigs.discoveryMatchIndicator);
+ legacy_request->service_specific_info_len = hidl_request.baseConfigs.serviceSpecificInfo.size();
+ if (legacy_request->service_specific_info_len > NAN_MAX_SERVICE_SPECIFIC_INFO_LEN) {
+ LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
+ "service_specific_info_len too large";
+ return false;
+ }
+ memcpy(legacy_request->service_specific_info,
+ hidl_request.baseConfigs.serviceSpecificInfo.data(),
+ legacy_request->service_specific_info_len);
+ legacy_request->sdea_service_specific_info_len =
+ hidl_request.baseConfigs.extendedServiceSpecificInfo.size();
+ if (legacy_request->sdea_service_specific_info_len > NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN) {
+ LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
+ "sdea_service_specific_info_len too large";
+ return false;
+ }
+ memcpy(legacy_request->sdea_service_specific_info,
+ hidl_request.baseConfigs.extendedServiceSpecificInfo.data(),
+ legacy_request->sdea_service_specific_info_len);
+ legacy_request->rx_match_filter_len = hidl_request.baseConfigs.rxMatchFilter.size();
+ if (legacy_request->rx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) {
+ LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
+ "rx_match_filter_len too large";
+ return false;
+ }
+ memcpy(legacy_request->rx_match_filter, hidl_request.baseConfigs.rxMatchFilter.data(),
+ legacy_request->rx_match_filter_len);
+ legacy_request->tx_match_filter_len = hidl_request.baseConfigs.txMatchFilter.size();
+ if (legacy_request->tx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) {
+ LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
+ "tx_match_filter_len too large";
+ return false;
+ }
+ memcpy(legacy_request->tx_match_filter, hidl_request.baseConfigs.txMatchFilter.data(),
+ legacy_request->tx_match_filter_len);
+ legacy_request->rssi_threshold_flag = hidl_request.baseConfigs.useRssiThreshold;
+ legacy_request->recv_indication_cfg = 0;
+ legacy_request->recv_indication_cfg |=
+ hidl_request.baseConfigs.disableDiscoveryTerminationIndication ? 0x1 : 0x0;
+ legacy_request->recv_indication_cfg |=
+ hidl_request.baseConfigs.disableMatchExpirationIndication ? 0x2 : 0x0;
+ legacy_request->recv_indication_cfg |=
+ hidl_request.baseConfigs.disableFollowupReceivedIndication ? 0x4 : 0x0;
+ legacy_request->cipher_type = (unsigned int)hidl_request.baseConfigs.securityConfig.cipherType;
+ if (hidl_request.baseConfigs.securityConfig.securityType == NanDataPathSecurityType::PMK) {
+ legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
+ legacy_request->key_info.body.pmk_info.pmk_len =
+ hidl_request.baseConfigs.securityConfig.pmk.size();
+ if (legacy_request->key_info.body.pmk_info.pmk_len != NAN_PMK_INFO_LEN) {
+ LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: invalid pmk_len";
+ return false;
+ }
+ memcpy(legacy_request->key_info.body.pmk_info.pmk,
+ hidl_request.baseConfigs.securityConfig.pmk.data(),
+ legacy_request->key_info.body.pmk_info.pmk_len);
+ }
+ if (hidl_request.baseConfigs.securityConfig.securityType ==
+ NanDataPathSecurityType::PASSPHRASE) {
+ legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
+ legacy_request->key_info.body.passphrase_info.passphrase_len =
+ hidl_request.baseConfigs.securityConfig.passphrase.size();
+ if (legacy_request->key_info.body.passphrase_info.passphrase_len <
+ NAN_SECURITY_MIN_PASSPHRASE_LEN) {
+ LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
+ "passphrase_len too small";
+ return false;
+ }
+ if (legacy_request->key_info.body.passphrase_info.passphrase_len >
+ NAN_SECURITY_MAX_PASSPHRASE_LEN) {
+ LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
+ "passphrase_len too large";
+ return false;
+ }
+ memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
+ hidl_request.baseConfigs.securityConfig.passphrase.data(),
+ legacy_request->key_info.body.passphrase_info.passphrase_len);
+ }
+ legacy_request->sdea_params.security_cfg =
+ (hidl_request.baseConfigs.securityConfig.securityType != NanDataPathSecurityType::OPEN)
+ ? legacy_hal::NAN_DP_CONFIG_SECURITY
+ : legacy_hal::NAN_DP_CONFIG_NO_SECURITY;
+ legacy_request->sdea_params.ranging_state = hidl_request.baseConfigs.rangingRequired
+ ? legacy_hal::NAN_RANGING_ENABLE
+ : legacy_hal::NAN_RANGING_DISABLE;
+ legacy_request->ranging_cfg.ranging_interval_msec =
+ hidl_request.baseConfigs.rangingIntervalMsec;
+ legacy_request->ranging_cfg.config_ranging_indications =
+ hidl_request.baseConfigs.configRangingIndications;
+ legacy_request->ranging_cfg.distance_ingress_mm =
+ hidl_request.baseConfigs.distanceIngressCm * 10;
+ legacy_request->ranging_cfg.distance_egress_mm = hidl_request.baseConfigs.distanceEgressCm * 10;
+ legacy_request->ranging_auto_response = hidl_request.baseConfigs.rangingRequired
+ ? legacy_hal::NAN_RANGING_AUTO_RESPONSE_ENABLE
+ : legacy_hal::NAN_RANGING_AUTO_RESPONSE_DISABLE;
+ legacy_request->sdea_params.range_report = legacy_hal::NAN_DISABLE_RANGE_REPORT;
+ legacy_request->subscribe_type =
+ convertHidlNanSubscribeTypeToLegacy(hidl_request.subscribeType);
+ legacy_request->serviceResponseFilter = convertHidlNanSrfTypeToLegacy(hidl_request.srfType);
+ legacy_request->serviceResponseInclude = hidl_request.srfRespondIfInAddressSet
+ ? legacy_hal::NAN_SRF_INCLUDE_RESPOND
+ : legacy_hal::NAN_SRF_INCLUDE_DO_NOT_RESPOND;
+ legacy_request->useServiceResponseFilter =
+ hidl_request.shouldUseSrf ? legacy_hal::NAN_USE_SRF : legacy_hal::NAN_DO_NOT_USE_SRF;
+ legacy_request->ssiRequiredForMatchIndication =
+ hidl_request.isSsiRequiredForMatch ? legacy_hal::NAN_SSI_REQUIRED_IN_MATCH_IND
+ : legacy_hal::NAN_SSI_NOT_REQUIRED_IN_MATCH_IND;
+ legacy_request->num_intf_addr_present = hidl_request.intfAddr.size();
+ if (legacy_request->num_intf_addr_present > NAN_MAX_SUBSCRIBE_MAX_ADDRESS) {
+ LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
+ "num_intf_addr_present - too many";
+ return false;
+ }
+ for (int i = 0; i < legacy_request->num_intf_addr_present; i++) {
+ memcpy(legacy_request->intf_addr[i], hidl_request.intfAddr[i].data(), 6);
+ }
+
+ return true;
+}
+
+bool convertHidlNanTransmitFollowupRequestToLegacy(
+ const NanTransmitFollowupRequest& hidl_request,
+ legacy_hal::NanTransmitFollowupRequest* legacy_request) {
+ if (!legacy_request) {
+ LOG(ERROR) << "convertHidlNanTransmitFollowupRequestToLegacy: "
+ "legacy_request is null";
+ return false;
+ }
+ *legacy_request = {};
+
+ legacy_request->publish_subscribe_id = hidl_request.discoverySessionId;
+ legacy_request->requestor_instance_id = hidl_request.peerId;
+ memcpy(legacy_request->addr, hidl_request.addr.data(), 6);
+ legacy_request->priority = hidl_request.isHighPriority ? legacy_hal::NAN_TX_PRIORITY_HIGH
+ : legacy_hal::NAN_TX_PRIORITY_NORMAL;
+ legacy_request->dw_or_faw = hidl_request.shouldUseDiscoveryWindow
+ ? legacy_hal::NAN_TRANSMIT_IN_DW
+ : legacy_hal::NAN_TRANSMIT_IN_FAW;
+ legacy_request->service_specific_info_len = hidl_request.serviceSpecificInfo.size();
+ if (legacy_request->service_specific_info_len > NAN_MAX_SERVICE_SPECIFIC_INFO_LEN) {
+ LOG(ERROR) << "convertHidlNanTransmitFollowupRequestToLegacy: "
+ "service_specific_info_len too large";
+ return false;
+ }
+ memcpy(legacy_request->service_specific_info, hidl_request.serviceSpecificInfo.data(),
+ legacy_request->service_specific_info_len);
+ legacy_request->sdea_service_specific_info_len =
+ hidl_request.extendedServiceSpecificInfo.size();
+ if (legacy_request->sdea_service_specific_info_len > NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN) {
+ LOG(ERROR) << "convertHidlNanTransmitFollowupRequestToLegacy: "
+ "sdea_service_specific_info_len too large";
+ return false;
+ }
+ memcpy(legacy_request->sdea_service_specific_info,
+ hidl_request.extendedServiceSpecificInfo.data(),
+ legacy_request->sdea_service_specific_info_len);
+ legacy_request->recv_indication_cfg = hidl_request.disableFollowupResultIndication ? 0x1 : 0x0;
+
+ return true;
+}
+
+bool convertHidlNanConfigRequestToLegacy(const V1_4::NanConfigRequest& hidl_request,
+ legacy_hal::NanConfigRequest* legacy_request) {
+ if (!legacy_request) {
+ LOG(ERROR) << "convertHidlNanConfigRequestToLegacy: legacy_request is null";
+ return false;
+ }
+ *legacy_request = {};
+
+ // TODO: b/34059183 tracks missing configurations in legacy HAL or uknown
+ // defaults
+ legacy_request->master_pref = hidl_request.masterPref;
+ legacy_request->discovery_indication_cfg = 0;
+ legacy_request->discovery_indication_cfg |=
+ hidl_request.disableDiscoveryAddressChangeIndication ? 0x1 : 0x0;
+ legacy_request->discovery_indication_cfg |=
+ hidl_request.disableStartedClusterIndication ? 0x2 : 0x0;
+ legacy_request->discovery_indication_cfg |=
+ hidl_request.disableJoinedClusterIndication ? 0x4 : 0x0;
+ legacy_request->config_sid_beacon = 1;
+ if (hidl_request.numberOfPublishServiceIdsInBeacon > 127) {
+ LOG(ERROR) << "convertHidlNanConfigRequestToLegacy: "
+ "numberOfPublishServiceIdsInBeacon > 127";
+ return false;
+ }
+ legacy_request->sid_beacon = (hidl_request.includePublishServiceIdsInBeacon ? 0x1 : 0x0) |
+ (hidl_request.numberOfPublishServiceIdsInBeacon << 1);
+ legacy_request->config_subscribe_sid_beacon = 1;
+ if (hidl_request.numberOfSubscribeServiceIdsInBeacon > 127) {
+ LOG(ERROR) << "convertHidlNanConfigRequestToLegacy: "
+ "numberOfSubscribeServiceIdsInBeacon > 127";
+ return false;
+ }
+ legacy_request->subscribe_sid_beacon_val =
+ (hidl_request.includeSubscribeServiceIdsInBeacon ? 0x1 : 0x0) |
+ (hidl_request.numberOfSubscribeServiceIdsInBeacon << 1);
+ legacy_request->config_rssi_window_size = 1;
+ legacy_request->rssi_window_size_val = hidl_request.rssiWindowSize;
+ legacy_request->config_disc_mac_addr_randomization = 1;
+ legacy_request->disc_mac_addr_rand_interval_sec =
+ hidl_request.macAddressRandomizationIntervalSec;
+ /* TODO : missing
+ legacy_request->config_2dot4g_rssi_close = 1;
+ legacy_request->rssi_close_2dot4g_val =
+ hidl_request.bandSpecificConfig[
+ (size_t) NanBandIndex::NAN_BAND_24GHZ].rssiClose;
+ legacy_request->config_2dot4g_rssi_middle = 1;
+ legacy_request->rssi_middle_2dot4g_val =
+ hidl_request.bandSpecificConfig[
+ (size_t) NanBandIndex::NAN_BAND_24GHZ].rssiMiddle;
+ legacy_request->config_2dot4g_rssi_proximity = 1;
+ legacy_request->rssi_proximity_2dot4g_val =
+ hidl_request.bandSpecificConfig[
+ (size_t) NanBandIndex::NAN_BAND_24GHZ].rssiCloseProximity;
+ */
+ legacy_request->config_scan_params = 1;
+ legacy_request->scan_params_val.dwell_time[legacy_hal::NAN_CHANNEL_24G_BAND] =
+ hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ].dwellTimeMs;
+ legacy_request->scan_params_val.scan_period[legacy_hal::NAN_CHANNEL_24G_BAND] =
+ hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ].scanPeriodSec;
+ legacy_request->config_dw.config_2dot4g_dw_band =
+ hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+ .validDiscoveryWindowIntervalVal;
+ legacy_request->config_dw.dw_2dot4g_interval_val =
+ hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+ .discoveryWindowIntervalVal;
+ /* TODO: missing
+ legacy_request->config_5g_rssi_close = 1;
+ legacy_request->rssi_close_5g_val =
+ hidl_request.bandSpecificConfig[
+ (size_t) NanBandIndex::NAN_BAND_5GHZ].rssiClose;
+ legacy_request->config_5g_rssi_middle = 1;
+ legacy_request->rssi_middle_5g_val =
+ hidl_request.bandSpecificConfig[
+ (size_t) NanBandIndex::NAN_BAND_5GHZ].rssiMiddle;
+ */
+ legacy_request->config_5g_rssi_close_proximity = 1;
+ legacy_request->rssi_close_proximity_5g_val =
+ hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ].rssiCloseProximity;
+ legacy_request->scan_params_val.dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] =
+ hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ].dwellTimeMs;
+ legacy_request->scan_params_val.scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] =
+ hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ].scanPeriodSec;
+ legacy_request->scan_params_val.dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] =
+ hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ].dwellTimeMs;
+ legacy_request->scan_params_val.scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] =
+ hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ].scanPeriodSec;
+ legacy_request->config_dw.config_5g_dw_band =
+ hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+ .validDiscoveryWindowIntervalVal;
+ legacy_request->config_dw.dw_5g_interval_val =
+ hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+ .discoveryWindowIntervalVal;
+ /* TODO: b/145609058
+ * Missing updates needed to legacy_hal::NanConfigRequest and conversion to
+ * it for 6GHz band */
+
+ return true;
+}
+
+bool convertHidlNanDataPathInitiatorRequestToLegacy(
+ const V1_0::NanInitiateDataPathRequest& hidl_request,
+ legacy_hal::NanDataPathInitiatorRequest* legacy_request) {
+ if (!legacy_request) {
+ LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
+ "legacy_request is null";
+ return false;
+ }
+ *legacy_request = {};
+
+ legacy_request->requestor_instance_id = hidl_request.peerId;
+ memcpy(legacy_request->peer_disc_mac_addr, hidl_request.peerDiscMacAddr.data(), 6);
+ legacy_request->channel_request_type =
+ convertHidlNanDataPathChannelCfgToLegacy(hidl_request.channelRequestType);
+ legacy_request->channel = hidl_request.channel;
+ if (strnlen(hidl_request.ifaceName.c_str(), IFNAMSIZ + 1) == IFNAMSIZ + 1) {
+ LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
+ "ifaceName too long";
+ return false;
+ }
+ strlcpy(legacy_request->ndp_iface, hidl_request.ifaceName.c_str(), IFNAMSIZ + 1);
+ legacy_request->ndp_cfg.security_cfg =
+ (hidl_request.securityConfig.securityType != NanDataPathSecurityType::OPEN)
+ ? legacy_hal::NAN_DP_CONFIG_SECURITY
+ : legacy_hal::NAN_DP_CONFIG_NO_SECURITY;
+ legacy_request->app_info.ndp_app_info_len = hidl_request.appInfo.size();
+ if (legacy_request->app_info.ndp_app_info_len > NAN_DP_MAX_APP_INFO_LEN) {
+ LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
+ "ndp_app_info_len too large";
+ return false;
+ }
+ memcpy(legacy_request->app_info.ndp_app_info, hidl_request.appInfo.data(),
+ legacy_request->app_info.ndp_app_info_len);
+ legacy_request->cipher_type = (unsigned int)hidl_request.securityConfig.cipherType;
+ if (hidl_request.securityConfig.securityType == NanDataPathSecurityType::PMK) {
+ legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
+ legacy_request->key_info.body.pmk_info.pmk_len = hidl_request.securityConfig.pmk.size();
+ if (legacy_request->key_info.body.pmk_info.pmk_len != NAN_PMK_INFO_LEN) {
+ LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
+ "invalid pmk_len";
+ return false;
+ }
+ memcpy(legacy_request->key_info.body.pmk_info.pmk, hidl_request.securityConfig.pmk.data(),
+ legacy_request->key_info.body.pmk_info.pmk_len);
+ }
+ if (hidl_request.securityConfig.securityType == NanDataPathSecurityType::PASSPHRASE) {
+ legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
+ legacy_request->key_info.body.passphrase_info.passphrase_len =
+ hidl_request.securityConfig.passphrase.size();
+ if (legacy_request->key_info.body.passphrase_info.passphrase_len <
+ NAN_SECURITY_MIN_PASSPHRASE_LEN) {
+ LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
+ "passphrase_len too small";
+ return false;
+ }
+ if (legacy_request->key_info.body.passphrase_info.passphrase_len >
+ NAN_SECURITY_MAX_PASSPHRASE_LEN) {
+ LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
+ "passphrase_len too large";
+ return false;
+ }
+ memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
+ hidl_request.securityConfig.passphrase.data(),
+ legacy_request->key_info.body.passphrase_info.passphrase_len);
+ }
+ legacy_request->service_name_len = hidl_request.serviceNameOutOfBand.size();
+ if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
+ LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
+ "service_name_len too large";
+ return false;
+ }
+ memcpy(legacy_request->service_name, hidl_request.serviceNameOutOfBand.data(),
+ legacy_request->service_name_len);
+
+ return true;
+}
+
+bool convertHidlNanDataPathInitiatorRequest_1_6ToLegacy(
+ const V1_6::NanInitiateDataPathRequest& hidl_request,
+ legacy_hal::NanDataPathInitiatorRequest* legacy_request) {
+ if (!legacy_request) {
+ LOG(ERROR) << "convertHidlNanDataPathInitiatorRequest_1_6ToLegacy: "
+ "legacy_request is null";
+ return false;
+ }
+ *legacy_request = {};
+
+ legacy_request->requestor_instance_id = hidl_request.peerId;
+ memcpy(legacy_request->peer_disc_mac_addr, hidl_request.peerDiscMacAddr.data(), 6);
+ legacy_request->channel_request_type =
+ convertHidlNanDataPathChannelCfgToLegacy(hidl_request.channelRequestType);
+ legacy_request->channel = hidl_request.channel;
+ if (strnlen(hidl_request.ifaceName.c_str(), IFNAMSIZ + 1) == IFNAMSIZ + 1) {
+ LOG(ERROR) << "convertHidlNanDataPathInitiatorRequest_1_6ToLegacy: "
+ "ifaceName too long";
+ return false;
+ }
+ strlcpy(legacy_request->ndp_iface, hidl_request.ifaceName.c_str(), IFNAMSIZ + 1);
+ legacy_request->ndp_cfg.security_cfg =
+ (hidl_request.securityConfig.securityType != NanDataPathSecurityType::OPEN)
+ ? legacy_hal::NAN_DP_CONFIG_SECURITY
+ : legacy_hal::NAN_DP_CONFIG_NO_SECURITY;
+ legacy_request->app_info.ndp_app_info_len = hidl_request.appInfo.size();
+ if (legacy_request->app_info.ndp_app_info_len > NAN_DP_MAX_APP_INFO_LEN) {
+ LOG(ERROR) << "convertHidlNanDataPathInitiatorRequest_1_6ToLegacy: "
+ "ndp_app_info_len too large";
+ return false;
+ }
+ memcpy(legacy_request->app_info.ndp_app_info, hidl_request.appInfo.data(),
+ legacy_request->app_info.ndp_app_info_len);
+ legacy_request->cipher_type = (unsigned int)hidl_request.securityConfig.cipherType;
+ if (hidl_request.securityConfig.securityType == NanDataPathSecurityType::PMK) {
+ legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
+ legacy_request->key_info.body.pmk_info.pmk_len = hidl_request.securityConfig.pmk.size();
+ if (legacy_request->key_info.body.pmk_info.pmk_len != NAN_PMK_INFO_LEN) {
+ LOG(ERROR) << "convertHidlNanDataPathInitiatorRequest_1_6ToLegacy: "
+ "invalid pmk_len";
+ return false;
+ }
+ memcpy(legacy_request->key_info.body.pmk_info.pmk, hidl_request.securityConfig.pmk.data(),
+ legacy_request->key_info.body.pmk_info.pmk_len);
+ }
+ if (hidl_request.securityConfig.securityType == NanDataPathSecurityType::PASSPHRASE) {
+ legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
+ legacy_request->key_info.body.passphrase_info.passphrase_len =
+ hidl_request.securityConfig.passphrase.size();
+ if (legacy_request->key_info.body.passphrase_info.passphrase_len <
+ NAN_SECURITY_MIN_PASSPHRASE_LEN) {
+ LOG(ERROR) << "convertHidlNanDataPathInitiatorRequest_1_6ToLegacy: "
+ "passphrase_len too small";
+ return false;
+ }
+ if (legacy_request->key_info.body.passphrase_info.passphrase_len >
+ NAN_SECURITY_MAX_PASSPHRASE_LEN) {
+ LOG(ERROR) << "convertHidlNanDataPathInitiatorRequest_1_6ToLegacy: "
+ "passphrase_len too large";
+ return false;
+ }
+ memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
+ hidl_request.securityConfig.passphrase.data(),
+ legacy_request->key_info.body.passphrase_info.passphrase_len);
+ }
+ legacy_request->service_name_len = hidl_request.serviceNameOutOfBand.size();
+ if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
+ LOG(ERROR) << "convertHidlNanDataPathInitiatorRequest_1_6ToLegacy: "
+ "service_name_len too large";
+ return false;
+ }
+ memcpy(legacy_request->service_name, hidl_request.serviceNameOutOfBand.data(),
+ legacy_request->service_name_len);
+ legacy_request->scid_len = hidl_request.securityConfig.scid.size();
+ if (legacy_request->scid_len > NAN_MAX_SCID_BUF_LEN) {
+ LOG(ERROR) << "convertHidlNanDataPathInitiatorRequest_1_6ToLegacy: scid_len too large";
+ return false;
+ }
+ memcpy(legacy_request->scid, hidl_request.securityConfig.scid.data(), legacy_request->scid_len);
+
+ return true;
+}
+
+bool convertHidlNanDataPathIndicationResponseToLegacy(
+ const V1_0::NanRespondToDataPathIndicationRequest& hidl_request,
+ legacy_hal::NanDataPathIndicationResponse* legacy_request) {
+ if (!legacy_request) {
+ LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
+ "legacy_request is null";
+ return false;
+ }
+ *legacy_request = {};
+
+ legacy_request->rsp_code = hidl_request.acceptRequest ? legacy_hal::NAN_DP_REQUEST_ACCEPT
+ : legacy_hal::NAN_DP_REQUEST_REJECT;
+ legacy_request->ndp_instance_id = hidl_request.ndpInstanceId;
+ if (strnlen(hidl_request.ifaceName.c_str(), IFNAMSIZ + 1) == IFNAMSIZ + 1) {
+ LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
+ "ifaceName too long";
+ return false;
+ }
+ strlcpy(legacy_request->ndp_iface, hidl_request.ifaceName.c_str(), IFNAMSIZ + 1);
+ legacy_request->ndp_cfg.security_cfg =
+ (hidl_request.securityConfig.securityType != NanDataPathSecurityType::OPEN)
+ ? legacy_hal::NAN_DP_CONFIG_SECURITY
+ : legacy_hal::NAN_DP_CONFIG_NO_SECURITY;
+ legacy_request->app_info.ndp_app_info_len = hidl_request.appInfo.size();
+ if (legacy_request->app_info.ndp_app_info_len > NAN_DP_MAX_APP_INFO_LEN) {
+ LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
+ "ndp_app_info_len too large";
+ return false;
+ }
+ memcpy(legacy_request->app_info.ndp_app_info, hidl_request.appInfo.data(),
+ legacy_request->app_info.ndp_app_info_len);
+ legacy_request->cipher_type = (unsigned int)hidl_request.securityConfig.cipherType;
+ if (hidl_request.securityConfig.securityType == NanDataPathSecurityType::PMK) {
+ legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
+ legacy_request->key_info.body.pmk_info.pmk_len = hidl_request.securityConfig.pmk.size();
+ if (legacy_request->key_info.body.pmk_info.pmk_len != NAN_PMK_INFO_LEN) {
+ LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
+ "invalid pmk_len";
+ return false;
+ }
+ memcpy(legacy_request->key_info.body.pmk_info.pmk, hidl_request.securityConfig.pmk.data(),
+ legacy_request->key_info.body.pmk_info.pmk_len);
+ }
+ if (hidl_request.securityConfig.securityType == NanDataPathSecurityType::PASSPHRASE) {
+ legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
+ legacy_request->key_info.body.passphrase_info.passphrase_len =
+ hidl_request.securityConfig.passphrase.size();
+ if (legacy_request->key_info.body.passphrase_info.passphrase_len <
+ NAN_SECURITY_MIN_PASSPHRASE_LEN) {
+ LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
+ "passphrase_len too small";
+ return false;
+ }
+ if (legacy_request->key_info.body.passphrase_info.passphrase_len >
+ NAN_SECURITY_MAX_PASSPHRASE_LEN) {
+ LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
+ "passphrase_len too large";
+ return false;
+ }
+ memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
+ hidl_request.securityConfig.passphrase.data(),
+ legacy_request->key_info.body.passphrase_info.passphrase_len);
+ }
+ legacy_request->service_name_len = hidl_request.serviceNameOutOfBand.size();
+ if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
+ LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
+ "service_name_len too large";
+ return false;
+ }
+ memcpy(legacy_request->service_name, hidl_request.serviceNameOutOfBand.data(),
+ legacy_request->service_name_len);
+
+ return true;
+}
+
+bool convertHidlNanDataPathIndicationResponse_1_6ToLegacy(
+ const V1_6::NanRespondToDataPathIndicationRequest& hidl_request,
+ legacy_hal::NanDataPathIndicationResponse* legacy_request) {
+ if (!legacy_request) {
+ LOG(ERROR) << "convertHidlNanDataPathIndicationResponse_1_6ToLegacy: "
+ "legacy_request is null";
+ return false;
+ }
+ *legacy_request = {};
+
+ legacy_request->rsp_code = hidl_request.acceptRequest ? legacy_hal::NAN_DP_REQUEST_ACCEPT
+ : legacy_hal::NAN_DP_REQUEST_REJECT;
+ legacy_request->ndp_instance_id = hidl_request.ndpInstanceId;
+ if (strnlen(hidl_request.ifaceName.c_str(), IFNAMSIZ + 1) == IFNAMSIZ + 1) {
+ LOG(ERROR) << "convertHidlNanDataPathIndicationResponse_1_6ToLegacy: "
+ "ifaceName too long";
+ return false;
+ }
+ strlcpy(legacy_request->ndp_iface, hidl_request.ifaceName.c_str(), IFNAMSIZ + 1);
+ legacy_request->ndp_cfg.security_cfg =
+ (hidl_request.securityConfig.securityType != NanDataPathSecurityType::OPEN)
+ ? legacy_hal::NAN_DP_CONFIG_SECURITY
+ : legacy_hal::NAN_DP_CONFIG_NO_SECURITY;
+ legacy_request->app_info.ndp_app_info_len = hidl_request.appInfo.size();
+ if (legacy_request->app_info.ndp_app_info_len > NAN_DP_MAX_APP_INFO_LEN) {
+ LOG(ERROR) << "convertHidlNanDataPathIndicationResponse_1_6ToLegacy: "
+ "ndp_app_info_len too large";
+ return false;
+ }
+ memcpy(legacy_request->app_info.ndp_app_info, hidl_request.appInfo.data(),
+ legacy_request->app_info.ndp_app_info_len);
+ legacy_request->cipher_type = (unsigned int)hidl_request.securityConfig.cipherType;
+ if (hidl_request.securityConfig.securityType == NanDataPathSecurityType::PMK) {
+ legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
+ legacy_request->key_info.body.pmk_info.pmk_len = hidl_request.securityConfig.pmk.size();
+ if (legacy_request->key_info.body.pmk_info.pmk_len != NAN_PMK_INFO_LEN) {
+ LOG(ERROR) << "convertHidlNanDataPathIndicationResponse_1_6ToLegacy: "
+ "invalid pmk_len";
+ return false;
+ }
+ memcpy(legacy_request->key_info.body.pmk_info.pmk, hidl_request.securityConfig.pmk.data(),
+ legacy_request->key_info.body.pmk_info.pmk_len);
+ }
+ if (hidl_request.securityConfig.securityType == NanDataPathSecurityType::PASSPHRASE) {
+ legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
+ legacy_request->key_info.body.passphrase_info.passphrase_len =
+ hidl_request.securityConfig.passphrase.size();
+ if (legacy_request->key_info.body.passphrase_info.passphrase_len <
+ NAN_SECURITY_MIN_PASSPHRASE_LEN) {
+ LOG(ERROR) << "convertHidlNanDataPathIndicationResponse_1_6ToLegacy: "
+ "passphrase_len too small";
+ return false;
+ }
+ if (legacy_request->key_info.body.passphrase_info.passphrase_len >
+ NAN_SECURITY_MAX_PASSPHRASE_LEN) {
+ LOG(ERROR) << "convertHidlNanDataPathIndicationResponse_1_6ToLegacy: "
+ "passphrase_len too large";
+ return false;
+ }
+ memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
+ hidl_request.securityConfig.passphrase.data(),
+ legacy_request->key_info.body.passphrase_info.passphrase_len);
+ }
+ legacy_request->service_name_len = hidl_request.serviceNameOutOfBand.size();
+ if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
+ LOG(ERROR) << "convertHidlNanDataPathIndicationResponse_1_6ToLegacy: "
+ "service_name_len too large";
+ return false;
+ }
+ memcpy(legacy_request->service_name, hidl_request.serviceNameOutOfBand.data(),
+ legacy_request->service_name_len);
+ legacy_request->scid_len = hidl_request.securityConfig.scid.size();
+ if (legacy_request->scid_len > NAN_MAX_SCID_BUF_LEN) {
+ LOG(ERROR) << "convertHidlNanDataPathIndicationResponse_1_6ToLegacy: scid_len too large";
+ return false;
+ }
+ memcpy(legacy_request->scid, hidl_request.securityConfig.scid.data(), legacy_request->scid_len);
+
+ return true;
+}
+
+bool convertLegacyNanResponseHeaderToHidl(const legacy_hal::NanResponseMsg& legacy_response,
+ WifiNanStatus* wifiNanStatus) {
+ if (!wifiNanStatus) {
+ LOG(ERROR) << "convertLegacyNanResponseHeaderToHidl: wifiNanStatus is null";
+ return false;
+ }
+ *wifiNanStatus = {};
+
+ convertToWifiNanStatus(legacy_response.status, legacy_response.nan_error,
+ sizeof(legacy_response.nan_error), wifiNanStatus);
+ return true;
+}
+
+bool convertLegacyNanCapabilitiesResponseToHidl(const legacy_hal::NanCapabilities& legacy_response,
+ V1_6::NanCapabilities* hidl_response) {
+ if (!hidl_response) {
+ LOG(ERROR) << "convertLegacyNanCapabilitiesResponseToHidl: "
+ "hidl_response is null";
+ return false;
+ }
+ *hidl_response = {};
+
+ hidl_response->maxConcurrentClusters = legacy_response.max_concurrent_nan_clusters;
+ hidl_response->maxPublishes = legacy_response.max_publishes;
+ hidl_response->maxSubscribes = legacy_response.max_subscribes;
+ hidl_response->maxServiceNameLen = legacy_response.max_service_name_len;
+ hidl_response->maxMatchFilterLen = legacy_response.max_match_filter_len;
+ hidl_response->maxTotalMatchFilterLen = legacy_response.max_total_match_filter_len;
+ hidl_response->maxServiceSpecificInfoLen = legacy_response.max_service_specific_info_len;
+ hidl_response->maxExtendedServiceSpecificInfoLen =
+ legacy_response.max_sdea_service_specific_info_len;
+ hidl_response->maxNdiInterfaces = legacy_response.max_ndi_interfaces;
+ hidl_response->maxNdpSessions = legacy_response.max_ndp_sessions;
+ hidl_response->maxAppInfoLen = legacy_response.max_app_info_len;
+ hidl_response->maxQueuedTransmitFollowupMsgs =
+ legacy_response.max_queued_transmit_followup_msgs;
+ hidl_response->maxSubscribeInterfaceAddresses = legacy_response.max_subscribe_address;
+ hidl_response->supportedCipherSuites = legacy_response.cipher_suites_supported;
+ hidl_response->instantCommunicationModeSupportFlag = legacy_response.is_instant_mode_supported;
+
+ return true;
+}
+
+bool convertLegacyNanMatchIndToHidl(const legacy_hal::NanMatchInd& legacy_ind,
+ V1_6::NanMatchInd* hidl_ind) {
+ if (!hidl_ind) {
+ LOG(ERROR) << "convertLegacyNanMatchIndToHidl: hidl_ind is null";
+ return false;
+ }
+ *hidl_ind = {};
+
+ hidl_ind->discoverySessionId = legacy_ind.publish_subscribe_id;
+ hidl_ind->peerId = legacy_ind.requestor_instance_id;
+ hidl_ind->addr = hidl_array<uint8_t, 6>(legacy_ind.addr);
+ hidl_ind->serviceSpecificInfo = std::vector<uint8_t>(
+ legacy_ind.service_specific_info,
+ legacy_ind.service_specific_info + legacy_ind.service_specific_info_len);
+ hidl_ind->extendedServiceSpecificInfo = std::vector<uint8_t>(
+ legacy_ind.sdea_service_specific_info,
+ legacy_ind.sdea_service_specific_info + legacy_ind.sdea_service_specific_info_len);
+ hidl_ind->matchFilter =
+ std::vector<uint8_t>(legacy_ind.sdf_match_filter,
+ legacy_ind.sdf_match_filter + legacy_ind.sdf_match_filter_len);
+ hidl_ind->matchOccuredInBeaconFlag = legacy_ind.match_occured_flag == 1;
+ hidl_ind->outOfResourceFlag = legacy_ind.out_of_resource_flag == 1;
+ hidl_ind->rssiValue = legacy_ind.rssi_value;
+ hidl_ind->peerCipherType = (V1_6::NanCipherSuiteType)legacy_ind.peer_cipher_type;
+ hidl_ind->peerRequiresSecurityEnabledInNdp =
+ legacy_ind.peer_sdea_params.security_cfg == legacy_hal::NAN_DP_CONFIG_SECURITY;
+ hidl_ind->peerRequiresRanging =
+ legacy_ind.peer_sdea_params.ranging_state == legacy_hal::NAN_RANGING_ENABLE;
+ hidl_ind->rangingMeasurementInMm = legacy_ind.range_info.range_measurement_mm;
+ hidl_ind->rangingIndicationType = legacy_ind.range_info.ranging_event_type;
+ hidl_ind->scid = std::vector<uint8_t>(legacy_ind.scid, legacy_ind.scid + legacy_ind.scid_len);
+ return true;
+}
+
+bool convertLegacyNanFollowupIndToHidl(const legacy_hal::NanFollowupInd& legacy_ind,
+ NanFollowupReceivedInd* hidl_ind) {
+ if (!hidl_ind) {
+ LOG(ERROR) << "convertLegacyNanFollowupIndToHidl: hidl_ind is null";
+ return false;
+ }
+ *hidl_ind = {};
+
+ hidl_ind->discoverySessionId = legacy_ind.publish_subscribe_id;
+ hidl_ind->peerId = legacy_ind.requestor_instance_id;
+ hidl_ind->addr = hidl_array<uint8_t, 6>(legacy_ind.addr);
+ hidl_ind->receivedInFaw = legacy_ind.dw_or_faw == 1;
+ hidl_ind->serviceSpecificInfo = std::vector<uint8_t>(
+ legacy_ind.service_specific_info,
+ legacy_ind.service_specific_info + legacy_ind.service_specific_info_len);
+ hidl_ind->extendedServiceSpecificInfo = std::vector<uint8_t>(
+ legacy_ind.sdea_service_specific_info,
+ legacy_ind.sdea_service_specific_info + legacy_ind.sdea_service_specific_info_len);
+
+ return true;
+}
+
+bool convertLegacyNanDataPathRequestIndToHidl(const legacy_hal::NanDataPathRequestInd& legacy_ind,
+ NanDataPathRequestInd* hidl_ind) {
+ if (!hidl_ind) {
+ LOG(ERROR) << "convertLegacyNanDataPathRequestIndToHidl: hidl_ind is null";
+ return false;
+ }
+ *hidl_ind = {};
+
+ hidl_ind->discoverySessionId = legacy_ind.service_instance_id;
+ hidl_ind->peerDiscMacAddr = hidl_array<uint8_t, 6>(legacy_ind.peer_disc_mac_addr);
+ hidl_ind->ndpInstanceId = legacy_ind.ndp_instance_id;
+ hidl_ind->securityRequired =
+ legacy_ind.ndp_cfg.security_cfg == legacy_hal::NAN_DP_CONFIG_SECURITY;
+ hidl_ind->appInfo = std::vector<uint8_t>(
+ legacy_ind.app_info.ndp_app_info,
+ legacy_ind.app_info.ndp_app_info + legacy_ind.app_info.ndp_app_info_len);
+
+ return true;
+}
+
+bool convertLegacyNdpChannelInfoToHidl(const legacy_hal::NanChannelInfo& legacy_struct,
+ V1_6::NanDataPathChannelInfo* hidl_struct) {
+ if (!hidl_struct) {
+ LOG(ERROR) << "convertLegacyNdpChannelInfoToHidl: hidl_struct is null";
+ return false;
+ }
+ *hidl_struct = {};
+
+ hidl_struct->channelFreq = legacy_struct.channel;
+ hidl_struct->channelBandwidth = convertLegacyWifiChannelWidthToHidl(
+ (legacy_hal::wifi_channel_width)legacy_struct.bandwidth);
+ hidl_struct->numSpatialStreams = legacy_struct.nss;
+
+ return true;
+}
+
+bool convertLegacyNanDataPathConfirmIndToHidl(const legacy_hal::NanDataPathConfirmInd& legacy_ind,
+ V1_6::NanDataPathConfirmInd* hidl_ind) {
+ if (!hidl_ind) {
+ LOG(ERROR) << "convertLegacyNanDataPathConfirmIndToHidl: hidl_ind is null";
+ return false;
+ }
+ *hidl_ind = {};
+
+ hidl_ind->V1_0.ndpInstanceId = legacy_ind.ndp_instance_id;
+ hidl_ind->V1_0.dataPathSetupSuccess = legacy_ind.rsp_code == legacy_hal::NAN_DP_REQUEST_ACCEPT;
+ hidl_ind->V1_0.peerNdiMacAddr = hidl_array<uint8_t, 6>(legacy_ind.peer_ndi_mac_addr);
+ hidl_ind->V1_0.appInfo = std::vector<uint8_t>(
+ legacy_ind.app_info.ndp_app_info,
+ legacy_ind.app_info.ndp_app_info + legacy_ind.app_info.ndp_app_info_len);
+ hidl_ind->V1_0.status.status = convertLegacyNanStatusTypeToHidl(legacy_ind.reason_code);
+ hidl_ind->V1_0.status.description = ""; // TODO: b/34059183
+
+ std::vector<V1_6::NanDataPathChannelInfo> channelInfo;
+ for (unsigned int i = 0; i < legacy_ind.num_channels; ++i) {
+ V1_6::NanDataPathChannelInfo hidl_struct;
+ if (!convertLegacyNdpChannelInfoToHidl(legacy_ind.channel_info[i], &hidl_struct)) {
+ return false;
+ }
+ channelInfo.push_back(hidl_struct);
+ }
+ hidl_ind->channelInfo = channelInfo;
+
+ return true;
+}
+
+bool convertLegacyNanDataPathScheduleUpdateIndToHidl(
+ const legacy_hal::NanDataPathScheduleUpdateInd& legacy_ind,
+ V1_6::NanDataPathScheduleUpdateInd* hidl_ind) {
+ if (!hidl_ind) {
+ LOG(ERROR) << "convertLegacyNanDataPathScheduleUpdateIndToHidl: "
+ "hidl_ind is null";
+ return false;
+ }
+ *hidl_ind = {};
+
+ hidl_ind->peerDiscoveryAddress = hidl_array<uint8_t, 6>(legacy_ind.peer_mac_addr);
+ std::vector<V1_6::NanDataPathChannelInfo> channelInfo;
+ for (unsigned int i = 0; i < legacy_ind.num_channels; ++i) {
+ V1_6::NanDataPathChannelInfo hidl_struct;
+ if (!convertLegacyNdpChannelInfoToHidl(legacy_ind.channel_info[i], &hidl_struct)) {
+ return false;
+ }
+ channelInfo.push_back(hidl_struct);
+ }
+ hidl_ind->channelInfo = channelInfo;
+ std::vector<uint32_t> ndpInstanceIds;
+ for (unsigned int i = 0; i < legacy_ind.num_ndp_instances; ++i) {
+ ndpInstanceIds.push_back(legacy_ind.ndp_instance_id[i]);
+ }
+ hidl_ind->ndpInstanceIds = ndpInstanceIds;
+
+ return true;
+}
+
+legacy_hal::wifi_rtt_type convertHidlRttTypeToLegacy(RttType type) {
+ switch (type) {
+ case RttType::ONE_SIDED:
+ return legacy_hal::RTT_TYPE_1_SIDED;
+ case RttType::TWO_SIDED:
+ return legacy_hal::RTT_TYPE_2_SIDED;
+ };
+ CHECK(false);
+}
+
+RttType convertLegacyRttTypeToHidl(legacy_hal::wifi_rtt_type type) {
+ switch (type) {
+ case legacy_hal::RTT_TYPE_1_SIDED:
+ return RttType::ONE_SIDED;
+ case legacy_hal::RTT_TYPE_2_SIDED:
+ return RttType::TWO_SIDED;
+ };
+ CHECK(false) << "Unknown legacy type: " << type;
+}
+
+legacy_hal::rtt_peer_type convertHidlRttPeerTypeToLegacy(RttPeerType type) {
+ switch (type) {
+ case RttPeerType::AP:
+ return legacy_hal::RTT_PEER_AP;
+ case RttPeerType::STA:
+ return legacy_hal::RTT_PEER_STA;
+ case RttPeerType::P2P_GO:
+ return legacy_hal::RTT_PEER_P2P_GO;
+ case RttPeerType::P2P_CLIENT:
+ return legacy_hal::RTT_PEER_P2P_CLIENT;
+ case RttPeerType::NAN:
+ return legacy_hal::RTT_PEER_NAN;
+ };
+ CHECK(false);
+}
+
+legacy_hal::wifi_channel_width convertHidlWifiChannelWidthToLegacy(WifiChannelWidthInMhz type) {
+ switch (type) {
+ case WifiChannelWidthInMhz::WIDTH_20:
+ return legacy_hal::WIFI_CHAN_WIDTH_20;
+ case WifiChannelWidthInMhz::WIDTH_40:
+ return legacy_hal::WIFI_CHAN_WIDTH_40;
+ case WifiChannelWidthInMhz::WIDTH_80:
+ return legacy_hal::WIFI_CHAN_WIDTH_80;
+ case WifiChannelWidthInMhz::WIDTH_160:
+ return legacy_hal::WIFI_CHAN_WIDTH_160;
+ case WifiChannelWidthInMhz::WIDTH_80P80:
+ return legacy_hal::WIFI_CHAN_WIDTH_80P80;
+ case WifiChannelWidthInMhz::WIDTH_5:
+ return legacy_hal::WIFI_CHAN_WIDTH_5;
+ case WifiChannelWidthInMhz::WIDTH_10:
+ return legacy_hal::WIFI_CHAN_WIDTH_10;
+ case V1_6::WifiChannelWidthInMhz::WIDTH_320:
+ return legacy_hal::WIFI_CHAN_WIDTH_320;
+ case WifiChannelWidthInMhz::WIDTH_INVALID:
+ return legacy_hal::WIFI_CHAN_WIDTH_INVALID;
+ };
+ CHECK(false);
+}
+
+V1_6::WifiChannelWidthInMhz convertLegacyWifiChannelWidthToHidl(
+ legacy_hal::wifi_channel_width type) {
+ switch (type) {
+ case legacy_hal::WIFI_CHAN_WIDTH_20:
+ return WifiChannelWidthInMhz::WIDTH_20;
+ case legacy_hal::WIFI_CHAN_WIDTH_40:
+ return WifiChannelWidthInMhz::WIDTH_40;
+ case legacy_hal::WIFI_CHAN_WIDTH_80:
+ return WifiChannelWidthInMhz::WIDTH_80;
+ case legacy_hal::WIFI_CHAN_WIDTH_160:
+ return WifiChannelWidthInMhz::WIDTH_160;
+ case legacy_hal::WIFI_CHAN_WIDTH_80P80:
+ return WifiChannelWidthInMhz::WIDTH_80P80;
+ case legacy_hal::WIFI_CHAN_WIDTH_5:
+ return WifiChannelWidthInMhz::WIDTH_5;
+ case legacy_hal::WIFI_CHAN_WIDTH_10:
+ return WifiChannelWidthInMhz::WIDTH_10;
+ case legacy_hal::WIFI_CHAN_WIDTH_320:
+ return V1_6::WifiChannelWidthInMhz::WIDTH_320;
+ default:
+ return WifiChannelWidthInMhz::WIDTH_INVALID;
+ };
+}
+
+legacy_hal::wifi_rtt_preamble convertHidlRttPreambleToLegacy(V1_6::RttPreamble type) {
+ switch (type) {
+ case V1_6::RttPreamble::LEGACY:
+ return legacy_hal::WIFI_RTT_PREAMBLE_LEGACY;
+ case V1_6::RttPreamble::HT:
+ return legacy_hal::WIFI_RTT_PREAMBLE_HT;
+ case V1_6::RttPreamble::VHT:
+ return legacy_hal::WIFI_RTT_PREAMBLE_VHT;
+ case V1_6::RttPreamble::HE:
+ return legacy_hal::WIFI_RTT_PREAMBLE_HE;
+ case V1_6::RttPreamble::EHT:
+ return legacy_hal::WIFI_RTT_PREAMBLE_EHT;
+ };
+ CHECK(false);
+}
+
+V1_6::RttPreamble convertLegacyRttPreambleToHidl(legacy_hal::wifi_rtt_preamble type) {
+ switch (type) {
+ case legacy_hal::WIFI_RTT_PREAMBLE_LEGACY:
+ return V1_6::RttPreamble::LEGACY;
+ case legacy_hal::WIFI_RTT_PREAMBLE_HT:
+ return V1_6::RttPreamble::HT;
+ case legacy_hal::WIFI_RTT_PREAMBLE_VHT:
+ return V1_6::RttPreamble::VHT;
+ case legacy_hal::WIFI_RTT_PREAMBLE_HE:
+ return V1_6::RttPreamble::HE;
+ case legacy_hal::WIFI_RTT_PREAMBLE_EHT:
+ return V1_6::RttPreamble::EHT;
+ };
+ CHECK(false) << "Unknown legacy type: " << type;
+}
+
+legacy_hal::wifi_rtt_bw convertHidlRttBwToLegacy(RttBw type) {
+ switch (type) {
+ case RttBw::BW_5MHZ:
+ return legacy_hal::WIFI_RTT_BW_5;
+ case RttBw::BW_10MHZ:
+ return legacy_hal::WIFI_RTT_BW_10;
+ case RttBw::BW_20MHZ:
+ return legacy_hal::WIFI_RTT_BW_20;
+ case RttBw::BW_40MHZ:
+ return legacy_hal::WIFI_RTT_BW_40;
+ case RttBw::BW_80MHZ:
+ return legacy_hal::WIFI_RTT_BW_80;
+ case RttBw::BW_160MHZ:
+ return legacy_hal::WIFI_RTT_BW_160;
+ case RttBw::BW_320MHZ:
+ return legacy_hal::WIFI_RTT_BW_320;
+ };
+ CHECK(false);
+}
+
+RttBw convertLegacyRttBwToHidl(legacy_hal::wifi_rtt_bw type) {
+ switch (type) {
+ case legacy_hal::WIFI_RTT_BW_5:
+ return RttBw::BW_5MHZ;
+ case legacy_hal::WIFI_RTT_BW_10:
+ return RttBw::BW_10MHZ;
+ case legacy_hal::WIFI_RTT_BW_20:
+ return RttBw::BW_20MHZ;
+ case legacy_hal::WIFI_RTT_BW_40:
+ return RttBw::BW_40MHZ;
+ case legacy_hal::WIFI_RTT_BW_80:
+ return RttBw::BW_80MHZ;
+ case legacy_hal::WIFI_RTT_BW_160:
+ return RttBw::BW_160MHZ;
+ case legacy_hal::WIFI_RTT_BW_320:
+ return RttBw::BW_320MHZ;
+ };
+ CHECK(false) << "Unknown legacy type: " << type;
+}
+
+legacy_hal::wifi_motion_pattern convertHidlRttMotionPatternToLegacy(RttMotionPattern type) {
+ switch (type) {
+ case RttMotionPattern::NOT_EXPECTED:
+ return legacy_hal::WIFI_MOTION_NOT_EXPECTED;
+ case RttMotionPattern::EXPECTED:
+ return legacy_hal::WIFI_MOTION_EXPECTED;
+ case RttMotionPattern::UNKNOWN:
+ return legacy_hal::WIFI_MOTION_UNKNOWN;
+ };
+ CHECK(false);
+}
+
+V1_6::WifiRatePreamble convertLegacyWifiRatePreambleToHidl(uint8_t preamble) {
+ switch (preamble) {
+ case 0:
+ return V1_6::WifiRatePreamble::OFDM;
+ case 1:
+ return V1_6::WifiRatePreamble::CCK;
+ case 2:
+ return V1_6::WifiRatePreamble::HT;
+ case 3:
+ return V1_6::WifiRatePreamble::VHT;
+ case 4:
+ return V1_6::WifiRatePreamble::HE;
+ case 5:
+ return V1_6::WifiRatePreamble::EHT;
+ default:
+ return V1_6::WifiRatePreamble::RESERVED;
+ };
+ CHECK(false) << "Unknown legacy preamble: " << preamble;
+}
+
+WifiRateNss convertLegacyWifiRateNssToHidl(uint8_t nss) {
+ switch (nss) {
+ case 0:
+ return WifiRateNss::NSS_1x1;
+ case 1:
+ return WifiRateNss::NSS_2x2;
+ case 2:
+ return WifiRateNss::NSS_3x3;
+ case 3:
+ return WifiRateNss::NSS_4x4;
+ };
+ CHECK(false) << "Unknown legacy nss: " << nss;
+ return {};
+}
+
+RttStatus convertLegacyRttStatusToHidl(legacy_hal::wifi_rtt_status status) {
+ switch (status) {
+ case legacy_hal::RTT_STATUS_SUCCESS:
+ return RttStatus::SUCCESS;
+ case legacy_hal::RTT_STATUS_FAILURE:
+ return RttStatus::FAILURE;
+ case legacy_hal::RTT_STATUS_FAIL_NO_RSP:
+ return RttStatus::FAIL_NO_RSP;
+ case legacy_hal::RTT_STATUS_FAIL_REJECTED:
+ return RttStatus::FAIL_REJECTED;
+ case legacy_hal::RTT_STATUS_FAIL_NOT_SCHEDULED_YET:
+ return RttStatus::FAIL_NOT_SCHEDULED_YET;
+ case legacy_hal::RTT_STATUS_FAIL_TM_TIMEOUT:
+ return RttStatus::FAIL_TM_TIMEOUT;
+ case legacy_hal::RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL:
+ return RttStatus::FAIL_AP_ON_DIFF_CHANNEL;
+ case legacy_hal::RTT_STATUS_FAIL_NO_CAPABILITY:
+ return RttStatus::FAIL_NO_CAPABILITY;
+ case legacy_hal::RTT_STATUS_ABORTED:
+ return RttStatus::ABORTED;
+ case legacy_hal::RTT_STATUS_FAIL_INVALID_TS:
+ return RttStatus::FAIL_INVALID_TS;
+ case legacy_hal::RTT_STATUS_FAIL_PROTOCOL:
+ return RttStatus::FAIL_PROTOCOL;
+ case legacy_hal::RTT_STATUS_FAIL_SCHEDULE:
+ return RttStatus::FAIL_SCHEDULE;
+ case legacy_hal::RTT_STATUS_FAIL_BUSY_TRY_LATER:
+ return RttStatus::FAIL_BUSY_TRY_LATER;
+ case legacy_hal::RTT_STATUS_INVALID_REQ:
+ return RttStatus::INVALID_REQ;
+ case legacy_hal::RTT_STATUS_NO_WIFI:
+ return RttStatus::NO_WIFI;
+ case legacy_hal::RTT_STATUS_FAIL_FTM_PARAM_OVERRIDE:
+ return RttStatus::FAIL_FTM_PARAM_OVERRIDE;
+ case legacy_hal::RTT_STATUS_NAN_RANGING_PROTOCOL_FAILURE:
+ return RttStatus::FAILURE; // TODO: add HIDL enumeration
+ case legacy_hal::RTT_STATUS_NAN_RANGING_CONCURRENCY_NOT_SUPPORTED:
+ return RttStatus::FAILURE; // TODO: add HIDL enumeration
+ };
+ CHECK(false) << "Unknown legacy status: " << status;
+}
+
+bool convertHidlWifiChannelInfoToLegacy(const WifiChannelInfo& hidl_info,
+ legacy_hal::wifi_channel_info* legacy_info) {
+ if (!legacy_info) {
+ return false;
+ }
+ *legacy_info = {};
+ legacy_info->width = convertHidlWifiChannelWidthToLegacy(hidl_info.width);
+ legacy_info->center_freq = hidl_info.centerFreq;
+ legacy_info->center_freq0 = hidl_info.centerFreq0;
+ legacy_info->center_freq1 = hidl_info.centerFreq1;
+ return true;
+}
+
+bool convertLegacyWifiChannelInfoToHidl(const legacy_hal::wifi_channel_info& legacy_info,
+ WifiChannelInfo* hidl_info) {
+ if (!hidl_info) {
+ return false;
+ }
+ *hidl_info = {};
+ hidl_info->width = convertLegacyWifiChannelWidthToHidl(legacy_info.width);
+ hidl_info->centerFreq = legacy_info.center_freq;
+ hidl_info->centerFreq0 = legacy_info.center_freq0;
+ hidl_info->centerFreq1 = legacy_info.center_freq1;
+ return true;
+}
+
+bool convertHidlRttConfigToLegacy(const V1_6::RttConfig& hidl_config,
+ legacy_hal::wifi_rtt_config* legacy_config) {
+ if (!legacy_config) {
+ return false;
+ }
+ *legacy_config = {};
+ CHECK(hidl_config.addr.size() == sizeof(legacy_config->addr));
+ memcpy(legacy_config->addr, hidl_config.addr.data(), hidl_config.addr.size());
+ legacy_config->type = convertHidlRttTypeToLegacy(hidl_config.type);
+ legacy_config->peer = convertHidlRttPeerTypeToLegacy(hidl_config.peer);
+ if (!convertHidlWifiChannelInfoToLegacy(hidl_config.channel, &legacy_config->channel)) {
+ return false;
+ }
+ legacy_config->burst_period = hidl_config.burstPeriod;
+ legacy_config->num_burst = hidl_config.numBurst;
+ legacy_config->num_frames_per_burst = hidl_config.numFramesPerBurst;
+ legacy_config->num_retries_per_rtt_frame = hidl_config.numRetriesPerRttFrame;
+ legacy_config->num_retries_per_ftmr = hidl_config.numRetriesPerFtmr;
+ legacy_config->LCI_request = hidl_config.mustRequestLci;
+ legacy_config->LCR_request = hidl_config.mustRequestLcr;
+ legacy_config->burst_duration = hidl_config.burstDuration;
+ legacy_config->preamble = convertHidlRttPreambleToLegacy(hidl_config.preamble);
+ legacy_config->bw = convertHidlRttBwToLegacy(hidl_config.bw);
+ return true;
+}
+
+bool convertHidlVectorOfRttConfigToLegacy(
+ const std::vector<V1_6::RttConfig>& hidl_configs,
+ std::vector<legacy_hal::wifi_rtt_config>* legacy_configs) {
+ if (!legacy_configs) {
+ return false;
+ }
+ *legacy_configs = {};
+ for (const auto& hidl_config : hidl_configs) {
+ legacy_hal::wifi_rtt_config legacy_config;
+ if (!convertHidlRttConfigToLegacy(hidl_config, &legacy_config)) {
+ return false;
+ }
+ legacy_configs->push_back(legacy_config);
+ }
+ return true;
+}
+
+bool convertHidlRttLciInformationToLegacy(const RttLciInformation& hidl_info,
+ legacy_hal::wifi_lci_information* legacy_info) {
+ if (!legacy_info) {
+ return false;
+ }
+ *legacy_info = {};
+ legacy_info->latitude = hidl_info.latitude;
+ legacy_info->longitude = hidl_info.longitude;
+ legacy_info->altitude = hidl_info.altitude;
+ legacy_info->latitude_unc = hidl_info.latitudeUnc;
+ legacy_info->longitude_unc = hidl_info.longitudeUnc;
+ legacy_info->altitude_unc = hidl_info.altitudeUnc;
+ legacy_info->motion_pattern = convertHidlRttMotionPatternToLegacy(hidl_info.motionPattern);
+ legacy_info->floor = hidl_info.floor;
+ legacy_info->height_above_floor = hidl_info.heightAboveFloor;
+ legacy_info->height_unc = hidl_info.heightUnc;
+ return true;
+}
+
+bool convertHidlRttLcrInformationToLegacy(const RttLcrInformation& hidl_info,
+ legacy_hal::wifi_lcr_information* legacy_info) {
+ if (!legacy_info) {
+ return false;
+ }
+ *legacy_info = {};
+ CHECK(hidl_info.countryCode.size() == sizeof(legacy_info->country_code));
+ memcpy(legacy_info->country_code, hidl_info.countryCode.data(), hidl_info.countryCode.size());
+ if (hidl_info.civicInfo.size() > sizeof(legacy_info->civic_info)) {
+ return false;
+ }
+ legacy_info->length = hidl_info.civicInfo.size();
+ memcpy(legacy_info->civic_info, hidl_info.civicInfo.c_str(), hidl_info.civicInfo.size());
+ return true;
+}
+
+bool convertHidlRttResponderToLegacy(const V1_6::RttResponder& hidl_responder,
+ legacy_hal::wifi_rtt_responder* legacy_responder) {
+ if (!legacy_responder) {
+ return false;
+ }
+ *legacy_responder = {};
+ if (!convertHidlWifiChannelInfoToLegacy(hidl_responder.channel, &legacy_responder->channel)) {
+ return false;
+ }
+ legacy_responder->preamble = convertHidlRttPreambleToLegacy(hidl_responder.preamble);
+ return true;
+}
+
+bool convertLegacyRttResponderToHidl(const legacy_hal::wifi_rtt_responder& legacy_responder,
+ V1_6::RttResponder* hidl_responder) {
+ if (!hidl_responder) {
+ return false;
+ }
+ *hidl_responder = {};
+ if (!convertLegacyWifiChannelInfoToHidl(legacy_responder.channel, &hidl_responder->channel)) {
+ return false;
+ }
+ hidl_responder->preamble = convertLegacyRttPreambleToHidl(legacy_responder.preamble);
+ return true;
+}
+
+bool convertLegacyRttCapabilitiesToHidl(
+ const legacy_hal::wifi_rtt_capabilities& legacy_capabilities,
+ V1_6::RttCapabilities* hidl_capabilities) {
+ if (!hidl_capabilities) {
+ return false;
+ }
+ *hidl_capabilities = {};
+ hidl_capabilities->rttOneSidedSupported = legacy_capabilities.rtt_one_sided_supported;
+ hidl_capabilities->rttFtmSupported = legacy_capabilities.rtt_ftm_supported;
+ hidl_capabilities->lciSupported = legacy_capabilities.lci_support;
+ hidl_capabilities->lcrSupported = legacy_capabilities.lcr_support;
+ hidl_capabilities->responderSupported = legacy_capabilities.responder_supported;
+ hidl_capabilities->preambleSupport = 0;
+ for (const auto flag : {legacy_hal::WIFI_RTT_PREAMBLE_LEGACY, legacy_hal::WIFI_RTT_PREAMBLE_HT,
+ legacy_hal::WIFI_RTT_PREAMBLE_VHT, legacy_hal::WIFI_RTT_PREAMBLE_HE,
+ legacy_hal::WIFI_RTT_PREAMBLE_EHT}) {
+ if (legacy_capabilities.preamble_support & flag) {
+ hidl_capabilities->preambleSupport |=
+ static_cast<std::underlying_type<V1_6::RttPreamble>::type>(
+ convertLegacyRttPreambleToHidl(flag));
+ }
+ }
+ hidl_capabilities->bwSupport = 0;
+ for (const auto flag :
+ {legacy_hal::WIFI_RTT_BW_5, legacy_hal::WIFI_RTT_BW_10, legacy_hal::WIFI_RTT_BW_20,
+ legacy_hal::WIFI_RTT_BW_40, legacy_hal::WIFI_RTT_BW_80, legacy_hal::WIFI_RTT_BW_160,
+ legacy_hal::WIFI_RTT_BW_320}) {
+ if (legacy_capabilities.bw_support & flag) {
+ hidl_capabilities->bwSupport |=
+ static_cast<std::underlying_type<RttBw>::type>(convertLegacyRttBwToHidl(flag));
+ }
+ }
+ hidl_capabilities->mcVersion = legacy_capabilities.mc_version;
+ return true;
+}
+
+bool convertLegacyWifiRateInfoToHidl(const legacy_hal::wifi_rate& legacy_rate,
+ V1_6::WifiRateInfo* hidl_rate) {
+ if (!hidl_rate) {
+ return false;
+ }
+ *hidl_rate = {};
+ hidl_rate->preamble = convertLegacyWifiRatePreambleToHidl(legacy_rate.preamble);
+ hidl_rate->nss = convertLegacyWifiRateNssToHidl(legacy_rate.nss);
+ hidl_rate->bw = convertLegacyWifiChannelWidthToHidl(
+ static_cast<legacy_hal::wifi_channel_width>(legacy_rate.bw));
+ hidl_rate->rateMcsIdx = legacy_rate.rateMcsIdx;
+ hidl_rate->bitRateInKbps = legacy_rate.bitrate;
+ return true;
+}
+
+bool convertLegacyRttResultToHidl(const legacy_hal::wifi_rtt_result& legacy_result,
+ V1_6::RttResult* hidl_result) {
+ if (!hidl_result) {
+ return false;
+ }
+ *hidl_result = {};
+ CHECK(sizeof(legacy_result.addr) == hidl_result->addr.size());
+ memcpy(hidl_result->addr.data(), legacy_result.addr, sizeof(legacy_result.addr));
+ hidl_result->burstNum = legacy_result.burst_num;
+ hidl_result->measurementNumber = legacy_result.measurement_number;
+ hidl_result->successNumber = legacy_result.success_number;
+ hidl_result->numberPerBurstPeer = legacy_result.number_per_burst_peer;
+ hidl_result->status = convertLegacyRttStatusToHidl(legacy_result.status);
+ hidl_result->retryAfterDuration = legacy_result.retry_after_duration;
+ hidl_result->type = convertLegacyRttTypeToHidl(legacy_result.type);
+ hidl_result->rssi = legacy_result.rssi;
+ hidl_result->rssiSpread = legacy_result.rssi_spread;
+ if (!convertLegacyWifiRateInfoToHidl(legacy_result.tx_rate, &hidl_result->txRate)) {
+ return false;
+ }
+ if (!convertLegacyWifiRateInfoToHidl(legacy_result.rx_rate, &hidl_result->rxRate)) {
+ return false;
+ }
+ hidl_result->rtt = legacy_result.rtt;
+ hidl_result->rttSd = legacy_result.rtt_sd;
+ hidl_result->rttSpread = legacy_result.rtt_spread;
+ hidl_result->distanceInMm = legacy_result.distance_mm;
+ hidl_result->distanceSdInMm = legacy_result.distance_sd_mm;
+ hidl_result->distanceSpreadInMm = legacy_result.distance_spread_mm;
+ hidl_result->timeStampInUs = legacy_result.ts;
+ hidl_result->burstDurationInMs = legacy_result.burst_duration;
+ hidl_result->negotiatedBurstNum = legacy_result.negotiated_burst_num;
+ if (legacy_result.LCI && !convertLegacyIeToHidl(*legacy_result.LCI, &hidl_result->lci)) {
+ return false;
+ }
+ if (legacy_result.LCR && !convertLegacyIeToHidl(*legacy_result.LCR, &hidl_result->lcr)) {
+ return false;
+ }
+ return true;
+}
+
+bool convertLegacyVectorOfRttResultToHidl(
+ const std::vector<const legacy_hal::wifi_rtt_result*>& legacy_results,
+ std::vector<V1_6::RttResult>* hidl_results) {
+ if (!hidl_results) {
+ return false;
+ }
+ *hidl_results = {};
+ for (const auto legacy_result : legacy_results) {
+ V1_6::RttResult hidl_result;
+ if (!convertLegacyRttResultToHidl(*legacy_result, &hidl_result)) {
+ return false;
+ }
+ hidl_results->push_back(hidl_result);
+ }
+ return true;
+}
+
+legacy_hal::wifi_interface_type convertHidlIfaceTypeToLegacy(IfaceType hidl_interface_type) {
+ switch (hidl_interface_type) {
+ case IfaceType::STA:
+ return legacy_hal::WIFI_INTERFACE_TYPE_STA;
+ case IfaceType::AP:
+ return legacy_hal::WIFI_INTERFACE_TYPE_AP;
+ case IfaceType::P2P:
+ return legacy_hal::WIFI_INTERFACE_TYPE_P2P;
+ case IfaceType::NAN:
+ return legacy_hal::WIFI_INTERFACE_TYPE_NAN;
+ }
+ CHECK(false);
+}
+
+legacy_hal::wifi_multi_sta_use_case convertHidlMultiStaUseCaseToLegacy(
+ V1_5::IWifiChip::MultiStaUseCase use_case) {
+ switch (use_case) {
+ case V1_5::IWifiChip::MultiStaUseCase::DUAL_STA_TRANSIENT_PREFER_PRIMARY:
+ return legacy_hal::WIFI_DUAL_STA_TRANSIENT_PREFER_PRIMARY;
+ case V1_5::IWifiChip::MultiStaUseCase::DUAL_STA_NON_TRANSIENT_UNBIASED:
+ return legacy_hal::WIFI_DUAL_STA_NON_TRANSIENT_UNBIASED;
+ }
+ CHECK(false);
+}
+
+bool convertHidlCoexUnsafeChannelToLegacy(
+ const V1_5::IWifiChip::CoexUnsafeChannel& hidl_unsafe_channel,
+ legacy_hal::wifi_coex_unsafe_channel* legacy_unsafe_channel) {
+ if (!legacy_unsafe_channel) {
+ return false;
+ }
+ *legacy_unsafe_channel = {};
+ switch (hidl_unsafe_channel.band) {
+ case V1_5::WifiBand::BAND_24GHZ:
+ legacy_unsafe_channel->band = legacy_hal::WLAN_MAC_2_4_BAND;
+ break;
+ case V1_5::WifiBand::BAND_5GHZ:
+ legacy_unsafe_channel->band = legacy_hal::WLAN_MAC_5_0_BAND;
+ break;
+ default:
+ return false;
+ };
+ legacy_unsafe_channel->channel = hidl_unsafe_channel.channel;
+ legacy_unsafe_channel->power_cap_dbm = hidl_unsafe_channel.powerCapDbm;
+ return true;
+}
+
+bool convertHidlVectorOfCoexUnsafeChannelToLegacy(
+ const std::vector<V1_5::IWifiChip::CoexUnsafeChannel>& hidl_unsafe_channels,
+ std::vector<legacy_hal::wifi_coex_unsafe_channel>* legacy_unsafe_channels) {
+ if (!legacy_unsafe_channels) {
+ return false;
+ }
+ *legacy_unsafe_channels = {};
+ for (const auto& hidl_unsafe_channel : hidl_unsafe_channels) {
+ legacy_hal::wifi_coex_unsafe_channel legacy_unsafe_channel;
+ if (!hidl_struct_util::convertHidlCoexUnsafeChannelToLegacy(hidl_unsafe_channel,
+ &legacy_unsafe_channel)) {
+ return false;
+ }
+ legacy_unsafe_channels->push_back(legacy_unsafe_channel);
+ }
+ return true;
+}
+
+V1_6::WifiAntennaMode convertLegacyAntennaConfigurationToHidl(uint32_t antenna_cfg) {
+ switch (antenna_cfg) {
+ case legacy_hal::WIFI_ANTENNA_1X1:
+ return V1_6::WifiAntennaMode::WIFI_ANTENNA_MODE_1X1;
+ case legacy_hal::WIFI_ANTENNA_2X2:
+ return V1_6::WifiAntennaMode::WIFI_ANTENNA_MODE_2X2;
+ case legacy_hal::WIFI_ANTENNA_3X3:
+ return V1_6::WifiAntennaMode::WIFI_ANTENNA_MODE_3X3;
+ case legacy_hal::WIFI_ANTENNA_4X4:
+ return V1_6::WifiAntennaMode::WIFI_ANTENNA_MODE_4X4;
+ default:
+ return V1_6::WifiAntennaMode::WIFI_ANTENNA_MODE_UNSPECIFIED;
+ }
+}
+
+bool convertLegacyWifiRadioConfigurationToHidl(
+ legacy_hal::wifi_radio_configuration* radio_configuration,
+ V1_6::WifiRadioConfiguration* hidl_radio_configuration) {
+ if (!hidl_radio_configuration) {
+ return false;
+ }
+ *hidl_radio_configuration = {};
+ hidl_radio_configuration->bandInfo =
+ hidl_struct_util::convertLegacyMacBandToHidlWifiBand(radio_configuration->band);
+ if (hidl_radio_configuration->bandInfo == V1_5::WifiBand::BAND_UNSPECIFIED) {
+ LOG(ERROR) << "Unspecified band";
+ return false;
+ }
+ hidl_radio_configuration->antennaMode =
+ hidl_struct_util::convertLegacyAntennaConfigurationToHidl(
+ radio_configuration->antenna_cfg);
+ return true;
+}
+
+bool convertLegacyRadioCombinationsMatrixToHidl(
+ legacy_hal::wifi_radio_combination_matrix* legacy_matrix,
+ WifiRadioCombinationMatrix* hidl_matrix) {
+ if (!hidl_matrix || !legacy_matrix) {
+ return false;
+ }
+ *hidl_matrix = {};
+
+ int num_combinations = legacy_matrix->num_radio_combinations;
+ std::vector<V1_6::WifiRadioCombination> radio_combinations_vec;
+ if (!num_combinations) {
+ LOG(ERROR) << "zero radio combinations";
+ return false;
+ }
+ wifi_radio_combination* l_radio_combinations_ptr = legacy_matrix->radio_combinations;
+ for (int i = 0; i < num_combinations; i++) {
+ int num_configurations = l_radio_combinations_ptr->num_radio_configurations;
+ WifiRadioCombination radioCombination;
+ std::vector<V1_6::WifiRadioConfiguration> radio_configurations_vec;
+ if (!num_configurations) {
+ LOG(ERROR) << "zero radio configurations";
+ return false;
+ }
+ for (int j = 0; j < num_configurations; j++) {
+ WifiRadioConfiguration radioConfiguration;
+ wifi_radio_configuration* l_radio_configurations_ptr =
+ &l_radio_combinations_ptr->radio_configurations[j];
+ if (!hidl_struct_util::convertLegacyWifiRadioConfigurationToHidl(
+ l_radio_configurations_ptr, &radioConfiguration)) {
+ LOG(ERROR) << "Error converting wifi radio configuration";
+ return false;
+ }
+ radio_configurations_vec.push_back(radioConfiguration);
+ }
+ radioCombination.radioConfigurations = radio_configurations_vec;
+ radio_combinations_vec.push_back(radioCombination);
+ l_radio_combinations_ptr =
+ (wifi_radio_combination*)((u8*)l_radio_combinations_ptr +
+ sizeof(wifi_radio_combination) +
+ (sizeof(wifi_radio_configuration) * num_configurations));
+ }
+ hidl_matrix->radioCombinations = radio_combinations_vec;
+ return true;
+}
+
+} // namespace hidl_struct_util
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.6/default/hidl_struct_util.h b/wifi/1.6/default/hidl_struct_util.h
new file mode 100644
index 0000000..2d4a5f1
--- /dev/null
+++ b/wifi/1.6/default/hidl_struct_util.h
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HIDL_STRUCT_UTIL_H_
+#define HIDL_STRUCT_UTIL_H_
+
+#include <vector>
+
+#include <android/hardware/wifi/1.0/IWifiChip.h>
+#include <android/hardware/wifi/1.0/types.h>
+#include <android/hardware/wifi/1.2/types.h>
+#include <android/hardware/wifi/1.3/types.h>
+#include <android/hardware/wifi/1.4/IWifiChipEventCallback.h>
+#include <android/hardware/wifi/1.4/types.h>
+#include <android/hardware/wifi/1.6/IWifiChip.h>
+#include <android/hardware/wifi/1.6/types.h>
+
+#include "wifi_legacy_hal.h"
+
+/**
+ * This file contains a bunch of functions to convert structs from the legacy
+ * HAL to HIDL and vice versa.
+ * TODO(b/32093047): Add unit tests for these conversion methods in the VTS test
+ * suite.
+ */
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace hidl_struct_util {
+using namespace android::hardware::wifi::V1_0;
+
+// Chip conversion methods.
+bool convertLegacyFeaturesToHidlChipCapabilities(uint64_t legacy_feature_set,
+ uint32_t legacy_logger_feature_set,
+ uint32_t* hidl_caps);
+bool convertLegacyDebugRingBufferStatusToHidl(
+ const legacy_hal::wifi_ring_buffer_status& legacy_status,
+ WifiDebugRingBufferStatus* hidl_status);
+bool convertLegacyVectorOfDebugRingBufferStatusToHidl(
+ const std::vector<legacy_hal::wifi_ring_buffer_status>& legacy_status_vec,
+ std::vector<WifiDebugRingBufferStatus>* hidl_status_vec);
+bool convertLegacyWakeReasonStatsToHidl(const legacy_hal::WakeReasonStats& legacy_stats,
+ WifiDebugHostWakeReasonStats* hidl_stats);
+legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy(
+ V1_1::IWifiChip::TxPowerScenario hidl_scenario);
+legacy_hal::wifi_latency_mode convertHidlLatencyModeToLegacy(
+ V1_3::IWifiChip::LatencyMode hidl_latency_mode);
+legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy_1_2(
+ V1_2::IWifiChip::TxPowerScenario hidl_scenario);
+bool convertLegacyWifiMacInfosToHidl(
+ const std::vector<legacy_hal::WifiMacInfo>& legacy_mac_infos,
+ std::vector<V1_4::IWifiChipEventCallback::RadioModeInfo>* hidl_radio_mode_infos);
+legacy_hal::wifi_interface_type convertHidlIfaceTypeToLegacy(IfaceType hidl_interface_type);
+legacy_hal::wifi_multi_sta_use_case convertHidlMultiStaUseCaseToLegacy(
+ V1_5::IWifiChip::MultiStaUseCase use_case);
+bool convertHidlCoexUnsafeChannelToLegacy(
+ const V1_5::IWifiChip::CoexUnsafeChannel& hidl_unsafe_channel,
+ legacy_hal::wifi_coex_unsafe_channel* legacy_unsafe_channel);
+bool convertHidlVectorOfCoexUnsafeChannelToLegacy(
+ const std::vector<V1_5::IWifiChip::CoexUnsafeChannel>& hidl_unsafe_channels,
+ std::vector<legacy_hal::wifi_coex_unsafe_channel>* legacy_unsafe_channels);
+bool convertLegacyRadioCombinationsMatrixToHidl(
+ legacy_hal::wifi_radio_combination_matrix* legacy_matrix,
+ V1_6::WifiRadioCombinationMatrix* hidl_matrix);
+V1_5::WifiBand convertLegacyMacBandToHidlWifiBand(uint32_t band);
+V1_6::WifiAntennaMode convertLegacyAntennaConfigurationToHidl(uint32_t antenna_cfg);
+
+// STA iface conversion methods.
+bool convertLegacyFeaturesToHidlStaCapabilities(uint64_t legacy_feature_set,
+ uint32_t legacy_logger_feature_set,
+ uint32_t* hidl_caps);
+bool convertLegacyApfCapabilitiesToHidl(const legacy_hal::PacketFilterCapabilities& legacy_caps,
+ StaApfPacketFilterCapabilities* hidl_caps);
+bool convertLegacyGscanCapabilitiesToHidl(const legacy_hal::wifi_gscan_capabilities& legacy_caps,
+ StaBackgroundScanCapabilities* hidl_caps);
+legacy_hal::wifi_band convertHidlWifiBandToLegacy(V1_0::WifiBand band);
+bool convertHidlGscanParamsToLegacy(const StaBackgroundScanParameters& hidl_scan_params,
+ legacy_hal::wifi_scan_cmd_params* legacy_scan_params);
+// |has_ie_data| indicates whether or not the wifi_scan_result includes 802.11
+// Information Elements (IEs)
+bool convertLegacyGscanResultToHidl(const legacy_hal::wifi_scan_result& legacy_scan_result,
+ bool has_ie_data, StaScanResult* hidl_scan_result);
+// |cached_results| is assumed to not include IEs.
+bool convertLegacyVectorOfCachedGscanResultsToHidl(
+ const std::vector<legacy_hal::wifi_cached_scan_results>& legacy_cached_scan_results,
+ std::vector<StaScanData>* hidl_scan_datas);
+bool convertLegacyLinkLayerStatsToHidl(const legacy_hal::LinkLayerStats& legacy_stats,
+ V1_6::StaLinkLayerStats* hidl_stats);
+bool convertLegacyRoamingCapabilitiesToHidl(
+ const legacy_hal::wifi_roaming_capabilities& legacy_caps,
+ StaRoamingCapabilities* hidl_caps);
+bool convertHidlRoamingConfigToLegacy(const StaRoamingConfig& hidl_config,
+ legacy_hal::wifi_roaming_config* legacy_config);
+legacy_hal::fw_roaming_state_t convertHidlRoamingStateToLegacy(StaRoamingState state);
+bool convertLegacyVectorOfDebugTxPacketFateToHidl(
+ const std::vector<legacy_hal::wifi_tx_report>& legacy_fates,
+ std::vector<WifiDebugTxPacketFateReport>* hidl_fates);
+bool convertLegacyVectorOfDebugRxPacketFateToHidl(
+ const std::vector<legacy_hal::wifi_rx_report>& legacy_fates,
+ std::vector<WifiDebugRxPacketFateReport>* hidl_fates);
+
+// NAN iface conversion methods.
+void convertToWifiNanStatus(legacy_hal::NanStatusType type, const char* str, size_t max_len,
+ WifiNanStatus* wifiNanStatus);
+bool convertHidlNanEnableRequestToLegacy(const V1_4::NanEnableRequest& hidl_request,
+ legacy_hal::NanEnableRequest* legacy_request);
+bool convertHidlNanConfigRequestToLegacy(const V1_4::NanConfigRequest& hidl_request,
+ legacy_hal::NanConfigRequest* legacy_request);
+bool convertHidlNanEnableRequest_1_6ToLegacy(
+ const V1_4::NanEnableRequest& hidl_request1,
+ const V1_6::NanConfigRequestSupplemental& hidl_request2,
+ legacy_hal::NanEnableRequest* legacy_request);
+bool convertHidlNanConfigRequest_1_6ToLegacy(
+ const V1_4::NanConfigRequest& hidl_request1,
+ const V1_6::NanConfigRequestSupplemental& hidl_request2,
+ legacy_hal::NanConfigRequest* legacy_request);
+bool convertHidlNanPublishRequestToLegacy(const V1_6::NanPublishRequest& hidl_request,
+ legacy_hal::NanPublishRequest* legacy_request);
+bool convertHidlNanSubscribeRequestToLegacy(const V1_0::NanSubscribeRequest& hidl_request,
+ legacy_hal::NanSubscribeRequest* legacy_request);
+bool convertHidlNanTransmitFollowupRequestToLegacy(
+ const NanTransmitFollowupRequest& hidl_request,
+ legacy_hal::NanTransmitFollowupRequest* legacy_request);
+bool convertHidlNanDataPathInitiatorRequestToLegacy(
+ const V1_0::NanInitiateDataPathRequest& hidl_request,
+ legacy_hal::NanDataPathInitiatorRequest* legacy_request);
+bool convertHidlNanDataPathIndicationResponseToLegacy(
+ const V1_0::NanRespondToDataPathIndicationRequest& hidl_response,
+ legacy_hal::NanDataPathIndicationResponse* legacy_response);
+bool convertHidlNanDataPathInitiatorRequest_1_6ToLegacy(
+ const V1_6::NanInitiateDataPathRequest& hidl_request,
+ legacy_hal::NanDataPathInitiatorRequest* legacy_request);
+bool convertHidlNanDataPathIndicationResponse_1_6ToLegacy(
+ const V1_6::NanRespondToDataPathIndicationRequest& hidl_response,
+ legacy_hal::NanDataPathIndicationResponse* legacy_response);
+
+bool convertLegacyNanResponseHeaderToHidl(const legacy_hal::NanResponseMsg& legacy_response,
+ WifiNanStatus* wifiNanStatus);
+bool convertLegacyNanCapabilitiesResponseToHidl(const legacy_hal::NanCapabilities& legacy_response,
+ V1_6::NanCapabilities* hidl_response);
+bool convertLegacyNanMatchIndToHidl(const legacy_hal::NanMatchInd& legacy_ind,
+ V1_6::NanMatchInd* hidl_ind);
+bool convertLegacyNanFollowupIndToHidl(const legacy_hal::NanFollowupInd& legacy_ind,
+ NanFollowupReceivedInd* hidl_ind);
+bool convertLegacyNanDataPathRequestIndToHidl(const legacy_hal::NanDataPathRequestInd& legacy_ind,
+ NanDataPathRequestInd* hidl_ind);
+bool convertLegacyNanDataPathConfirmIndToHidl(const legacy_hal::NanDataPathConfirmInd& legacy_ind,
+ V1_6::NanDataPathConfirmInd* hidl_ind);
+bool convertLegacyNanDataPathScheduleUpdateIndToHidl(
+ const legacy_hal::NanDataPathScheduleUpdateInd& legacy_ind,
+ V1_6::NanDataPathScheduleUpdateInd* hidl_ind);
+
+// RTT controller conversion methods.
+bool convertHidlVectorOfRttConfigToLegacy(const std::vector<V1_6::RttConfig>& hidl_configs,
+ std::vector<legacy_hal::wifi_rtt_config>* legacy_configs);
+bool convertHidlRttLciInformationToLegacy(const RttLciInformation& hidl_info,
+ legacy_hal::wifi_lci_information* legacy_info);
+bool convertHidlRttLcrInformationToLegacy(const RttLcrInformation& hidl_info,
+ legacy_hal::wifi_lcr_information* legacy_info);
+bool convertHidlRttResponderToLegacy(const V1_6::RttResponder& hidl_responder,
+ legacy_hal::wifi_rtt_responder* legacy_responder);
+bool convertHidlWifiChannelInfoToLegacy(const V1_6::WifiChannelInfo& hidl_info,
+ legacy_hal::wifi_channel_info* legacy_info);
+bool convertLegacyRttResponderToHidl(const legacy_hal::wifi_rtt_responder& legacy_responder,
+ V1_6::RttResponder* hidl_responder);
+bool convertLegacyRttCapabilitiesToHidl(
+ const legacy_hal::wifi_rtt_capabilities& legacy_capabilities,
+ V1_6::RttCapabilities* hidl_capabilities);
+bool convertLegacyVectorOfRttResultToHidl(
+ const std::vector<const legacy_hal::wifi_rtt_result*>& legacy_results,
+ std::vector<V1_6::RttResult>* hidl_results);
+uint32_t convertHidlWifiBandToLegacyMacBand(V1_5::WifiBand band);
+uint32_t convertHidlWifiIfaceModeToLegacy(uint32_t hidl_iface_mask);
+uint32_t convertHidlUsableChannelFilterToLegacy(uint32_t hidl_filter_mask);
+bool convertLegacyWifiUsableChannelsToHidl(
+ const std::vector<legacy_hal::wifi_usable_channel>& legacy_usable_channels,
+ std::vector<V1_6::WifiUsableChannel>* hidl_usable_channels);
+bool convertLegacyPeerInfoStatsToHidl(const legacy_hal::WifiPeerInfo& legacy_peer_info_stats,
+ V1_6::StaPeerInfo* hidl_peer_info_stats);
+bool convertLegacyWifiRateInfoToHidl(const legacy_hal::wifi_rate& legacy_rate,
+ V1_6::WifiRateInfo* hidl_rate);
+} // namespace hidl_struct_util
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+
+#endif // HIDL_STRUCT_UTIL_H_
diff --git a/wifi/1.6/default/hidl_sync_util.cpp b/wifi/1.6/default/hidl_sync_util.cpp
new file mode 100644
index 0000000..358d95e
--- /dev/null
+++ b/wifi/1.6/default/hidl_sync_util.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "hidl_sync_util.h"
+
+namespace {
+std::recursive_mutex g_mutex;
+} // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace hidl_sync_util {
+
+std::unique_lock<std::recursive_mutex> acquireGlobalLock() {
+ return std::unique_lock<std::recursive_mutex>{g_mutex};
+}
+
+} // namespace hidl_sync_util
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.6/default/hidl_sync_util.h b/wifi/1.6/default/hidl_sync_util.h
new file mode 100644
index 0000000..2c1c37b
--- /dev/null
+++ b/wifi/1.6/default/hidl_sync_util.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HIDL_SYNC_UTIL_H_
+#define HIDL_SYNC_UTIL_H_
+
+#include <mutex>
+
+// Utility that provides a global lock to synchronize access between
+// the HIDL thread and the legacy HAL's event loop.
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace hidl_sync_util {
+std::unique_lock<std::recursive_mutex> acquireGlobalLock();
+} // namespace hidl_sync_util
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+#endif // HIDL_SYNC_UTIL_H_
diff --git a/wifi/1.6/default/ringbuffer.cpp b/wifi/1.6/default/ringbuffer.cpp
new file mode 100644
index 0000000..981bf7b
--- /dev/null
+++ b/wifi/1.6/default/ringbuffer.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+
+#include "ringbuffer.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+
+Ringbuffer::Ringbuffer(size_t maxSize) : size_(0), maxSize_(maxSize) {}
+
+enum Ringbuffer::AppendStatus Ringbuffer::append(const std::vector<uint8_t>& input) {
+ if (input.size() == 0) {
+ return AppendStatus::FAIL_IP_BUFFER_ZERO;
+ }
+ if (input.size() > maxSize_) {
+ LOG(INFO) << "Oversized message of " << input.size() << " bytes is dropped";
+ return AppendStatus::FAIL_IP_BUFFER_EXCEEDED_MAXSIZE;
+ }
+ data_.push_back(input);
+ size_ += input.size() * sizeof(input[0]);
+ while (size_ > maxSize_) {
+ if (data_.front().size() <= 0 || data_.front().size() > maxSize_) {
+ LOG(ERROR) << "First buffer in the ring buffer is Invalid. Size: "
+ << data_.front().size();
+ return AppendStatus::FAIL_RING_BUFFER_CORRUPTED;
+ }
+ size_ -= data_.front().size() * sizeof(data_.front()[0]);
+ data_.pop_front();
+ }
+ return AppendStatus::SUCCESS;
+}
+
+const std::list<std::vector<uint8_t>>& Ringbuffer::getData() const {
+ return data_;
+}
+
+void Ringbuffer::clear() {
+ data_.clear();
+ size_ = 0;
+}
+
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.6/default/ringbuffer.h b/wifi/1.6/default/ringbuffer.h
new file mode 100644
index 0000000..c6a1e4c
--- /dev/null
+++ b/wifi/1.6/default/ringbuffer.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef RINGBUFFER_H_
+#define RINGBUFFER_H_
+
+#include <list>
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+
+/**
+ * Ringbuffer object used to store debug data.
+ */
+class Ringbuffer {
+ public:
+ // Error codes for the append ring buffer operation
+ enum AppendStatus {
+ SUCCESS,
+ FAIL_GENERIC,
+ FAIL_IP_BUFFER_ZERO,
+ FAIL_IP_BUFFER_EXCEEDED_MAXSIZE,
+ FAIL_RING_BUFFER_CORRUPTED
+ };
+ explicit Ringbuffer(size_t maxSize);
+
+ // Appends the data buffer and deletes from the front until buffer is
+ // within |maxSize_|.
+ enum AppendStatus append(const std::vector<uint8_t>& input);
+ const std::list<std::vector<uint8_t>>& getData() const;
+ void clear();
+
+ private:
+ std::list<std::vector<uint8_t>> data_;
+ size_t size_;
+ size_t maxSize_;
+};
+
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+
+#endif // RINGBUFFER_H_
diff --git a/wifi/1.6/default/service.cpp b/wifi/1.6/default/service.cpp
new file mode 100644
index 0000000..c874d8b
--- /dev/null
+++ b/wifi/1.6/default/service.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <hidl/HidlLazyUtils.h>
+#include <hidl/HidlTransportSupport.h>
+#include <signal.h>
+#include <utils/Looper.h>
+#include <utils/StrongPointer.h>
+
+#include "wifi.h"
+#include "wifi_feature_flags.h"
+#include "wifi_legacy_hal.h"
+#include "wifi_legacy_hal_factory.h"
+#include "wifi_mode_controller.h"
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::hardware::LazyServiceRegistrar;
+using android::hardware::wifi::V1_6::implementation::feature_flags::WifiFeatureFlags;
+using android::hardware::wifi::V1_6::implementation::legacy_hal::WifiLegacyHal;
+using android::hardware::wifi::V1_6::implementation::legacy_hal::WifiLegacyHalFactory;
+using android::hardware::wifi::V1_6::implementation::mode_controller::WifiModeController;
+
+#ifdef LAZY_SERVICE
+const bool kLazyService = true;
+#else
+const bool kLazyService = false;
+#endif
+
+int main(int /*argc*/, char** argv) {
+ signal(SIGPIPE, SIG_IGN);
+ android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM));
+ LOG(INFO) << "Wifi Hal is booting up...";
+
+ configureRpcThreadpool(1, true /* callerWillJoin */);
+
+ const auto iface_tool = std::make_shared<android::wifi_system::InterfaceTool>();
+ const auto legacy_hal_factory = std::make_shared<WifiLegacyHalFactory>(iface_tool);
+
+ // Setup hwbinder service
+ android::sp<android::hardware::wifi::V1_6::IWifi> service =
+ new android::hardware::wifi::V1_6::implementation::Wifi(
+ iface_tool, legacy_hal_factory, std::make_shared<WifiModeController>(),
+ std::make_shared<WifiFeatureFlags>());
+ if (kLazyService) {
+ auto registrar = LazyServiceRegistrar::getInstance();
+ CHECK_EQ(registrar.registerService(service), android::NO_ERROR)
+ << "Failed to register wifi HAL";
+ } else {
+ CHECK_EQ(service->registerAsService(), android::NO_ERROR) << "Failed to register wifi HAL";
+ }
+
+ joinRpcThreadpool();
+
+ LOG(INFO) << "Wifi Hal is terminating...";
+ return 0;
+}
diff --git a/wifi/1.6/default/tests/hidl_struct_util_unit_tests.cpp b/wifi/1.6/default/tests/hidl_struct_util_unit_tests.cpp
new file mode 100644
index 0000000..0dd0aa1
--- /dev/null
+++ b/wifi/1.6/default/tests/hidl_struct_util_unit_tests.cpp
@@ -0,0 +1,486 @@
+/*
+ * Copyright (C) 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <gmock/gmock.h>
+
+#undef NAN
+#include "hidl_struct_util.h"
+
+using testing::Test;
+
+namespace {
+constexpr uint32_t kMacId1 = 1;
+constexpr uint32_t kMacId2 = 2;
+constexpr uint32_t kIfaceChannel1 = 3;
+constexpr uint32_t kIfaceChannel2 = 5;
+constexpr char kIfaceName1[] = "wlan0";
+constexpr char kIfaceName2[] = "wlan1";
+} // namespace
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+using namespace android::hardware::wifi::V1_0;
+using ::android::hardware::wifi::V1_6::WifiChannelWidthInMhz;
+
+class HidlStructUtilTest : public Test {};
+
+TEST_F(HidlStructUtilTest, CanConvertLegacyWifiMacInfosToHidlWithOneMac) {
+ std::vector<legacy_hal::WifiMacInfo> legacy_mac_infos;
+ legacy_hal::WifiMacInfo legacy_mac_info1 = {
+ .wlan_mac_id = kMacId1,
+ .mac_band = legacy_hal::WLAN_MAC_5_0_BAND | legacy_hal::WLAN_MAC_2_4_BAND};
+ legacy_hal::WifiIfaceInfo legacy_iface_info1 = {.name = kIfaceName1, .channel = kIfaceChannel1};
+ legacy_hal::WifiIfaceInfo legacy_iface_info2 = {.name = kIfaceName2, .channel = kIfaceChannel2};
+ legacy_mac_info1.iface_infos.push_back(legacy_iface_info1);
+ legacy_mac_info1.iface_infos.push_back(legacy_iface_info2);
+ legacy_mac_infos.push_back(legacy_mac_info1);
+
+ std::vector<V1_4::IWifiChipEventCallback::RadioModeInfo> hidl_radio_mode_infos;
+ ASSERT_TRUE(hidl_struct_util::convertLegacyWifiMacInfosToHidl(legacy_mac_infos,
+ &hidl_radio_mode_infos));
+
+ ASSERT_EQ(1u, hidl_radio_mode_infos.size());
+ auto hidl_radio_mode_info1 = hidl_radio_mode_infos[0];
+ EXPECT_EQ(legacy_mac_info1.wlan_mac_id, hidl_radio_mode_info1.radioId);
+ EXPECT_EQ(V1_4::WifiBand::BAND_24GHZ_5GHZ, hidl_radio_mode_info1.bandInfo);
+ ASSERT_EQ(2u, hidl_radio_mode_info1.ifaceInfos.size());
+ auto hidl_iface_info1 = hidl_radio_mode_info1.ifaceInfos[0];
+ EXPECT_EQ(legacy_iface_info1.name, hidl_iface_info1.name);
+ EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info1.channel), hidl_iface_info1.channel);
+ auto hidl_iface_info2 = hidl_radio_mode_info1.ifaceInfos[1];
+ EXPECT_EQ(legacy_iface_info2.name, hidl_iface_info2.name);
+ EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info2.channel), hidl_iface_info2.channel);
+}
+
+TEST_F(HidlStructUtilTest, CanConvertLegacyWifiMacInfosToHidlWithTwoMac) {
+ std::vector<legacy_hal::WifiMacInfo> legacy_mac_infos;
+ legacy_hal::WifiMacInfo legacy_mac_info1 = {.wlan_mac_id = kMacId1,
+ .mac_band = legacy_hal::WLAN_MAC_5_0_BAND};
+ legacy_hal::WifiIfaceInfo legacy_iface_info1 = {.name = kIfaceName1, .channel = kIfaceChannel1};
+ legacy_hal::WifiMacInfo legacy_mac_info2 = {.wlan_mac_id = kMacId2,
+ .mac_band = legacy_hal::WLAN_MAC_2_4_BAND};
+ legacy_hal::WifiIfaceInfo legacy_iface_info2 = {.name = kIfaceName2, .channel = kIfaceChannel2};
+ legacy_mac_info1.iface_infos.push_back(legacy_iface_info1);
+ legacy_mac_infos.push_back(legacy_mac_info1);
+ legacy_mac_info2.iface_infos.push_back(legacy_iface_info2);
+ legacy_mac_infos.push_back(legacy_mac_info2);
+
+ std::vector<V1_4::IWifiChipEventCallback::RadioModeInfo> hidl_radio_mode_infos;
+ ASSERT_TRUE(hidl_struct_util::convertLegacyWifiMacInfosToHidl(legacy_mac_infos,
+ &hidl_radio_mode_infos));
+
+ ASSERT_EQ(2u, hidl_radio_mode_infos.size());
+
+ // Find mac info 1.
+ const auto hidl_radio_mode_info1 =
+ std::find_if(hidl_radio_mode_infos.begin(), hidl_radio_mode_infos.end(),
+ [&legacy_mac_info1](const V1_4::IWifiChipEventCallback::RadioModeInfo& x) {
+ return x.radioId == legacy_mac_info1.wlan_mac_id;
+ });
+ ASSERT_NE(hidl_radio_mode_infos.end(), hidl_radio_mode_info1);
+ EXPECT_EQ(V1_4::WifiBand::BAND_5GHZ, hidl_radio_mode_info1->bandInfo);
+ ASSERT_EQ(1u, hidl_radio_mode_info1->ifaceInfos.size());
+ auto hidl_iface_info1 = hidl_radio_mode_info1->ifaceInfos[0];
+ EXPECT_EQ(legacy_iface_info1.name, hidl_iface_info1.name);
+ EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info1.channel), hidl_iface_info1.channel);
+
+ // Find mac info 2.
+ const auto hidl_radio_mode_info2 =
+ std::find_if(hidl_radio_mode_infos.begin(), hidl_radio_mode_infos.end(),
+ [&legacy_mac_info2](const V1_4::IWifiChipEventCallback::RadioModeInfo& x) {
+ return x.radioId == legacy_mac_info2.wlan_mac_id;
+ });
+ ASSERT_NE(hidl_radio_mode_infos.end(), hidl_radio_mode_info2);
+ EXPECT_EQ(V1_4::WifiBand::BAND_24GHZ, hidl_radio_mode_info2->bandInfo);
+ ASSERT_EQ(1u, hidl_radio_mode_info2->ifaceInfos.size());
+ auto hidl_iface_info2 = hidl_radio_mode_info2->ifaceInfos[0];
+ EXPECT_EQ(legacy_iface_info2.name, hidl_iface_info2.name);
+ EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info2.channel), hidl_iface_info2.channel);
+}
+
+TEST_F(HidlStructUtilTest, canConvertLegacyLinkLayerStatsToHidl) {
+ legacy_hal::LinkLayerStats legacy_stats{};
+ legacy_stats.radios.push_back(legacy_hal::LinkLayerRadioStats{});
+ legacy_stats.radios.push_back(legacy_hal::LinkLayerRadioStats{});
+ legacy_stats.peers.push_back(legacy_hal::WifiPeerInfo{});
+ legacy_stats.peers.push_back(legacy_hal::WifiPeerInfo{});
+ legacy_stats.iface.beacon_rx = rand();
+ legacy_stats.iface.rssi_mgmt = rand();
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu = rand();
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].tx_mpdu = rand();
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].mpdu_lost = rand();
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].retries = rand();
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_min = rand();
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_max = rand();
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_avg = rand();
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_num_samples = rand();
+
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].rx_mpdu = rand();
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].tx_mpdu = rand();
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].mpdu_lost = rand();
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].retries = rand();
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_min = rand();
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_max = rand();
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_avg = rand();
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_num_samples = rand();
+
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].rx_mpdu = rand();
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].tx_mpdu = rand();
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].mpdu_lost = rand();
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].retries = rand();
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_min = rand();
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_max = rand();
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_avg = rand();
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_num_samples = rand();
+
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].rx_mpdu = rand();
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].tx_mpdu = rand();
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost = rand();
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries = rand();
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_min = rand();
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_max = rand();
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_avg = rand();
+ legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_num_samples = rand();
+
+ legacy_stats.iface.info.time_slicing_duty_cycle_percent = rand();
+ legacy_stats.iface.num_peers = 1;
+
+ for (auto& radio : legacy_stats.radios) {
+ radio.stats.radio = rand();
+ radio.stats.on_time = rand();
+ radio.stats.tx_time = rand();
+ radio.stats.rx_time = rand();
+ radio.stats.on_time_scan = rand();
+ radio.stats.on_time_nbd = rand();
+ radio.stats.on_time_gscan = rand();
+ radio.stats.on_time_roam_scan = rand();
+ radio.stats.on_time_pno_scan = rand();
+ radio.stats.on_time_hs20 = rand();
+ for (int i = 0; i < 4; i++) {
+ radio.tx_time_per_levels.push_back(rand());
+ }
+
+ legacy_hal::wifi_channel_stat channel_stat1 = {
+ .channel = {legacy_hal::WIFI_CHAN_WIDTH_20, 2437, 2437, 0},
+ .on_time = 0x1111,
+ .cca_busy_time = 0x55,
+ };
+ legacy_hal::wifi_channel_stat channel_stat2 = {
+ .channel = {legacy_hal::WIFI_CHAN_WIDTH_20, 5180, 5180, 0},
+ .on_time = 0x2222,
+ .cca_busy_time = 0x66,
+ };
+ radio.channel_stats.push_back(channel_stat1);
+ radio.channel_stats.push_back(channel_stat2);
+ }
+
+ for (auto& peer : legacy_stats.peers) {
+ peer.peer_info.bssload.sta_count = rand();
+ peer.peer_info.bssload.chan_util = rand();
+ wifi_rate_stat rate_stat1 = {
+ .rate = {3, 1, 2, 5, 0, 0},
+ .tx_mpdu = 0,
+ .rx_mpdu = 1,
+ .mpdu_lost = 2,
+ .retries = 3,
+ .retries_short = 4,
+ .retries_long = 5,
+ };
+ wifi_rate_stat rate_stat2 = {
+ .rate = {2, 2, 1, 6, 0, 1},
+ .tx_mpdu = 6,
+ .rx_mpdu = 7,
+ .mpdu_lost = 8,
+ .retries = 9,
+ .retries_short = 10,
+ .retries_long = 11,
+ };
+ peer.rate_stats.push_back(rate_stat1);
+ peer.rate_stats.push_back(rate_stat2);
+ }
+
+ V1_6::StaLinkLayerStats converted{};
+ hidl_struct_util::convertLegacyLinkLayerStatsToHidl(legacy_stats, &converted);
+ EXPECT_EQ(legacy_stats.iface.beacon_rx, converted.iface.V1_0.beaconRx);
+ EXPECT_EQ(legacy_stats.iface.rssi_mgmt, converted.iface.V1_0.avgRssiMgmt);
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu,
+ converted.iface.V1_0.wmeBePktStats.rxMpdu);
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].tx_mpdu,
+ converted.iface.V1_0.wmeBePktStats.txMpdu);
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].mpdu_lost,
+ converted.iface.V1_0.wmeBePktStats.lostMpdu);
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].retries,
+ converted.iface.V1_0.wmeBePktStats.retries);
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_min,
+ converted.iface.wmeBeContentionTimeStats.contentionTimeMinInUsec);
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_max,
+ converted.iface.wmeBeContentionTimeStats.contentionTimeMaxInUsec);
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_avg,
+ converted.iface.wmeBeContentionTimeStats.contentionTimeAvgInUsec);
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_num_samples,
+ converted.iface.wmeBeContentionTimeStats.contentionNumSamples);
+
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].rx_mpdu,
+ converted.iface.V1_0.wmeBkPktStats.rxMpdu);
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].tx_mpdu,
+ converted.iface.V1_0.wmeBkPktStats.txMpdu);
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].mpdu_lost,
+ converted.iface.V1_0.wmeBkPktStats.lostMpdu);
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].retries,
+ converted.iface.V1_0.wmeBkPktStats.retries);
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_min,
+ converted.iface.wmeBkContentionTimeStats.contentionTimeMinInUsec);
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_max,
+ converted.iface.wmeBkContentionTimeStats.contentionTimeMaxInUsec);
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_avg,
+ converted.iface.wmeBkContentionTimeStats.contentionTimeAvgInUsec);
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_num_samples,
+ converted.iface.wmeBkContentionTimeStats.contentionNumSamples);
+
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].rx_mpdu,
+ converted.iface.V1_0.wmeViPktStats.rxMpdu);
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].tx_mpdu,
+ converted.iface.V1_0.wmeViPktStats.txMpdu);
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].mpdu_lost,
+ converted.iface.V1_0.wmeViPktStats.lostMpdu);
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].retries,
+ converted.iface.V1_0.wmeViPktStats.retries);
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_min,
+ converted.iface.wmeViContentionTimeStats.contentionTimeMinInUsec);
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_max,
+ converted.iface.wmeViContentionTimeStats.contentionTimeMaxInUsec);
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_avg,
+ converted.iface.wmeViContentionTimeStats.contentionTimeAvgInUsec);
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_num_samples,
+ converted.iface.wmeViContentionTimeStats.contentionNumSamples);
+
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].rx_mpdu,
+ converted.iface.V1_0.wmeVoPktStats.rxMpdu);
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].tx_mpdu,
+ converted.iface.V1_0.wmeVoPktStats.txMpdu);
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost,
+ converted.iface.V1_0.wmeVoPktStats.lostMpdu);
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries,
+ converted.iface.V1_0.wmeVoPktStats.retries);
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_min,
+ converted.iface.wmeVoContentionTimeStats.contentionTimeMinInUsec);
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_max,
+ converted.iface.wmeVoContentionTimeStats.contentionTimeMaxInUsec);
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_avg,
+ converted.iface.wmeVoContentionTimeStats.contentionTimeAvgInUsec);
+ EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_num_samples,
+ converted.iface.wmeVoContentionTimeStats.contentionNumSamples);
+
+ EXPECT_EQ(legacy_stats.iface.info.time_slicing_duty_cycle_percent,
+ converted.iface.timeSliceDutyCycleInPercent);
+
+ EXPECT_EQ(legacy_stats.radios.size(), converted.radios.size());
+ for (size_t i = 0; i < legacy_stats.radios.size(); i++) {
+ EXPECT_EQ(legacy_stats.radios[i].stats.radio, converted.radios[i].radioId);
+ EXPECT_EQ(legacy_stats.radios[i].stats.on_time, converted.radios[i].V1_0.onTimeInMs);
+ EXPECT_EQ(legacy_stats.radios[i].stats.tx_time, converted.radios[i].V1_0.txTimeInMs);
+ EXPECT_EQ(legacy_stats.radios[i].stats.rx_time, converted.radios[i].V1_0.rxTimeInMs);
+ EXPECT_EQ(legacy_stats.radios[i].stats.on_time_scan,
+ converted.radios[i].V1_0.onTimeInMsForScan);
+ EXPECT_EQ(legacy_stats.radios[i].tx_time_per_levels.size(),
+ converted.radios[i].V1_0.txTimeInMsPerLevel.size());
+ for (size_t j = 0; j < legacy_stats.radios[i].tx_time_per_levels.size(); j++) {
+ EXPECT_EQ(legacy_stats.radios[i].tx_time_per_levels[j],
+ converted.radios[i].V1_0.txTimeInMsPerLevel[j]);
+ }
+ EXPECT_EQ(legacy_stats.radios[i].stats.on_time_nbd,
+ converted.radios[i].onTimeInMsForNanScan);
+ EXPECT_EQ(legacy_stats.radios[i].stats.on_time_gscan,
+ converted.radios[i].onTimeInMsForBgScan);
+ EXPECT_EQ(legacy_stats.radios[i].stats.on_time_roam_scan,
+ converted.radios[i].onTimeInMsForRoamScan);
+ EXPECT_EQ(legacy_stats.radios[i].stats.on_time_pno_scan,
+ converted.radios[i].onTimeInMsForPnoScan);
+ EXPECT_EQ(legacy_stats.radios[i].stats.on_time_hs20,
+ converted.radios[i].onTimeInMsForHs20Scan);
+ EXPECT_EQ(legacy_stats.radios[i].channel_stats.size(),
+ converted.radios[i].channelStats.size());
+ for (size_t k = 0; k < legacy_stats.radios[i].channel_stats.size(); k++) {
+ auto& legacy_channel_st = legacy_stats.radios[i].channel_stats[k];
+ EXPECT_EQ(WifiChannelWidthInMhz::WIDTH_20,
+ converted.radios[i].channelStats[k].channel.width);
+ EXPECT_EQ(WifiChannelInMhz(legacy_channel_st.channel.center_freq),
+ converted.radios[i].channelStats[k].channel.centerFreq);
+ EXPECT_EQ(WifiChannelInMhz(legacy_channel_st.channel.center_freq0),
+ converted.radios[i].channelStats[k].channel.centerFreq0);
+ EXPECT_EQ(WifiChannelInMhz(legacy_channel_st.channel.center_freq1),
+ converted.radios[i].channelStats[k].channel.centerFreq1);
+ EXPECT_EQ(legacy_channel_st.cca_busy_time,
+ converted.radios[i].channelStats[k].ccaBusyTimeInMs);
+ EXPECT_EQ(legacy_channel_st.on_time, converted.radios[i].channelStats[k].onTimeInMs);
+ }
+ }
+
+ EXPECT_EQ(legacy_stats.peers.size(), converted.iface.peers.size());
+ for (size_t i = 0; i < legacy_stats.peers.size(); i++) {
+ EXPECT_EQ(legacy_stats.peers[i].peer_info.bssload.sta_count,
+ converted.iface.peers[i].staCount);
+ EXPECT_EQ(legacy_stats.peers[i].peer_info.bssload.chan_util,
+ converted.iface.peers[i].chanUtil);
+ for (size_t j = 0; j < legacy_stats.peers[i].rate_stats.size(); j++) {
+ EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].rate.preamble,
+ (uint32_t)converted.iface.peers[i].rateStats[j].rateInfo.preamble);
+ EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].rate.nss,
+ (uint32_t)converted.iface.peers[i].rateStats[j].rateInfo.nss);
+ EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].rate.bw,
+ (uint32_t)converted.iface.peers[i].rateStats[j].rateInfo.bw);
+ EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].rate.rateMcsIdx,
+ converted.iface.peers[i].rateStats[j].rateInfo.rateMcsIdx);
+ EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].tx_mpdu,
+ converted.iface.peers[i].rateStats[j].txMpdu);
+ EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].rx_mpdu,
+ converted.iface.peers[i].rateStats[j].rxMpdu);
+ EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].mpdu_lost,
+ converted.iface.peers[i].rateStats[j].mpduLost);
+ EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].retries,
+ converted.iface.peers[i].rateStats[j].retries);
+ }
+ }
+}
+
+TEST_F(HidlStructUtilTest, CanConvertLegacyFeaturesToHidl) {
+ using HidlChipCaps = V1_3::IWifiChip::ChipCapabilityMask;
+
+ uint32_t hidle_caps;
+
+ uint32_t legacy_feature_set = WIFI_FEATURE_D2D_RTT | WIFI_FEATURE_SET_LATENCY_MODE;
+ uint32_t legacy_logger_feature_set = legacy_hal::WIFI_LOGGER_DRIVER_DUMP_SUPPORTED;
+
+ ASSERT_TRUE(hidl_struct_util::convertLegacyFeaturesToHidlChipCapabilities(
+ legacy_feature_set, legacy_logger_feature_set, &hidle_caps));
+
+ EXPECT_EQ(HidlChipCaps::DEBUG_RING_BUFFER_VENDOR_DATA |
+ HidlChipCaps::DEBUG_HOST_WAKE_REASON_STATS |
+ HidlChipCaps::DEBUG_ERROR_ALERTS | HidlChipCaps::D2D_RTT |
+ HidlChipCaps::SET_LATENCY_MODE | HidlChipCaps::DEBUG_MEMORY_DRIVER_DUMP,
+ hidle_caps);
+}
+
+void insertRadioCombination(legacy_hal::wifi_radio_combination* dst_radio_combination_ptr,
+ int num_radio_configurations,
+ legacy_hal::wifi_radio_configuration* radio_configuration) {
+ dst_radio_combination_ptr->num_radio_configurations = num_radio_configurations;
+ memcpy(dst_radio_combination_ptr->radio_configurations, radio_configuration,
+ num_radio_configurations * sizeof(legacy_hal::wifi_radio_configuration));
+}
+
+void verifyRadioCombination(WifiRadioCombination* radioCombination, size_t num_radio_configurations,
+ legacy_hal::wifi_radio_configuration* radio_configuration) {
+ EXPECT_EQ(num_radio_configurations, radioCombination->radioConfigurations.size());
+ for (size_t i = 0; i < num_radio_configurations; i++) {
+ EXPECT_EQ(hidl_struct_util::convertLegacyMacBandToHidlWifiBand(radio_configuration->band),
+ radioCombination->radioConfigurations[i].bandInfo);
+ EXPECT_EQ(hidl_struct_util::convertLegacyAntennaConfigurationToHidl(
+ radio_configuration->antenna_cfg),
+ radioCombination->radioConfigurations[i].antennaMode);
+ radio_configuration++;
+ }
+}
+
+TEST_F(HidlStructUtilTest, canConvertLegacyRadioCombinationsMatrixToHidl) {
+ legacy_hal::wifi_radio_configuration radio_configurations_array1[] = {
+ {.band = legacy_hal::WLAN_MAC_2_4_BAND, .antenna_cfg = legacy_hal::WIFI_ANTENNA_1X1},
+ };
+ legacy_hal::wifi_radio_configuration radio_configurations_array2[] = {
+ {.band = legacy_hal::WLAN_MAC_2_4_BAND, .antenna_cfg = legacy_hal::WIFI_ANTENNA_2X2},
+ {.band = legacy_hal::WLAN_MAC_5_0_BAND, .antenna_cfg = legacy_hal::WIFI_ANTENNA_3X3},
+ };
+ legacy_hal::wifi_radio_configuration radio_configurations_array3[] = {
+ {.band = legacy_hal::WLAN_MAC_2_4_BAND, .antenna_cfg = legacy_hal::WIFI_ANTENNA_2X2},
+ {.band = legacy_hal::WLAN_MAC_6_0_BAND, .antenna_cfg = legacy_hal::WIFI_ANTENNA_1X1},
+ {.band = legacy_hal::WLAN_MAC_5_0_BAND, .antenna_cfg = legacy_hal::WIFI_ANTENNA_4X4},
+ };
+
+ int num_radio_configs = 0;
+ int num_combinations = 0;
+ std::array<char, 256> buffer;
+ buffer.fill(0);
+ legacy_hal::wifi_radio_combination_matrix* legacy_matrix =
+ reinterpret_cast<wifi_radio_combination_matrix*>(buffer.data());
+ legacy_hal::wifi_radio_combination* radio_combinations;
+
+ // Prepare a legacy wifi_radio_combination_matrix
+ legacy_matrix->num_radio_combinations = 3;
+ // Insert first combination
+ radio_combinations =
+ (legacy_hal::wifi_radio_combination*)((char*)legacy_matrix->radio_combinations);
+ insertRadioCombination(
+ radio_combinations,
+ sizeof(radio_configurations_array1) / sizeof(radio_configurations_array1[0]),
+ radio_configurations_array1);
+ num_combinations++;
+ num_radio_configs +=
+ sizeof(radio_configurations_array1) / sizeof(radio_configurations_array1[0]);
+
+ // Insert second combination
+ radio_combinations =
+ (legacy_hal::wifi_radio_combination*)((char*)legacy_matrix->radio_combinations +
+ (num_combinations *
+ sizeof(legacy_hal::wifi_radio_combination)) +
+ (num_radio_configs *
+ sizeof(wifi_radio_configuration)));
+ insertRadioCombination(
+ radio_combinations,
+ sizeof(radio_configurations_array2) / sizeof(radio_configurations_array2[0]),
+ radio_configurations_array2);
+ num_combinations++;
+ num_radio_configs +=
+ sizeof(radio_configurations_array2) / sizeof(radio_configurations_array2[0]);
+
+ // Insert third combination
+ radio_combinations =
+ (legacy_hal::wifi_radio_combination*)((char*)legacy_matrix->radio_combinations +
+ (num_combinations *
+ sizeof(legacy_hal::wifi_radio_combination)) +
+ (num_radio_configs *
+ sizeof(wifi_radio_configuration)));
+ insertRadioCombination(
+ radio_combinations,
+ sizeof(radio_configurations_array3) / sizeof(radio_configurations_array3[0]),
+ radio_configurations_array3);
+
+ V1_6::WifiRadioCombinationMatrix converted_matrix{};
+ hidl_struct_util::convertLegacyRadioCombinationsMatrixToHidl(legacy_matrix, &converted_matrix);
+
+ // Verify the conversion
+ EXPECT_EQ(legacy_matrix->num_radio_combinations, converted_matrix.radioCombinations.size());
+ verifyRadioCombination(
+ &converted_matrix.radioCombinations[0],
+ sizeof(radio_configurations_array1) / sizeof(radio_configurations_array1[0]),
+ radio_configurations_array1);
+ verifyRadioCombination(
+ &converted_matrix.radioCombinations[1],
+ sizeof(radio_configurations_array2) / sizeof(radio_configurations_array2[0]),
+ radio_configurations_array2);
+ verifyRadioCombination(
+ &converted_matrix.radioCombinations[2],
+ sizeof(radio_configurations_array3) / sizeof(radio_configurations_array3[0]),
+ radio_configurations_array3);
+}
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.6/default/tests/main.cpp b/wifi/1.6/default/tests/main.cpp
new file mode 100644
index 0000000..9aac837
--- /dev/null
+++ b/wifi/1.6/default/tests/main.cpp
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <android-base/logging.h>
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ ::testing::InitGoogleMock(&argc, argv);
+ // Force ourselves to always log to stderr
+ android::base::InitLogging(argv, android::base::StderrLogger);
+ return RUN_ALL_TESTS();
+}
diff --git a/wifi/1.6/default/tests/mock_interface_tool.cpp b/wifi/1.6/default/tests/mock_interface_tool.cpp
new file mode 100644
index 0000000..b99a164
--- /dev/null
+++ b/wifi/1.6/default/tests/mock_interface_tool.cpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <gmock/gmock.h>
+
+#undef NAN // This is weird, NAN is defined in bionic/libc/include/math.h:38
+#include "mock_interface_tool.h"
+
+namespace android {
+namespace wifi_system {
+
+MockInterfaceTool::MockInterfaceTool() {}
+
+} // namespace wifi_system
+} // namespace android
diff --git a/wifi/1.6/default/tests/mock_interface_tool.h b/wifi/1.6/default/tests/mock_interface_tool.h
new file mode 100644
index 0000000..7ce3992
--- /dev/null
+++ b/wifi/1.6/default/tests/mock_interface_tool.h
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+#ifndef MOCK_INTERFACE_TOOL_H
+#define MOCK_INTERFACE_TOOL_H
+
+#include <gmock/gmock.h>
+#include <wifi_system/interface_tool.h>
+
+namespace android {
+namespace wifi_system {
+
+class MockInterfaceTool : public InterfaceTool {
+ public:
+ MockInterfaceTool();
+
+ MOCK_METHOD1(GetUpState, bool(const char* if_name));
+ MOCK_METHOD2(SetUpState, bool(const char* if_name, bool request_up));
+ MOCK_METHOD1(SetWifiUpState, bool(bool request_up));
+ MOCK_METHOD2(SetMacAddress,
+ bool(const char* if_name, const std::array<uint8_t, ETH_ALEN>& address));
+ MOCK_METHOD1(GetFactoryMacAddress, std::array<uint8_t, ETH_ALEN>(const char* if_name));
+
+}; // class MockInterfaceTool
+
+} // namespace wifi_system
+} // namespace android
+
+#endif // MOCK_INTERFACE_TOOL_H
diff --git a/wifi/1.6/default/tests/mock_wifi_feature_flags.cpp b/wifi/1.6/default/tests/mock_wifi_feature_flags.cpp
new file mode 100644
index 0000000..d10b74c
--- /dev/null
+++ b/wifi/1.6/default/tests/mock_wifi_feature_flags.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gmock/gmock.h>
+
+#include "mock_wifi_feature_flags.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace feature_flags {
+
+MockWifiFeatureFlags::MockWifiFeatureFlags() {}
+
+} // namespace feature_flags
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.6/default/tests/mock_wifi_feature_flags.h b/wifi/1.6/default/tests/mock_wifi_feature_flags.h
new file mode 100644
index 0000000..fbe1f7a
--- /dev/null
+++ b/wifi/1.6/default/tests/mock_wifi_feature_flags.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MOCK_WIFI_FEATURE_FLAGS_H_
+#define MOCK_WIFI_FEATURE_FLAGS_H_
+
+#include <gmock/gmock.h>
+#undef NAN // This is weird, NAN is defined in bionic/libc/include/math.h:38
+
+#include "wifi_feature_flags.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace feature_flags {
+
+class MockWifiFeatureFlags : public WifiFeatureFlags {
+ public:
+ MockWifiFeatureFlags();
+
+ MOCK_METHOD1(getChipModes, std::vector<V1_6::IWifiChip::ChipMode>(bool is_primary));
+ MOCK_METHOD0(isApMacRandomizationDisabled, bool());
+};
+
+} // namespace feature_flags
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+
+#endif // MOCK_WIFI_FEATURE_FLAGS_H_
diff --git a/wifi/1.6/default/tests/mock_wifi_iface_util.cpp b/wifi/1.6/default/tests/mock_wifi_iface_util.cpp
new file mode 100644
index 0000000..24b16cb
--- /dev/null
+++ b/wifi/1.6/default/tests/mock_wifi_iface_util.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <gmock/gmock.h>
+
+#undef NAN // This is weird, NAN is defined in bionic/libc/include/math.h:38
+#include "mock_wifi_iface_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace iface_util {
+
+MockWifiIfaceUtil::MockWifiIfaceUtil(const std::weak_ptr<wifi_system::InterfaceTool> iface_tool,
+ const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal)
+ : WifiIfaceUtil(iface_tool, legacy_hal) {}
+} // namespace iface_util
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.6/default/tests/mock_wifi_iface_util.h b/wifi/1.6/default/tests/mock_wifi_iface_util.h
new file mode 100644
index 0000000..2701c36
--- /dev/null
+++ b/wifi/1.6/default/tests/mock_wifi_iface_util.h
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+#ifndef MOCK_WIFI_IFACE_UTIL_H_
+#define MOCK_WIFI_IFACE_UTIL_H_
+
+#include <gmock/gmock.h>
+
+#include "wifi_iface_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace iface_util {
+
+class MockWifiIfaceUtil : public WifiIfaceUtil {
+ public:
+ MockWifiIfaceUtil(const std::weak_ptr<wifi_system::InterfaceTool> iface_tool,
+ const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
+ MOCK_METHOD1(getFactoryMacAddress, std::array<uint8_t, 6>(const std::string&));
+ MOCK_METHOD2(setMacAddress, bool(const std::string&, const std::array<uint8_t, 6>&));
+ MOCK_METHOD0(getOrCreateRandomMacAddress, std::array<uint8_t, 6>());
+ MOCK_METHOD2(registerIfaceEventHandlers, void(const std::string&, IfaceEventHandlers));
+ MOCK_METHOD1(unregisterIfaceEventHandlers, void(const std::string&));
+ MOCK_METHOD2(setUpState, bool(const std::string&, bool));
+ MOCK_METHOD1(ifNameToIndex, unsigned(const std::string&));
+};
+} // namespace iface_util
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+
+#endif // MOCK_WIFI_IFACE_UTIL_H_
diff --git a/wifi/1.6/default/tests/mock_wifi_legacy_hal.cpp b/wifi/1.6/default/tests/mock_wifi_legacy_hal.cpp
new file mode 100644
index 0000000..2c55861
--- /dev/null
+++ b/wifi/1.6/default/tests/mock_wifi_legacy_hal.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <gmock/gmock.h>
+
+#undef NAN // This is weird, NAN is defined in bionic/libc/include/math.h:38
+#include "mock_wifi_legacy_hal.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace legacy_hal {
+
+MockWifiLegacyHal::MockWifiLegacyHal(const std::weak_ptr<wifi_system::InterfaceTool> iface_tool,
+ const wifi_hal_fn& fn, bool is_primary)
+ : WifiLegacyHal(iface_tool, fn, is_primary) {}
+} // namespace legacy_hal
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.6/default/tests/mock_wifi_legacy_hal.h b/wifi/1.6/default/tests/mock_wifi_legacy_hal.h
new file mode 100644
index 0000000..85dbf0f
--- /dev/null
+++ b/wifi/1.6/default/tests/mock_wifi_legacy_hal.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MOCK_WIFI_LEGACY_HAL_H_
+#define MOCK_WIFI_LEGACY_HAL_H_
+
+#include <gmock/gmock.h>
+
+#include "wifi_legacy_hal.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace legacy_hal {
+
+class MockWifiLegacyHal : public WifiLegacyHal {
+ public:
+ MockWifiLegacyHal(const std::weak_ptr<wifi_system::InterfaceTool> iface_tool,
+ const wifi_hal_fn& fn, bool is_primary);
+ MOCK_METHOD0(initialize, wifi_error());
+ MOCK_METHOD0(start, wifi_error());
+ MOCK_METHOD2(stop,
+ wifi_error(std::unique_lock<std::recursive_mutex>*, const std::function<void()>&));
+ MOCK_METHOD2(setDfsFlag, wifi_error(const std::string&, bool));
+ MOCK_METHOD2(registerRadioModeChangeCallbackHandler,
+ wifi_error(const std::string&, const on_radio_mode_change_callback&));
+ MOCK_METHOD1(getFirmwareVersion,
+ std::pair<wifi_error, std::string>(const std::string& iface_name));
+ MOCK_METHOD1(getDriverVersion,
+ std::pair<wifi_error, std::string>(const std::string& iface_name));
+
+ MOCK_METHOD2(selectTxPowerScenario,
+ wifi_error(const std::string& iface_name, wifi_power_scenario scenario));
+ MOCK_METHOD1(resetTxPowerScenario, wifi_error(const std::string& iface_name));
+ MOCK_METHOD2(nanRegisterCallbackHandlers,
+ wifi_error(const std::string&, const NanCallbackHandlers&));
+ MOCK_METHOD2(nanDisableRequest, wifi_error(const std::string&, transaction_id));
+ MOCK_METHOD3(nanDataInterfaceDelete,
+ wifi_error(const std::string&, transaction_id, const std::string&));
+ MOCK_METHOD2(createVirtualInterface,
+ wifi_error(const std::string& ifname, wifi_interface_type iftype));
+ MOCK_METHOD1(deleteVirtualInterface, wifi_error(const std::string& ifname));
+ MOCK_METHOD0(waitForDriverReady, wifi_error());
+ MOCK_METHOD2(getSupportedIfaceName, wifi_error(uint32_t, std::string&));
+ MOCK_METHOD1(registerSubsystemRestartCallbackHandler,
+ wifi_error(const on_subsystem_restart_callback&));
+ MOCK_METHOD1(getSupportedFeatureSet, std::pair<wifi_error, uint64_t>(const std::string&));
+};
+} // namespace legacy_hal
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+
+#endif // MOCK_WIFI_LEGACY_HAL_H_
diff --git a/wifi/1.6/default/tests/mock_wifi_mode_controller.cpp b/wifi/1.6/default/tests/mock_wifi_mode_controller.cpp
new file mode 100644
index 0000000..446f829
--- /dev/null
+++ b/wifi/1.6/default/tests/mock_wifi_mode_controller.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <gmock/gmock.h>
+
+#undef NAN // This is weird, NAN is defined in bionic/libc/include/math.h:38
+#include "mock_wifi_mode_controller.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace mode_controller {
+
+MockWifiModeController::MockWifiModeController() : WifiModeController() {}
+} // namespace mode_controller
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.6/default/tests/mock_wifi_mode_controller.h b/wifi/1.6/default/tests/mock_wifi_mode_controller.h
new file mode 100644
index 0000000..addcc81
--- /dev/null
+++ b/wifi/1.6/default/tests/mock_wifi_mode_controller.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MOCK_WIFI_MODE_CONTROLLER_H_
+#define MOCK_WIFI_MODE_CONTROLLER_H_
+
+#include <gmock/gmock.h>
+
+#include "wifi_mode_controller.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace mode_controller {
+
+class MockWifiModeController : public WifiModeController {
+ public:
+ MockWifiModeController();
+ MOCK_METHOD0(initialize, bool());
+ MOCK_METHOD1(changeFirmwareMode, bool(IfaceType));
+ MOCK_METHOD1(isFirmwareModeChangeNeeded, bool(IfaceType));
+ MOCK_METHOD0(deinitialize, bool());
+};
+} // namespace mode_controller
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+
+#endif // MOCK_WIFI_MODE_CONTROLLER_H_
diff --git a/wifi/1.6/default/tests/ringbuffer_unit_tests.cpp b/wifi/1.6/default/tests/ringbuffer_unit_tests.cpp
new file mode 100644
index 0000000..eb86194
--- /dev/null
+++ b/wifi/1.6/default/tests/ringbuffer_unit_tests.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <gmock/gmock.h>
+
+#include "ringbuffer.h"
+
+using testing::Return;
+using testing::Test;
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+
+class RingbufferTest : public Test {
+ public:
+ const uint32_t maxBufferSize_ = 10;
+ Ringbuffer buffer_{maxBufferSize_};
+};
+
+TEST_F(RingbufferTest, CreateEmptyBuffer) {
+ ASSERT_TRUE(buffer_.getData().empty());
+}
+
+TEST_F(RingbufferTest, CanUseFullBufferCapacity) {
+ const std::vector<uint8_t> input(maxBufferSize_ / 2, '0');
+ const std::vector<uint8_t> input2(maxBufferSize_ / 2, '1');
+ buffer_.append(input);
+ buffer_.append(input2);
+ ASSERT_EQ(2u, buffer_.getData().size());
+ EXPECT_EQ(input, buffer_.getData().front());
+ EXPECT_EQ(input2, buffer_.getData().back());
+}
+
+TEST_F(RingbufferTest, OldDataIsRemovedOnOverflow) {
+ const std::vector<uint8_t> input(maxBufferSize_ / 2, '0');
+ const std::vector<uint8_t> input2(maxBufferSize_ / 2, '1');
+ const std::vector<uint8_t> input3 = {'G'};
+ buffer_.append(input);
+ buffer_.append(input2);
+ buffer_.append(input3);
+ ASSERT_EQ(2u, buffer_.getData().size());
+ EXPECT_EQ(input2, buffer_.getData().front());
+ EXPECT_EQ(input3, buffer_.getData().back());
+}
+
+TEST_F(RingbufferTest, MultipleOldDataIsRemovedOnOverflow) {
+ const std::vector<uint8_t> input(maxBufferSize_ / 2, '0');
+ const std::vector<uint8_t> input2(maxBufferSize_ / 2, '1');
+ const std::vector<uint8_t> input3(maxBufferSize_, '2');
+ buffer_.append(input);
+ buffer_.append(input2);
+ buffer_.append(input3);
+ ASSERT_EQ(1u, buffer_.getData().size());
+ EXPECT_EQ(input3, buffer_.getData().front());
+}
+
+TEST_F(RingbufferTest, AppendingEmptyBufferDoesNotAddGarbage) {
+ const std::vector<uint8_t> input = {};
+ buffer_.append(input);
+ ASSERT_TRUE(buffer_.getData().empty());
+}
+
+TEST_F(RingbufferTest, OversizedAppendIsDropped) {
+ const std::vector<uint8_t> input(maxBufferSize_ + 1, '0');
+ buffer_.append(input);
+ ASSERT_TRUE(buffer_.getData().empty());
+}
+
+TEST_F(RingbufferTest, OversizedAppendDoesNotDropExistingData) {
+ const std::vector<uint8_t> input(maxBufferSize_, '0');
+ const std::vector<uint8_t> input2(maxBufferSize_ + 1, '1');
+ buffer_.append(input);
+ buffer_.append(input2);
+ ASSERT_EQ(1u, buffer_.getData().size());
+ EXPECT_EQ(input, buffer_.getData().front());
+}
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.6/default/tests/runtests.sh b/wifi/1.6/default/tests/runtests.sh
new file mode 100755
index 0000000..6bce3ef
--- /dev/null
+++ b/wifi/1.6/default/tests/runtests.sh
@@ -0,0 +1,26 @@
+#!/usr/bin/env bash
+
+# Copyright(C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0(the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http:// www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+if [ -z $ANDROID_BUILD_TOP ]; then
+ echo "You need to source and lunch before you can use this script"
+ exit 1
+fi
+set -e
+
+$ANDROID_BUILD_TOP/build/soong/soong_ui.bash --make-mode android.hardware.wifi@1.0-service-tests
+adb root
+adb sync data
+adb shell /data/nativetest64/vendor/android.hardware.wifi@1.0-service-tests/android.hardware.wifi@1.0-service-tests
diff --git a/wifi/1.6/default/tests/wifi_chip_unit_tests.cpp b/wifi/1.6/default/tests/wifi_chip_unit_tests.cpp
new file mode 100644
index 0000000..81117c5
--- /dev/null
+++ b/wifi/1.6/default/tests/wifi_chip_unit_tests.cpp
@@ -0,0 +1,864 @@
+/*
+ * Copyright (C) 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <cutils/properties.h>
+#include <gmock/gmock.h>
+
+#undef NAN // This is weird, NAN is defined in bionic/libc/include/math.h:38
+#include "wifi_chip.h"
+
+#include "mock_interface_tool.h"
+#include "mock_wifi_feature_flags.h"
+#include "mock_wifi_iface_util.h"
+#include "mock_wifi_legacy_hal.h"
+#include "mock_wifi_mode_controller.h"
+
+using testing::NiceMock;
+using testing::Return;
+using testing::Test;
+
+namespace {
+using android::hardware::wifi::V1_0::ChipId;
+
+constexpr ChipId kFakeChipId = 5;
+} // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+
+class WifiChipTest : public Test {
+ protected:
+ void setupV1IfaceCombination() {
+ // clang-format off
+ const hidl_vec<IWifiChip::ChipConcurrencyCombination> combinationsSta = {
+ {{{{IfaceConcurrencyType::STA}, 1}, {{IfaceConcurrencyType::P2P}, 1}}}
+ };
+ const hidl_vec<IWifiChip::ChipConcurrencyCombination> combinationsAp = {
+ {{{{IfaceConcurrencyType::AP}, 1}}}
+ };
+ const std::vector<V1_6::IWifiChip::ChipMode> modes = {
+ {feature_flags::chip_mode_ids::kV1Sta, combinationsSta},
+ {feature_flags::chip_mode_ids::kV1Ap, combinationsAp}
+ };
+ // clang-format on
+ EXPECT_CALL(*feature_flags_, getChipModes(true)).WillRepeatedly(testing::Return(modes));
+ }
+
+ void setupV1_AwareIfaceCombination() {
+ // clang-format off
+ const hidl_vec<IWifiChip::ChipConcurrencyCombination> combinationsSta = {
+ {{{{IfaceConcurrencyType::STA}, 1},
+ {{IfaceConcurrencyType::P2P, IfaceConcurrencyType::NAN}, 1}}}
+ };
+ const hidl_vec<IWifiChip::ChipConcurrencyCombination> combinationsAp = {
+ {{{{IfaceConcurrencyType::AP}, 1}}}
+ };
+ const std::vector<V1_6::IWifiChip::ChipMode> modes = {
+ {feature_flags::chip_mode_ids::kV1Sta, combinationsSta},
+ {feature_flags::chip_mode_ids::kV1Ap, combinationsAp}
+ };
+ // clang-format on
+ EXPECT_CALL(*feature_flags_, getChipModes(true)).WillRepeatedly(testing::Return(modes));
+ }
+
+ void setupV1_AwareDisabledApIfaceCombination() {
+ // clang-format off
+ const hidl_vec<IWifiChip::ChipConcurrencyCombination> combinationsSta = {
+ {{{{IfaceConcurrencyType::STA}, 1},
+ {{IfaceConcurrencyType::P2P, IfaceConcurrencyType::NAN}, 1}}}
+ };
+ const std::vector<V1_6::IWifiChip::ChipMode> modes = {
+ {feature_flags::chip_mode_ids::kV1Sta, combinationsSta}
+ };
+ // clang-format on
+ EXPECT_CALL(*feature_flags_, getChipModes(true)).WillRepeatedly(testing::Return(modes));
+ }
+
+ void setupV2_AwareIfaceCombination() {
+ // clang-format off
+ const hidl_vec<IWifiChip::ChipConcurrencyCombination> combinations = {
+ {{{{IfaceConcurrencyType::STA}, 1}, {{IfaceConcurrencyType::AP}, 1}}},
+ {{{{IfaceConcurrencyType::STA}, 1},
+ {{IfaceConcurrencyType::P2P, IfaceConcurrencyType::NAN}, 1}}}
+ };
+ const std::vector<V1_6::IWifiChip::ChipMode> modes = {
+ {feature_flags::chip_mode_ids::kV3, combinations}
+ };
+ // clang-format on
+ EXPECT_CALL(*feature_flags_, getChipModes(true)).WillRepeatedly(testing::Return(modes));
+ }
+
+ void setupV2_AwareDisabledApIfaceCombination() {
+ // clang-format off
+ const hidl_vec<IWifiChip::ChipConcurrencyCombination> combinations = {
+ {{{{IfaceConcurrencyType::STA}, 1},
+ {{IfaceConcurrencyType::P2P, IfaceConcurrencyType::NAN}, 1}}}
+ };
+ const std::vector<V1_6::IWifiChip::ChipMode> modes = {
+ {feature_flags::chip_mode_ids::kV3, combinations}
+ };
+ // clang-format on
+ EXPECT_CALL(*feature_flags_, getChipModes(true)).WillRepeatedly(testing::Return(modes));
+ }
+
+ void setup_MultiIfaceCombination() {
+ // clang-format off
+ const hidl_vec<IWifiChip::ChipConcurrencyCombination> combinations = {
+ {{{{IfaceConcurrencyType::STA}, 3}, {{IfaceConcurrencyType::AP}, 1}}}
+ };
+ const std::vector<V1_6::IWifiChip::ChipMode> modes = {
+ {feature_flags::chip_mode_ids::kV3, combinations}
+ };
+ // clang-format on
+ EXPECT_CALL(*feature_flags_, getChipModes(true)).WillRepeatedly(testing::Return(modes));
+ }
+
+ void assertNumberOfModes(uint32_t num_modes) {
+ chip_->getAvailableModes_1_6([num_modes](const WifiStatus& status,
+ const std::vector<WifiChip::ChipMode>& modes) {
+ ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+ // V2_Aware has 1 mode of operation.
+ ASSERT_EQ(num_modes, modes.size());
+ });
+ }
+
+ void findModeAndConfigureForIfaceType(const IfaceConcurrencyType& type) {
+ // This should be aligned with kInvalidModeId in wifi_chip.cpp.
+ ChipModeId mode_id = UINT32_MAX;
+ chip_->getAvailableModes_1_6([&mode_id, &type](
+ const WifiStatus& status,
+ const std::vector<WifiChip::ChipMode>& modes) {
+ ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+ for (const auto& mode : modes) {
+ for (const auto& combination : mode.availableCombinations) {
+ for (const auto& limit : combination.limits) {
+ if (limit.types.end() !=
+ std::find(limit.types.begin(), limit.types.end(), type)) {
+ mode_id = mode.id;
+ }
+ }
+ }
+ }
+ });
+ ASSERT_NE(UINT32_MAX, mode_id);
+
+ chip_->configureChip(mode_id, [](const WifiStatus& status) {
+ ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+ });
+ }
+
+ // Returns an empty string on error.
+ std::string createIface(const IfaceType& type) {
+ std::string iface_name;
+ if (type == IfaceType::AP) {
+ chip_->createApIface(
+ [&iface_name](const WifiStatus& status, const sp<V1_0::IWifiApIface>& iface) {
+ if (WifiStatusCode::SUCCESS == status.code) {
+ ASSERT_NE(iface.get(), nullptr);
+ iface->getName([&iface_name](const WifiStatus& status,
+ const hidl_string& name) {
+ ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+ iface_name = name.c_str();
+ });
+ }
+ });
+ } else if (type == IfaceType::NAN) {
+ chip_->createNanIface(
+ [&iface_name](const WifiStatus& status,
+ const sp<android::hardware::wifi::V1_0::IWifiNanIface>& iface) {
+ if (WifiStatusCode::SUCCESS == status.code) {
+ ASSERT_NE(iface.get(), nullptr);
+ iface->getName([&iface_name](const WifiStatus& status,
+ const hidl_string& name) {
+ ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+ iface_name = name.c_str();
+ });
+ }
+ });
+ } else if (type == IfaceType::P2P) {
+ chip_->createP2pIface(
+ [&iface_name](const WifiStatus& status, const sp<IWifiP2pIface>& iface) {
+ if (WifiStatusCode::SUCCESS == status.code) {
+ ASSERT_NE(iface.get(), nullptr);
+ iface->getName([&iface_name](const WifiStatus& status,
+ const hidl_string& name) {
+ ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+ iface_name = name.c_str();
+ });
+ }
+ });
+ } else if (type == IfaceType::STA) {
+ chip_->createStaIface(
+ [&iface_name](const WifiStatus& status, const sp<V1_0::IWifiStaIface>& iface) {
+ if (WifiStatusCode::SUCCESS == status.code) {
+ ASSERT_NE(iface.get(), nullptr);
+ iface->getName([&iface_name](const WifiStatus& status,
+ const hidl_string& name) {
+ ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+ iface_name = name.c_str();
+ });
+ }
+ });
+ }
+ return iface_name;
+ }
+
+ void removeIface(const IfaceType& type, const std::string& iface_name) {
+ if (type == IfaceType::AP) {
+ chip_->removeApIface(iface_name, [](const WifiStatus& status) {
+ ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+ });
+ } else if (type == IfaceType::NAN) {
+ chip_->removeNanIface(iface_name, [](const WifiStatus& status) {
+ ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+ });
+ } else if (type == IfaceType::P2P) {
+ chip_->removeP2pIface(iface_name, [](const WifiStatus& status) {
+ ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+ });
+ } else if (type == IfaceType::STA) {
+ chip_->removeStaIface(iface_name, [](const WifiStatus& status) {
+ ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+ });
+ }
+ }
+
+ bool createRttController() {
+ bool success = false;
+ chip_->createRttController_1_6(
+ NULL, [&success](const WifiStatus& status, const sp<IWifiRttController>& rtt) {
+ if (WifiStatusCode::SUCCESS == status.code) {
+ ASSERT_NE(rtt.get(), nullptr);
+ success = true;
+ }
+ });
+ return success;
+ }
+
+ static void subsystemRestartHandler(const std::string& /*error*/) {}
+
+ sp<WifiChip> chip_;
+ ChipId chip_id_ = kFakeChipId;
+ legacy_hal::wifi_hal_fn fake_func_table_;
+ std::shared_ptr<NiceMock<wifi_system::MockInterfaceTool>> iface_tool_{
+ new NiceMock<wifi_system::MockInterfaceTool>};
+ std::shared_ptr<NiceMock<legacy_hal::MockWifiLegacyHal>> legacy_hal_{
+ new NiceMock<legacy_hal::MockWifiLegacyHal>(iface_tool_, fake_func_table_, true)};
+ std::shared_ptr<NiceMock<mode_controller::MockWifiModeController>> mode_controller_{
+ new NiceMock<mode_controller::MockWifiModeController>};
+ std::shared_ptr<NiceMock<iface_util::MockWifiIfaceUtil>> iface_util_{
+ new NiceMock<iface_util::MockWifiIfaceUtil>(iface_tool_, legacy_hal_)};
+ std::shared_ptr<NiceMock<feature_flags::MockWifiFeatureFlags>> feature_flags_{
+ new NiceMock<feature_flags::MockWifiFeatureFlags>};
+
+ public:
+ void SetUp() override {
+ chip_ = new WifiChip(chip_id_, true, legacy_hal_, mode_controller_, iface_util_,
+ feature_flags_, subsystemRestartHandler);
+
+ EXPECT_CALL(*mode_controller_, changeFirmwareMode(testing::_))
+ .WillRepeatedly(testing::Return(true));
+ EXPECT_CALL(*legacy_hal_, start())
+ .WillRepeatedly(testing::Return(legacy_hal::WIFI_SUCCESS));
+ // Vendor HAL does not override the name by default.
+ EXPECT_CALL(*legacy_hal_, getSupportedIfaceName(testing::_, testing::_))
+ .WillRepeatedly(testing::Return(legacy_hal::WIFI_ERROR_UNKNOWN));
+ }
+
+ void TearDown() override {
+ // Restore default system iface names (This should ideally be using a
+ // mock).
+ property_set("wifi.interface", "wlan0");
+ property_set("wifi.concurrent.interface", "wlan1");
+ property_set("wifi.aware.interface", nullptr);
+ }
+};
+
+////////// V1 Iface Combinations ////////////
+// Mode 1 - STA + P2P
+// Mode 2 - AP
+class WifiChipV1IfaceCombinationTest : public WifiChipTest {
+ public:
+ void SetUp() override {
+ setupV1IfaceCombination();
+ WifiChipTest::SetUp();
+ // V1 has 2 modes of operation.
+ assertNumberOfModes(2u);
+ }
+};
+
+TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateSta_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+ ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateP2p_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+ ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateNan_ShouldFail) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+ ASSERT_TRUE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateAp_ShouldFail) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+ ASSERT_TRUE(createIface(IfaceType::AP).empty());
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateStaP2p_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+ ASSERT_FALSE(createIface(IfaceType::STA).empty());
+ ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateAp_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
+ ASSERT_EQ(createIface(IfaceType::AP), "wlan0");
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateSta_ShouldFail) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
+ ASSERT_TRUE(createIface(IfaceType::STA).empty());
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateP2p_ShouldFail) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
+ ASSERT_TRUE(createIface(IfaceType::STA).empty());
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateNan_ShouldFail) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
+ ASSERT_TRUE(createIface(IfaceType::NAN).empty());
+}
+
+////////// V1 + Aware Iface Combinations ////////////
+// Mode 1 - STA + P2P/NAN
+// Mode 2 - AP
+class WifiChipV1_AwareIfaceCombinationTest : public WifiChipTest {
+ public:
+ void SetUp() override {
+ setupV1_AwareIfaceCombination();
+ WifiChipTest::SetUp();
+ // V1_Aware has 2 modes of operation.
+ assertNumberOfModes(2u);
+ }
+};
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateSta_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+ ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateP2p_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+ ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateNan_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+ ASSERT_FALSE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateAp_ShouldFail) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+ ASSERT_TRUE(createIface(IfaceType::AP).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateStaP2p_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+ ASSERT_FALSE(createIface(IfaceType::STA).empty());
+ ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateStaNan_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+ ASSERT_FALSE(createIface(IfaceType::STA).empty());
+ ASSERT_FALSE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateStaP2PNan_ShouldFail) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+ ASSERT_FALSE(createIface(IfaceType::STA).empty());
+ ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+ ASSERT_TRUE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateStaNan_AfterP2pRemove_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+ ASSERT_FALSE(createIface(IfaceType::STA).empty());
+ const auto p2p_iface_name = createIface(IfaceType::P2P);
+ ASSERT_FALSE(p2p_iface_name.empty());
+ ASSERT_TRUE(createIface(IfaceType::NAN).empty());
+
+ // After removing P2P iface, NAN iface creation should succeed.
+ removeIface(IfaceType::P2P, p2p_iface_name);
+ ASSERT_FALSE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateStaP2p_AfterNanRemove_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+ ASSERT_FALSE(createIface(IfaceType::STA).empty());
+ const auto nan_iface_name = createIface(IfaceType::NAN);
+ ASSERT_FALSE(nan_iface_name.empty());
+ ASSERT_TRUE(createIface(IfaceType::P2P).empty());
+
+ // After removing NAN iface, P2P iface creation should succeed.
+ removeIface(IfaceType::NAN, nan_iface_name);
+ ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateAp_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
+ ASSERT_EQ(createIface(IfaceType::AP), "wlan0");
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateSta_ShouldFail) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
+ ASSERT_TRUE(createIface(IfaceType::STA).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateP2p_ShouldFail) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
+ ASSERT_TRUE(createIface(IfaceType::STA).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateNan_ShouldFail) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
+ ASSERT_TRUE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, RttControllerFlowStaModeNoSta) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+ ASSERT_TRUE(createRttController());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, RttControllerFlowStaModeWithSta) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+ ASSERT_FALSE(createIface(IfaceType::STA).empty());
+ ASSERT_TRUE(createRttController());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, RttControllerFlowApToSta) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
+ const auto ap_iface_name = createIface(IfaceType::AP);
+ ASSERT_FALSE(ap_iface_name.empty());
+ ASSERT_FALSE(createRttController());
+
+ removeIface(IfaceType::AP, ap_iface_name);
+
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+ ASSERT_TRUE(createRttController());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, SelectTxScenarioWithOnlySta) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+ ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+ EXPECT_CALL(*legacy_hal_, selectTxPowerScenario("wlan0", testing::_))
+ .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
+ chip_->selectTxPowerScenario_1_2(
+ V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF,
+ [](const WifiStatus& status) { ASSERT_EQ(WifiStatusCode::SUCCESS, status.code); });
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, SelectTxScenarioWithOnlyAp) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
+ ASSERT_EQ(createIface(IfaceType::AP), "wlan0");
+ EXPECT_CALL(*legacy_hal_, selectTxPowerScenario("wlan0", testing::_))
+ .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
+ chip_->selectTxPowerScenario_1_2(
+ V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF,
+ [](const WifiStatus& status) { ASSERT_EQ(WifiStatusCode::SUCCESS, status.code); });
+}
+
+////////// V2 + Aware Iface Combinations ////////////
+// Mode 1 - STA + STA/AP
+// - STA + P2P/NAN
+class WifiChipV2_AwareIfaceCombinationTest : public WifiChipTest {
+ public:
+ void SetUp() override {
+ setupV2_AwareIfaceCombination();
+ WifiChipTest::SetUp();
+ // V2_Aware has 1 mode of operation.
+ assertNumberOfModes(1u);
+ }
+};
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateSta_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+ ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateP2p_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+ ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateNan_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+ ASSERT_FALSE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateAp_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+ ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaSta_ShouldFail) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
+ ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+ ASSERT_TRUE(createIface(IfaceType::STA).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaAp_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
+ ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+ ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateApSta_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
+ ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
+ ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateSta_AfterStaApRemove_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+ const auto sta_iface_name = createIface(IfaceType::STA);
+ ASSERT_FALSE(sta_iface_name.empty());
+ const auto ap_iface_name = createIface(IfaceType::AP);
+ ASSERT_FALSE(ap_iface_name.empty());
+
+ ASSERT_TRUE(createIface(IfaceType::STA).empty());
+
+ // After removing AP & STA iface, STA iface creation should succeed.
+ removeIface(IfaceType::STA, sta_iface_name);
+ removeIface(IfaceType::AP, ap_iface_name);
+ ASSERT_FALSE(createIface(IfaceType::STA).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaP2p_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+ ASSERT_FALSE(createIface(IfaceType::STA).empty());
+ ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaNan_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+ ASSERT_FALSE(createIface(IfaceType::STA).empty());
+ ASSERT_FALSE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaP2PNan_ShouldFail) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+ ASSERT_FALSE(createIface(IfaceType::STA).empty());
+ ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+ ASSERT_TRUE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaNan_AfterP2pRemove_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+ ASSERT_FALSE(createIface(IfaceType::STA).empty());
+ const auto p2p_iface_name = createIface(IfaceType::P2P);
+ ASSERT_FALSE(p2p_iface_name.empty());
+ ASSERT_TRUE(createIface(IfaceType::NAN).empty());
+
+ // After removing P2P iface, NAN iface creation should succeed.
+ removeIface(IfaceType::P2P, p2p_iface_name);
+ ASSERT_FALSE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaP2p_AfterNanRemove_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+ ASSERT_FALSE(createIface(IfaceType::STA).empty());
+ const auto nan_iface_name = createIface(IfaceType::NAN);
+ ASSERT_FALSE(nan_iface_name.empty());
+ ASSERT_TRUE(createIface(IfaceType::P2P).empty());
+
+ // After removing NAN iface, P2P iface creation should succeed.
+ removeIface(IfaceType::NAN, nan_iface_name);
+ ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateApNan_ShouldFail) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
+ ASSERT_FALSE(createIface(IfaceType::AP).empty());
+ ASSERT_TRUE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateApP2p_ShouldFail) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
+ ASSERT_FALSE(createIface(IfaceType::AP).empty());
+ ASSERT_TRUE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, StaMode_CreateStaNan_AfterP2pRemove_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+ ASSERT_FALSE(createIface(IfaceType::STA).empty());
+ const auto p2p_iface_name = createIface(IfaceType::P2P);
+ ASSERT_FALSE(p2p_iface_name.empty());
+ ASSERT_TRUE(createIface(IfaceType::NAN).empty());
+
+ // After removing P2P iface, NAN iface creation should succeed.
+ removeIface(IfaceType::P2P, p2p_iface_name);
+ ASSERT_FALSE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, StaMode_CreateStaP2p_AfterNanRemove_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+ ASSERT_FALSE(createIface(IfaceType::STA).empty());
+ const auto nan_iface_name = createIface(IfaceType::NAN);
+ ASSERT_FALSE(nan_iface_name.empty());
+ ASSERT_TRUE(createIface(IfaceType::P2P).empty());
+
+ // After removing NAN iface, P2P iface creation should succeed.
+ removeIface(IfaceType::NAN, nan_iface_name);
+ ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaAp_EnsureDifferentIfaceNames) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
+ const auto sta_iface_name = createIface(IfaceType::STA);
+ const auto ap_iface_name = createIface(IfaceType::AP);
+ ASSERT_FALSE(sta_iface_name.empty());
+ ASSERT_FALSE(ap_iface_name.empty());
+ ASSERT_NE(sta_iface_name, ap_iface_name);
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, RttControllerFlowStaModeNoSta) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+ ASSERT_TRUE(createRttController());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, RttControllerFlowStaModeWithSta) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+ ASSERT_FALSE(createIface(IfaceType::STA).empty());
+ ASSERT_TRUE(createRttController());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, RttControllerFlow) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+ ASSERT_FALSE(createIface(IfaceType::STA).empty());
+ ASSERT_FALSE(createIface(IfaceType::AP).empty());
+ ASSERT_TRUE(createRttController());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, SelectTxScenarioWithOnlySta) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+ ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+ EXPECT_CALL(*legacy_hal_, selectTxPowerScenario("wlan0", testing::_))
+ .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
+ chip_->selectTxPowerScenario_1_2(
+ V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF,
+ [](const WifiStatus& status) { ASSERT_EQ(WifiStatusCode::SUCCESS, status.code); });
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, SelectTxScenarioWithOnlyAp) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
+ ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
+ EXPECT_CALL(*legacy_hal_, selectTxPowerScenario("wlan1", testing::_))
+ .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
+ chip_->selectTxPowerScenario_1_2(
+ V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF,
+ [](const WifiStatus& status) { ASSERT_EQ(WifiStatusCode::SUCCESS, status.code); });
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, InvalidateAndRemoveNanOnStaRemove) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+ ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+
+ // Create NAN iface
+ ASSERT_EQ(createIface(IfaceType::NAN), "wlan0");
+
+ // We should have 1 nan iface.
+ chip_->getNanIfaceNames([](const WifiStatus& status, const hidl_vec<hidl_string>& iface_names) {
+ ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+ ASSERT_EQ(iface_names.size(), 1u);
+ ASSERT_EQ(iface_names[0], "wlan0");
+ });
+ // Retrieve the exact iface object.
+ sp<android::hardware::wifi::V1_0::IWifiNanIface> nan_iface;
+ chip_->getNanIface("wlan0",
+ [&nan_iface](const WifiStatus& status,
+ const sp<android::hardware::wifi::V1_0::IWifiNanIface>& iface) {
+ ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+ ASSERT_NE(iface.get(), nullptr);
+ nan_iface = iface;
+ });
+
+ // Remove the STA iface.
+ removeIface(IfaceType::STA, "wlan0");
+ // We should have 0 nan iface now.
+ chip_->getNanIfaceNames([](const WifiStatus& status, const hidl_vec<hidl_string>& iface_names) {
+ ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+ ASSERT_EQ(iface_names.size(), 0u);
+ });
+ // Any operation on the nan iface object should return error now.
+ nan_iface->getName([](const WifiStatus& status, const std::string& /* iface_name */) {
+ ASSERT_EQ(WifiStatusCode::ERROR_WIFI_IFACE_INVALID, status.code);
+ });
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, InvalidateAndRemoveRttControllerOnStaRemove) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+ ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+
+ // Create RTT controller
+ sp<IWifiRttController> rtt_controller;
+ chip_->createRttController_1_6(
+ NULL, [&rtt_controller](const WifiStatus& status, const sp<IWifiRttController>& rtt) {
+ if (WifiStatusCode::SUCCESS == status.code) {
+ ASSERT_NE(rtt.get(), nullptr);
+ rtt_controller = rtt;
+ }
+ });
+
+ // Remove the STA iface.
+ removeIface(IfaceType::STA, "wlan0");
+
+ // Any operation on the rtt controller object should return error now.
+ rtt_controller->getBoundIface([](const WifiStatus& status, const sp<IWifiIface>& /* iface */) {
+ ASSERT_EQ(WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID, status.code);
+ });
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateNanWithSharedNanIface) {
+ property_set("wifi.aware.interface", nullptr);
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+ ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+ ASSERT_EQ(createIface(IfaceType::NAN), "wlan0");
+ removeIface(IfaceType::NAN, "wlan0");
+ EXPECT_CALL(*iface_util_, setUpState(testing::_, testing::_)).Times(0);
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateNanWithDedicatedNanIface) {
+ property_set("wifi.aware.interface", "aware0");
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+ ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+ EXPECT_CALL(*iface_util_, ifNameToIndex("aware0")).WillOnce(testing::Return(4));
+ EXPECT_CALL(*iface_util_, setUpState("aware0", true)).WillOnce(testing::Return(true));
+ ASSERT_EQ(createIface(IfaceType::NAN), "aware0");
+
+ EXPECT_CALL(*iface_util_, setUpState("aware0", false)).WillOnce(testing::Return(true));
+ removeIface(IfaceType::NAN, "aware0");
+}
+
+////////// V1 Iface Combinations when AP creation is disabled //////////
+class WifiChipV1_AwareDisabledApIfaceCombinationTest : public WifiChipTest {
+ public:
+ void SetUp() override {
+ setupV1_AwareDisabledApIfaceCombination();
+ WifiChipTest::SetUp();
+ }
+};
+
+TEST_F(WifiChipV1_AwareDisabledApIfaceCombinationTest, StaMode_CreateSta_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+ ASSERT_FALSE(createIface(IfaceType::STA).empty());
+ ASSERT_TRUE(createIface(IfaceType::AP).empty());
+}
+
+////////// V2 Iface Combinations when AP creation is disabled //////////
+class WifiChipV2_AwareDisabledApIfaceCombinationTest : public WifiChipTest {
+ public:
+ void SetUp() override {
+ setupV2_AwareDisabledApIfaceCombination();
+ WifiChipTest::SetUp();
+ }
+};
+
+TEST_F(WifiChipV2_AwareDisabledApIfaceCombinationTest, CreateSta_ShouldSucceed) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+ ASSERT_FALSE(createIface(IfaceType::STA).empty());
+ ASSERT_TRUE(createIface(IfaceType::AP).empty());
+}
+
+////////// Hypothetical Iface Combination with multiple ifaces //////////
+class WifiChip_MultiIfaceTest : public WifiChipTest {
+ public:
+ void SetUp() override {
+ setup_MultiIfaceCombination();
+ WifiChipTest::SetUp();
+ }
+};
+
+TEST_F(WifiChip_MultiIfaceTest, Create3Sta) {
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+ ASSERT_FALSE(createIface(IfaceType::STA).empty());
+ ASSERT_FALSE(createIface(IfaceType::STA).empty());
+ ASSERT_FALSE(createIface(IfaceType::STA).empty());
+ ASSERT_TRUE(createIface(IfaceType::STA).empty());
+}
+
+TEST_F(WifiChip_MultiIfaceTest, CreateStaWithDefaultNames) {
+ property_set("wifi.interface.0", "");
+ property_set("wifi.interface.1", "");
+ property_set("wifi.interface.2", "");
+ property_set("wifi.interface", "");
+ property_set("wifi.concurrent.interface", "");
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+ ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+ ASSERT_EQ(createIface(IfaceType::STA), "wlan1");
+ ASSERT_EQ(createIface(IfaceType::STA), "wlan2");
+}
+
+TEST_F(WifiChip_MultiIfaceTest, CreateStaWithCustomNames) {
+ property_set("wifi.interface.0", "test0");
+ property_set("wifi.interface.1", "test1");
+ property_set("wifi.interface.2", "test2");
+ property_set("wifi.interface", "bad0");
+ property_set("wifi.concurrent.interface", "bad1");
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+ ASSERT_EQ(createIface(IfaceType::STA), "bad0");
+ ASSERT_EQ(createIface(IfaceType::STA), "bad1");
+ ASSERT_EQ(createIface(IfaceType::STA), "test2");
+}
+
+TEST_F(WifiChip_MultiIfaceTest, CreateStaWithCustomAltNames) {
+ property_set("wifi.interface.0", "");
+ property_set("wifi.interface.1", "");
+ property_set("wifi.interface.2", "");
+ property_set("wifi.interface", "testA0");
+ property_set("wifi.concurrent.interface", "testA1");
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+ ASSERT_EQ(createIface(IfaceType::STA), "testA0");
+ ASSERT_EQ(createIface(IfaceType::STA), "testA1");
+ ASSERT_EQ(createIface(IfaceType::STA), "wlan2");
+}
+
+TEST_F(WifiChip_MultiIfaceTest, CreateApStartsWithIdx1) {
+ // WifiChip_MultiIfaceTest iface combo: STAx3 + APx1
+ // When the HAL support dual STAs, AP should start with idx 2.
+ findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+ // First AP will be slotted to wlan1.
+ ASSERT_EQ(createIface(IfaceType::AP), "wlan2");
+ // First STA will be slotted to wlan0.
+ ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+ // All further STA will be slotted to the remaining free indices.
+ ASSERT_EQ(createIface(IfaceType::STA), "wlan1");
+ ASSERT_EQ(createIface(IfaceType::STA), "wlan3");
+}
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.6/default/tests/wifi_iface_util_unit_tests.cpp b/wifi/1.6/default/tests/wifi_iface_util_unit_tests.cpp
new file mode 100644
index 0000000..cc9a334
--- /dev/null
+++ b/wifi/1.6/default/tests/wifi_iface_util_unit_tests.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <gmock/gmock.h>
+
+#undef NAN
+#include "wifi_iface_util.h"
+
+#include "mock_interface_tool.h"
+#include "mock_wifi_legacy_hal.h"
+
+using testing::NiceMock;
+using testing::Test;
+
+namespace {
+constexpr uint8_t kValidUnicastLocallyAssignedMacAddressMask = 0x02;
+constexpr uint8_t kMacAddress[] = {0x02, 0x12, 0x45, 0x56, 0xab, 0xcc};
+constexpr char kIfaceName[] = "test-wlan0";
+
+bool isValidUnicastLocallyAssignedMacAddress(const std::array<uint8_t, 6>& mac_address) {
+ uint8_t first_byte = mac_address[0];
+ return (first_byte & 0x3) == kValidUnicastLocallyAssignedMacAddressMask;
+}
+} // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace iface_util {
+class WifiIfaceUtilTest : public Test {
+ protected:
+ std::shared_ptr<NiceMock<wifi_system::MockInterfaceTool>> iface_tool_{
+ new NiceMock<wifi_system::MockInterfaceTool>};
+ legacy_hal::wifi_hal_fn fake_func_table_;
+ std::shared_ptr<NiceMock<legacy_hal::MockWifiLegacyHal>> legacy_hal_{
+ new NiceMock<legacy_hal::MockWifiLegacyHal>(iface_tool_, fake_func_table_, true)};
+ WifiIfaceUtil* iface_util_ = new WifiIfaceUtil(iface_tool_, legacy_hal_);
+};
+
+TEST_F(WifiIfaceUtilTest, GetOrCreateRandomMacAddress) {
+ auto mac_address = iface_util_->getOrCreateRandomMacAddress();
+ ASSERT_TRUE(isValidUnicastLocallyAssignedMacAddress(mac_address));
+
+ // All further calls should return the same MAC address.
+ ASSERT_EQ(mac_address, iface_util_->getOrCreateRandomMacAddress());
+ ASSERT_EQ(mac_address, iface_util_->getOrCreateRandomMacAddress());
+}
+
+TEST_F(WifiIfaceUtilTest, IfaceEventHandlers_SetMacAddress) {
+ std::array<uint8_t, 6> mac_address = {};
+ std::copy(std::begin(kMacAddress), std::end(kMacAddress), std::begin(mac_address));
+ EXPECT_CALL(*iface_tool_, SetMacAddress(testing::_, testing::_))
+ .WillRepeatedly(testing::Return(true));
+ EXPECT_CALL(*iface_tool_, SetUpState(testing::_, testing::_))
+ .WillRepeatedly(testing::Return(true));
+
+ // Register for iface state toggle events.
+ bool callback_invoked = false;
+ iface_util::IfaceEventHandlers event_handlers = {};
+ event_handlers.on_state_toggle_off_on =
+ [&callback_invoked](const std::string& /* iface_name */) { callback_invoked = true; };
+ iface_util_->registerIfaceEventHandlers(kIfaceName, event_handlers);
+ // Invoke setMacAddress and ensure that the cb is invoked.
+ ASSERT_TRUE(iface_util_->setMacAddress(kIfaceName, mac_address));
+ ASSERT_TRUE(callback_invoked);
+
+ // Unregister for iface state toggle events.
+ callback_invoked = false;
+ iface_util_->unregisterIfaceEventHandlers(kIfaceName);
+ // Invoke setMacAddress and ensure that the cb is not invoked.
+ ASSERT_TRUE(iface_util_->setMacAddress(kIfaceName, mac_address));
+ ASSERT_FALSE(callback_invoked);
+}
+} // namespace iface_util
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.6/default/tests/wifi_nan_iface_unit_tests.cpp b/wifi/1.6/default/tests/wifi_nan_iface_unit_tests.cpp
new file mode 100644
index 0000000..8a5ddcd
--- /dev/null
+++ b/wifi/1.6/default/tests/wifi_nan_iface_unit_tests.cpp
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <cutils/properties.h>
+#include <gmock/gmock.h>
+
+#undef NAN // This is weird, NAN is defined in bionic/libc/include/math.h:38
+#include "wifi_nan_iface.h"
+
+#include "mock_interface_tool.h"
+#include "mock_wifi_feature_flags.h"
+#include "mock_wifi_iface_util.h"
+#include "mock_wifi_legacy_hal.h"
+
+using testing::NiceMock;
+using testing::Return;
+using testing::Test;
+
+namespace {
+constexpr char kIfaceName[] = "mockWlan0";
+} // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+
+using android::hardware::wifi::V1_2::NanDataPathConfirmInd;
+
+bool CaptureIfaceEventHandlers(const std::string& /* iface_name*/,
+ iface_util::IfaceEventHandlers in_iface_event_handlers,
+ iface_util::IfaceEventHandlers* out_iface_event_handlers) {
+ *out_iface_event_handlers = in_iface_event_handlers;
+ return true;
+}
+
+class MockNanIfaceEventCallback : public V1_5::IWifiNanIfaceEventCallback {
+ public:
+ MockNanIfaceEventCallback() = default;
+
+ MOCK_METHOD3(notifyCapabilitiesResponse,
+ Return<void>(uint16_t, const WifiNanStatus&,
+ const android::hardware::wifi::V1_0::NanCapabilities&));
+ MOCK_METHOD2(notifyEnableResponse, Return<void>(uint16_t, const WifiNanStatus&));
+ MOCK_METHOD2(notifyConfigResponse, Return<void>(uint16_t, const WifiNanStatus&));
+ MOCK_METHOD2(notifyDisableResponse, Return<void>(uint16_t, const WifiNanStatus&));
+ MOCK_METHOD3(notifyStartPublishResponse, Return<void>(uint16_t, const WifiNanStatus&, uint8_t));
+ MOCK_METHOD2(notifyStopPublishResponse, Return<void>(uint16_t, const WifiNanStatus&));
+ MOCK_METHOD3(notifyStartSubscribeResponse,
+ Return<void>(uint16_t, const WifiNanStatus&, uint8_t));
+ MOCK_METHOD2(notifyStopSubscribeResponse, Return<void>(uint16_t, const WifiNanStatus&));
+ MOCK_METHOD2(notifyTransmitFollowupResponse, Return<void>(uint16_t, const WifiNanStatus&));
+ MOCK_METHOD2(notifyCreateDataInterfaceResponse, Return<void>(uint16_t, const WifiNanStatus&));
+ MOCK_METHOD2(notifyDeleteDataInterfaceResponse, Return<void>(uint16_t, const WifiNanStatus&));
+ MOCK_METHOD3(notifyInitiateDataPathResponse,
+ Return<void>(uint16_t, const WifiNanStatus&, uint32_t));
+ MOCK_METHOD2(notifyRespondToDataPathIndicationResponse,
+ Return<void>(uint16_t, const WifiNanStatus&));
+ MOCK_METHOD2(notifyTerminateDataPathResponse, Return<void>(uint16_t, const WifiNanStatus&));
+ MOCK_METHOD1(eventClusterEvent, Return<void>(const NanClusterEventInd&));
+ MOCK_METHOD1(eventDisabled, Return<void>(const WifiNanStatus&));
+ MOCK_METHOD2(eventPublishTerminated, Return<void>(uint8_t, const WifiNanStatus&));
+ MOCK_METHOD2(eventSubscribeTerminated, Return<void>(uint8_t, const WifiNanStatus&));
+ MOCK_METHOD1(eventMatch, Return<void>(const V1_0::NanMatchInd&));
+ MOCK_METHOD1(eventMatch_1_6, Return<void>(const NanMatchInd&));
+ MOCK_METHOD2(eventMatchExpired, Return<void>(uint8_t, uint32_t));
+ MOCK_METHOD1(eventFollowupReceived, Return<void>(const NanFollowupReceivedInd&));
+ MOCK_METHOD2(eventTransmitFollowup, Return<void>(uint16_t, const WifiNanStatus&));
+ MOCK_METHOD1(eventDataPathRequest, Return<void>(const NanDataPathRequestInd&));
+ MOCK_METHOD1(eventDataPathConfirm,
+ Return<void>(const android::hardware::wifi::V1_0::NanDataPathConfirmInd&));
+ MOCK_METHOD1(eventDataPathTerminated, Return<void>(uint32_t));
+ MOCK_METHOD1(eventDataPathConfirm_1_2,
+ Return<void>(const android::hardware::wifi::V1_2::NanDataPathConfirmInd&));
+ MOCK_METHOD1(eventDataPathConfirm_1_6, Return<void>(const NanDataPathConfirmInd&));
+ MOCK_METHOD1(eventDataPathScheduleUpdate,
+ Return<void>(const android::hardware::wifi::V1_2::NanDataPathScheduleUpdateInd&));
+ MOCK_METHOD1(eventDataPathScheduleUpdate_1_6,
+ Return<void>(const NanDataPathScheduleUpdateInd&));
+ MOCK_METHOD3(notifyCapabilitiesResponse_1_5,
+ Return<void>(uint16_t, const WifiNanStatus&, const V1_5::NanCapabilities&));
+};
+
+class WifiNanIfaceTest : public Test {
+ protected:
+ legacy_hal::wifi_hal_fn fake_func_table_;
+ std::shared_ptr<NiceMock<wifi_system::MockInterfaceTool>> iface_tool_{
+ new NiceMock<wifi_system::MockInterfaceTool>};
+ std::shared_ptr<NiceMock<legacy_hal::MockWifiLegacyHal>> legacy_hal_{
+ new NiceMock<legacy_hal::MockWifiLegacyHal>(iface_tool_, fake_func_table_, true)};
+ std::shared_ptr<NiceMock<iface_util::MockWifiIfaceUtil>> iface_util_{
+ new NiceMock<iface_util::MockWifiIfaceUtil>(iface_tool_, legacy_hal_)};
+};
+
+TEST_F(WifiNanIfaceTest, IfacEventHandlers_OnStateToggleOffOn) {
+ iface_util::IfaceEventHandlers captured_iface_event_handlers = {};
+ EXPECT_CALL(*legacy_hal_, nanRegisterCallbackHandlers(testing::_, testing::_))
+ .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
+ EXPECT_CALL(*iface_util_, registerIfaceEventHandlers(testing::_, testing::_))
+ .WillOnce(testing::Invoke(bind(CaptureIfaceEventHandlers, std::placeholders::_1,
+ std::placeholders::_2, &captured_iface_event_handlers)));
+ sp<WifiNanIface> nan_iface = new WifiNanIface(kIfaceName, false, legacy_hal_, iface_util_);
+
+ // Register a mock nan event callback.
+ sp<NiceMock<MockNanIfaceEventCallback>> mock_event_callback{
+ new NiceMock<MockNanIfaceEventCallback>};
+ nan_iface->registerEventCallback(mock_event_callback, [](const WifiStatus& status) {
+ ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+ });
+ // Ensure that the eventDisabled() function in mock callback will be
+ // invoked.
+ WifiNanStatus expected_nan_status = {NanStatusType::UNSUPPORTED_CONCURRENCY_NAN_DISABLED, ""};
+ EXPECT_CALL(*mock_event_callback, eventDisabled(expected_nan_status)).Times(1);
+
+ // Trigger the iface state toggle callback.
+ captured_iface_event_handlers.on_state_toggle_off_on(kIfaceName);
+}
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.6/default/wifi.cpp b/wifi/1.6/default/wifi.cpp
new file mode 100644
index 0000000..c302ce2
--- /dev/null
+++ b/wifi/1.6/default/wifi.cpp
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+
+#include "hidl_return_util.h"
+#include "wifi.h"
+#include "wifi_status_util.h"
+
+namespace {
+// Starting Chip ID, will be assigned to primary chip
+static constexpr android::hardware::wifi::V1_0::ChipId kPrimaryChipId = 0;
+} // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+using hidl_return_util::validateAndCall;
+using hidl_return_util::validateAndCallWithLock;
+
+Wifi::Wifi(const std::shared_ptr<wifi_system::InterfaceTool> iface_tool,
+ const std::shared_ptr<legacy_hal::WifiLegacyHalFactory> legacy_hal_factory,
+ const std::shared_ptr<mode_controller::WifiModeController> mode_controller,
+ const std::shared_ptr<feature_flags::WifiFeatureFlags> feature_flags)
+ : iface_tool_(iface_tool),
+ legacy_hal_factory_(legacy_hal_factory),
+ mode_controller_(mode_controller),
+ feature_flags_(feature_flags),
+ run_state_(RunState::STOPPED) {}
+
+bool Wifi::isValid() {
+ // This object is always valid.
+ return true;
+}
+
+Return<void> Wifi::registerEventCallback(const sp<V1_0::IWifiEventCallback>& event_callback,
+ registerEventCallback_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN,
+ &Wifi::registerEventCallbackInternal, hidl_status_cb, event_callback);
+}
+
+Return<void> Wifi::registerEventCallback_1_5(const sp<V1_5::IWifiEventCallback>& event_callback,
+ registerEventCallback_1_5_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN,
+ &Wifi::registerEventCallbackInternal_1_5, hidl_status_cb,
+ event_callback);
+}
+
+Return<bool> Wifi::isStarted() {
+ return run_state_ != RunState::STOPPED;
+}
+
+Return<void> Wifi::start(start_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN, &Wifi::startInternal,
+ hidl_status_cb);
+}
+
+Return<void> Wifi::stop(stop_cb hidl_status_cb) {
+ return validateAndCallWithLock(this, WifiStatusCode::ERROR_UNKNOWN, &Wifi::stopInternal,
+ hidl_status_cb);
+}
+
+Return<void> Wifi::getChipIds(getChipIds_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN, &Wifi::getChipIdsInternal,
+ hidl_status_cb);
+}
+
+Return<void> Wifi::getChip(ChipId chip_id, getChip_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN, &Wifi::getChipInternal,
+ hidl_status_cb, chip_id);
+}
+
+Return<void> Wifi::debug(const hidl_handle& handle, const hidl_vec<hidl_string>&) {
+ LOG(INFO) << "-----------Debug is called----------------";
+ if (chips_.size() == 0) {
+ return Void();
+ }
+
+ for (sp<WifiChip> chip : chips_) {
+ if (!chip.get()) continue;
+
+ chip->debug(handle, {});
+ }
+ return Void();
+}
+
+WifiStatus Wifi::registerEventCallbackInternal(
+ const sp<V1_0::IWifiEventCallback>& event_callback __unused) {
+ // Deprecated support for this callback.
+ return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus Wifi::registerEventCallbackInternal_1_5(
+ const sp<V1_5::IWifiEventCallback>& event_callback) {
+ if (!event_cb_handler_.addCallback(event_callback)) {
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+ }
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+WifiStatus Wifi::startInternal() {
+ if (run_state_ == RunState::STARTED) {
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+ } else if (run_state_ == RunState::STOPPING) {
+ return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE, "HAL is stopping");
+ }
+ WifiStatus wifi_status = initializeModeControllerAndLegacyHal();
+ if (wifi_status.code == WifiStatusCode::SUCCESS) {
+ // Register the callback for subsystem restart
+ const auto& on_subsystem_restart_callback = [this](const std::string& error) {
+ WifiStatus wifi_status = createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, error);
+ for (const auto& callback : event_cb_handler_.getCallbacks()) {
+ LOG(INFO) << "Attempting to invoke onSubsystemRestart "
+ "callback";
+ if (!callback->onSubsystemRestart(wifi_status).isOk()) {
+ LOG(ERROR) << "Failed to invoke onSubsystemRestart callback";
+ } else {
+ LOG(INFO) << "Succeeded to invoke onSubsystemRestart "
+ "callback";
+ }
+ }
+ };
+
+ // Create the chip instance once the HAL is started.
+ android::hardware::wifi::V1_0::ChipId chipId = kPrimaryChipId;
+ for (auto& hal : legacy_hals_) {
+ chips_.push_back(
+ new WifiChip(chipId, chipId == kPrimaryChipId, hal, mode_controller_,
+ std::make_shared<iface_util::WifiIfaceUtil>(iface_tool_, hal),
+ feature_flags_, on_subsystem_restart_callback));
+ chipId++;
+ }
+ run_state_ = RunState::STARTED;
+ for (const auto& callback : event_cb_handler_.getCallbacks()) {
+ if (!callback->onStart().isOk()) {
+ LOG(ERROR) << "Failed to invoke onStart callback";
+ };
+ }
+ LOG(INFO) << "Wifi HAL started";
+ } else {
+ for (const auto& callback : event_cb_handler_.getCallbacks()) {
+ if (!callback->onFailure(wifi_status).isOk()) {
+ LOG(ERROR) << "Failed to invoke onFailure callback";
+ }
+ }
+ LOG(ERROR) << "Wifi HAL start failed";
+ // Clear the event callback objects since the HAL start failed.
+ event_cb_handler_.invalidate();
+ }
+ return wifi_status;
+}
+
+WifiStatus Wifi::stopInternal(
+ /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock) {
+ if (run_state_ == RunState::STOPPED) {
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+ } else if (run_state_ == RunState::STOPPING) {
+ return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE, "HAL is stopping");
+ }
+ // Clear the chip object and its child objects since the HAL is now
+ // stopped.
+ for (auto& chip : chips_) {
+ if (chip.get()) {
+ chip->invalidate();
+ chip.clear();
+ }
+ }
+ chips_.clear();
+ WifiStatus wifi_status = stopLegacyHalAndDeinitializeModeController(lock);
+ if (wifi_status.code == WifiStatusCode::SUCCESS) {
+ for (const auto& callback : event_cb_handler_.getCallbacks()) {
+ if (!callback->onStop().isOk()) {
+ LOG(ERROR) << "Failed to invoke onStop callback";
+ };
+ }
+ LOG(INFO) << "Wifi HAL stopped";
+ } else {
+ for (const auto& callback : event_cb_handler_.getCallbacks()) {
+ if (!callback->onFailure(wifi_status).isOk()) {
+ LOG(ERROR) << "Failed to invoke onFailure callback";
+ }
+ }
+ LOG(ERROR) << "Wifi HAL stop failed";
+ }
+ // Clear the event callback objects since the HAL is now stopped.
+ event_cb_handler_.invalidate();
+ return wifi_status;
+}
+
+std::pair<WifiStatus, std::vector<ChipId>> Wifi::getChipIdsInternal() {
+ std::vector<ChipId> chip_ids;
+
+ for (auto& chip : chips_) {
+ ChipId chip_id = getChipIdFromWifiChip(chip);
+ if (chip_id != UINT32_MAX) chip_ids.emplace_back(chip_id);
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), std::move(chip_ids)};
+}
+
+std::pair<WifiStatus, sp<V1_4::IWifiChip>> Wifi::getChipInternal(ChipId chip_id) {
+ for (auto& chip : chips_) {
+ ChipId cand_id = getChipIdFromWifiChip(chip);
+ if ((cand_id != UINT32_MAX) && (cand_id == chip_id))
+ return {createWifiStatus(WifiStatusCode::SUCCESS), chip};
+ }
+
+ return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
+}
+
+WifiStatus Wifi::initializeModeControllerAndLegacyHal() {
+ if (!mode_controller_->initialize()) {
+ LOG(ERROR) << "Failed to initialize firmware mode controller";
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+ }
+
+ legacy_hals_ = legacy_hal_factory_->getHals();
+ if (legacy_hals_.empty()) return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+ int index = 0; // for failure log
+ for (auto& hal : legacy_hals_) {
+ legacy_hal::wifi_error legacy_status = hal->initialize();
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ // Currently WifiLegacyHal::initialize does not allocate extra mem,
+ // only initializes the function table. If this changes, need to
+ // implement WifiLegacyHal::deinitialize and deinitalize the
+ // HALs already initialized
+ LOG(ERROR) << "Failed to initialize legacy HAL index: " << index
+ << " error: " << legacyErrorToString(legacy_status);
+ return createWifiStatusFromLegacyError(legacy_status);
+ }
+ index++;
+ }
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+WifiStatus Wifi::stopLegacyHalAndDeinitializeModeController(
+ /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock) {
+ legacy_hal::wifi_error legacy_status = legacy_hal::WIFI_SUCCESS;
+ int index = 0;
+
+ run_state_ = RunState::STOPPING;
+ for (auto& hal : legacy_hals_) {
+ legacy_hal::wifi_error tmp = hal->stop(lock, [&]() {});
+ if (tmp != legacy_hal::WIFI_SUCCESS) {
+ LOG(ERROR) << "Failed to stop legacy HAL index: " << index
+ << " error: " << legacyErrorToString(legacy_status);
+ legacy_status = tmp;
+ }
+ index++;
+ }
+ run_state_ = RunState::STOPPED;
+
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ LOG(ERROR) << "One or more legacy HALs failed to stop";
+ return createWifiStatusFromLegacyError(legacy_status);
+ }
+ if (!mode_controller_->deinitialize()) {
+ LOG(ERROR) << "Failed to deinitialize firmware mode controller";
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+ }
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+ChipId Wifi::getChipIdFromWifiChip(sp<WifiChip>& chip) {
+ ChipId chip_id = UINT32_MAX;
+ if (chip.get()) {
+ chip->getId([&](WifiStatus status, uint32_t id) {
+ if (status.code == WifiStatusCode::SUCCESS) {
+ chip_id = id;
+ }
+ });
+ }
+
+ return chip_id;
+}
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.6/default/wifi.h b/wifi/1.6/default/wifi.h
new file mode 100644
index 0000000..435358e
--- /dev/null
+++ b/wifi/1.6/default/wifi.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_H_
+#define WIFI_H_
+
+// HACK: NAN is a macro defined in math.h, which can be included in various
+// headers. This wifi HAL uses an enum called NAN, which does not compile when
+// the macro is defined. Undefine NAN to work around it.
+#undef NAN
+#include <android/hardware/wifi/1.6/IWifi.h>
+
+#include <android-base/macros.h>
+#include <utils/Looper.h>
+#include <functional>
+
+#include "hidl_callback_util.h"
+#include "wifi_chip.h"
+#include "wifi_feature_flags.h"
+#include "wifi_legacy_hal.h"
+#include "wifi_legacy_hal_factory.h"
+#include "wifi_mode_controller.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+
+/**
+ * Root HIDL interface object used to control the Wifi HAL.
+ */
+class Wifi : public V1_6::IWifi {
+ public:
+ Wifi(const std::shared_ptr<wifi_system::InterfaceTool> iface_tool,
+ const std::shared_ptr<legacy_hal::WifiLegacyHalFactory> legacy_hal_factory,
+ const std::shared_ptr<mode_controller::WifiModeController> mode_controller,
+ const std::shared_ptr<feature_flags::WifiFeatureFlags> feature_flags);
+
+ bool isValid();
+
+ // HIDL methods exposed.
+ Return<void> registerEventCallback(const sp<V1_0::IWifiEventCallback>& event_callback,
+ registerEventCallback_cb hidl_status_cb) override;
+ Return<void> registerEventCallback_1_5(const sp<V1_5::IWifiEventCallback>& event_callback,
+ registerEventCallback_1_5_cb hidl_status_cb) override;
+ Return<bool> isStarted() override;
+ Return<void> start(start_cb hidl_status_cb) override;
+ Return<void> stop(stop_cb hidl_status_cb) override;
+ Return<void> getChipIds(getChipIds_cb hidl_status_cb) override;
+ Return<void> getChip(ChipId chip_id, getChip_cb hidl_status_cb) override;
+ Return<void> debug(const hidl_handle& handle, const hidl_vec<hidl_string>& options) override;
+
+ private:
+ enum class RunState { STOPPED, STARTED, STOPPING };
+
+ // Corresponding worker functions for the HIDL methods.
+ WifiStatus registerEventCallbackInternal(
+ const sp<V1_0::IWifiEventCallback>& event_callback __unused);
+ WifiStatus registerEventCallbackInternal_1_5(
+ const sp<V1_5::IWifiEventCallback>& event_callback);
+ WifiStatus startInternal();
+ WifiStatus stopInternal(std::unique_lock<std::recursive_mutex>* lock);
+ std::pair<WifiStatus, std::vector<ChipId>> getChipIdsInternal();
+ std::pair<WifiStatus, sp<V1_4::IWifiChip>> getChipInternal(ChipId chip_id);
+
+ WifiStatus initializeModeControllerAndLegacyHal();
+ WifiStatus stopLegacyHalAndDeinitializeModeController(
+ std::unique_lock<std::recursive_mutex>* lock);
+ ChipId getChipIdFromWifiChip(sp<WifiChip>& chip);
+
+ // Instance is created in this root level |IWifi| HIDL interface object
+ // and shared with all the child HIDL interface objects.
+ std::shared_ptr<wifi_system::InterfaceTool> iface_tool_;
+ std::shared_ptr<legacy_hal::WifiLegacyHalFactory> legacy_hal_factory_;
+ std::shared_ptr<mode_controller::WifiModeController> mode_controller_;
+ std::vector<std::shared_ptr<legacy_hal::WifiLegacyHal>> legacy_hals_;
+ std::shared_ptr<feature_flags::WifiFeatureFlags> feature_flags_;
+ RunState run_state_;
+ std::vector<sp<WifiChip>> chips_;
+ hidl_callback_util::HidlCallbackHandler<V1_5::IWifiEventCallback> event_cb_handler_;
+
+ DISALLOW_COPY_AND_ASSIGN(Wifi);
+};
+
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+
+#endif // WIFI_H_
diff --git a/wifi/1.6/default/wifi_ap_iface.cpp b/wifi/1.6/default/wifi_ap_iface.cpp
new file mode 100644
index 0000000..b2957db
--- /dev/null
+++ b/wifi/1.6/default/wifi_ap_iface.cpp
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+
+#include "hidl_return_util.h"
+#include "hidl_struct_util.h"
+#include "wifi_ap_iface.h"
+#include "wifi_status_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+using hidl_return_util::validateAndCall;
+
+WifiApIface::WifiApIface(const std::string& ifname, const std::vector<std::string>& instances,
+ const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+ const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util)
+ : ifname_(ifname),
+ instances_(instances),
+ legacy_hal_(legacy_hal),
+ iface_util_(iface_util),
+ is_valid_(true) {}
+
+void WifiApIface::invalidate() {
+ legacy_hal_.reset();
+ is_valid_ = false;
+}
+
+bool WifiApIface::isValid() {
+ return is_valid_;
+}
+
+std::string WifiApIface::getName() {
+ return ifname_;
+}
+
+void WifiApIface::removeInstance(std::string instance) {
+ instances_.erase(std::remove(instances_.begin(), instances_.end(), instance), instances_.end());
+}
+
+Return<void> WifiApIface::getName(getName_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiApIface::getNameInternal, hidl_status_cb);
+}
+
+Return<void> WifiApIface::getType(getType_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiApIface::getTypeInternal, hidl_status_cb);
+}
+
+Return<void> WifiApIface::setCountryCode(const hidl_array<int8_t, 2>& code,
+ setCountryCode_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiApIface::setCountryCodeInternal, hidl_status_cb, code);
+}
+
+Return<void> WifiApIface::getValidFrequenciesForBand(V1_0::WifiBand band,
+ getValidFrequenciesForBand_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiApIface::getValidFrequenciesForBandInternal, hidl_status_cb, band);
+}
+
+Return<void> WifiApIface::setMacAddress(const hidl_array<uint8_t, 6>& mac,
+ setMacAddress_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiApIface::setMacAddressInternal, hidl_status_cb, mac);
+}
+
+Return<void> WifiApIface::getFactoryMacAddress(getFactoryMacAddress_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiApIface::getFactoryMacAddressInternal, hidl_status_cb,
+ instances_.size() > 0 ? instances_[0] : ifname_);
+}
+
+Return<void> WifiApIface::resetToFactoryMacAddress(resetToFactoryMacAddress_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiApIface::resetToFactoryMacAddressInternal, hidl_status_cb);
+}
+
+Return<void> WifiApIface::getBridgedInstances(getBridgedInstances_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiApIface::getBridgedInstancesInternal, hidl_status_cb);
+}
+
+std::pair<WifiStatus, std::string> WifiApIface::getNameInternal() {
+ return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_};
+}
+
+std::pair<WifiStatus, IfaceType> WifiApIface::getTypeInternal() {
+ return {createWifiStatus(WifiStatusCode::SUCCESS), IfaceType::AP};
+}
+
+WifiStatus WifiApIface::setCountryCodeInternal(const std::array<int8_t, 2>& code) {
+ legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->setCountryCode(
+ instances_.size() > 0 ? instances_[0] : ifname_, code);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, std::vector<WifiChannelInMhz>>
+WifiApIface::getValidFrequenciesForBandInternal(V1_0::WifiBand band) {
+ static_assert(sizeof(WifiChannelInMhz) == sizeof(uint32_t), "Size mismatch");
+ legacy_hal::wifi_error legacy_status;
+ std::vector<uint32_t> valid_frequencies;
+ std::tie(legacy_status, valid_frequencies) = legacy_hal_.lock()->getValidFrequenciesForBand(
+ instances_.size() > 0 ? instances_[0] : ifname_,
+ hidl_struct_util::convertHidlWifiBandToLegacy(band));
+ return {createWifiStatusFromLegacyError(legacy_status), valid_frequencies};
+}
+
+WifiStatus WifiApIface::setMacAddressInternal(const std::array<uint8_t, 6>& mac) {
+ // Support random MAC up to 2 interfaces
+ if (instances_.size() == 2) {
+ int rbyte = 1;
+ for (auto const& intf : instances_) {
+ std::array<uint8_t, 6> rmac = mac;
+ // reverse the bits to avoid collision
+ rmac[rbyte] = 0xff - rmac[rbyte];
+ if (!iface_util_.lock()->setMacAddress(intf, rmac)) {
+ LOG(INFO) << "Failed to set random mac address on " << intf;
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+ }
+ rbyte++;
+ }
+ }
+ // It also needs to set mac address for bridged interface, otherwise the mac
+ // address of bridged interface will be changed after one of instance
+ // down.
+ if (!iface_util_.lock()->setMacAddress(ifname_, mac)) {
+ LOG(ERROR) << "Fail to config MAC for interface " << ifname_;
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+ }
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+std::pair<WifiStatus, std::array<uint8_t, 6>> WifiApIface::getFactoryMacAddressInternal(
+ const std::string& ifaceName) {
+ std::array<uint8_t, 6> mac = iface_util_.lock()->getFactoryMacAddress(ifaceName);
+ if (mac[0] == 0 && mac[1] == 0 && mac[2] == 0 && mac[3] == 0 && mac[4] == 0 && mac[5] == 0) {
+ return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), mac};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), mac};
+}
+
+WifiStatus WifiApIface::resetToFactoryMacAddressInternal() {
+ std::pair<WifiStatus, std::array<uint8_t, 6>> getMacResult;
+ if (instances_.size() == 2) {
+ for (auto const& intf : instances_) {
+ getMacResult = getFactoryMacAddressInternal(intf);
+ LOG(DEBUG) << "Reset MAC to factory MAC on " << intf;
+ if (getMacResult.first.code != WifiStatusCode::SUCCESS ||
+ !iface_util_.lock()->setMacAddress(intf, getMacResult.second)) {
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+ }
+ }
+ // It needs to set mac address for bridged interface, otherwise the mac
+ // address of the bridged interface will be changed after one of the
+ // instance down. Thus we are generating a random MAC address for the
+ // bridged interface even if we got the request to reset the Factory
+ // MAC. Since the bridged interface is an internal interface for the
+ // operation of bpf and others networking operation.
+ if (!iface_util_.lock()->setMacAddress(ifname_,
+ iface_util_.lock()->createRandomMacAddress())) {
+ LOG(ERROR) << "Fail to config MAC for bridged interface " << ifname_;
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+ }
+ } else {
+ getMacResult = getFactoryMacAddressInternal(ifname_);
+ LOG(DEBUG) << "Reset MAC to factory MAC on " << ifname_;
+ if (getMacResult.first.code != WifiStatusCode::SUCCESS ||
+ !iface_util_.lock()->setMacAddress(ifname_, getMacResult.second)) {
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+ }
+ }
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+std::pair<WifiStatus, std::vector<hidl_string>> WifiApIface::getBridgedInstancesInternal() {
+ std::vector<hidl_string> instances;
+ for (const auto& instance_name : instances_) {
+ instances.push_back(instance_name);
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), instances};
+}
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.6/default/wifi_ap_iface.h b/wifi/1.6/default/wifi_ap_iface.h
new file mode 100644
index 0000000..d1c0642
--- /dev/null
+++ b/wifi/1.6/default/wifi_ap_iface.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_AP_IFACE_H_
+#define WIFI_AP_IFACE_H_
+
+#include <android-base/macros.h>
+#include <android/hardware/wifi/1.5/IWifiApIface.h>
+
+#include "wifi_iface_util.h"
+#include "wifi_legacy_hal.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+using namespace android::hardware::wifi::V1_0;
+
+/**
+ * HIDL interface object used to control a AP Iface instance.
+ */
+class WifiApIface : public V1_5::IWifiApIface {
+ public:
+ WifiApIface(const std::string& ifname, const std::vector<std::string>& instances,
+ const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+ const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util);
+ // Refer to |WifiChip::invalidate()|.
+ void invalidate();
+ bool isValid();
+ std::string getName();
+ void removeInstance(std::string instance);
+
+ // HIDL methods exposed.
+ Return<void> getName(getName_cb hidl_status_cb) override;
+ Return<void> getType(getType_cb hidl_status_cb) override;
+ Return<void> setCountryCode(const hidl_array<int8_t, 2>& code,
+ setCountryCode_cb hidl_status_cb) override;
+ Return<void> getValidFrequenciesForBand(V1_0::WifiBand band,
+ getValidFrequenciesForBand_cb hidl_status_cb) override;
+ Return<void> setMacAddress(const hidl_array<uint8_t, 6>& mac,
+ setMacAddress_cb hidl_status_cb) override;
+ Return<void> getFactoryMacAddress(getFactoryMacAddress_cb hidl_status_cb) override;
+ Return<void> resetToFactoryMacAddress(resetToFactoryMacAddress_cb hidl_status_cb) override;
+
+ Return<void> getBridgedInstances(getBridgedInstances_cb hidl_status_cb) override;
+
+ private:
+ // Corresponding worker functions for the HIDL methods.
+ std::pair<WifiStatus, std::string> getNameInternal();
+ std::pair<WifiStatus, IfaceType> getTypeInternal();
+ WifiStatus setCountryCodeInternal(const std::array<int8_t, 2>& code);
+ std::pair<WifiStatus, std::vector<WifiChannelInMhz>> getValidFrequenciesForBandInternal(
+ V1_0::WifiBand band);
+ WifiStatus setMacAddressInternal(const std::array<uint8_t, 6>& mac);
+ std::pair<WifiStatus, std::array<uint8_t, 6>> getFactoryMacAddressInternal(
+ const std::string& ifaceName);
+ WifiStatus resetToFactoryMacAddressInternal();
+ std::pair<WifiStatus, std::vector<hidl_string>> getBridgedInstancesInternal();
+
+ std::string ifname_;
+ std::vector<std::string> instances_;
+ std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+ std::weak_ptr<iface_util::WifiIfaceUtil> iface_util_;
+ bool is_valid_;
+
+ DISALLOW_COPY_AND_ASSIGN(WifiApIface);
+};
+
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+
+#endif // WIFI_AP_IFACE_H_
diff --git a/wifi/1.6/default/wifi_chip.cpp b/wifi/1.6/default/wifi_chip.cpp
new file mode 100644
index 0000000..920beb8
--- /dev/null
+++ b/wifi/1.6/default/wifi_chip.cpp
@@ -0,0 +1,2062 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fcntl.h>
+
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <cutils/properties.h>
+#include <net/if.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+
+#include "hidl_return_util.h"
+#include "hidl_struct_util.h"
+#include "wifi_chip.h"
+#include "wifi_status_util.h"
+
+#define P2P_MGMT_DEVICE_PREFIX "p2p-dev-"
+
+namespace {
+using android::sp;
+using android::base::unique_fd;
+using android::hardware::hidl_string;
+using android::hardware::hidl_vec;
+using android::hardware::wifi::V1_0::ChipModeId;
+using android::hardware::wifi::V1_0::IfaceType;
+using android::hardware::wifi::V1_0::IWifiChip;
+
+constexpr char kCpioMagic[] = "070701";
+constexpr size_t kMaxBufferSizeBytes = 1024 * 1024 * 3;
+constexpr uint32_t kMaxRingBufferFileAgeSeconds = 60 * 60 * 10;
+constexpr uint32_t kMaxRingBufferFileNum = 20;
+constexpr char kTombstoneFolderPath[] = "/data/vendor/tombstones/wifi/";
+constexpr char kActiveWlanIfaceNameProperty[] = "wifi.active.interface";
+constexpr char kNoActiveWlanIfaceNamePropertyValue[] = "";
+constexpr unsigned kMaxWlanIfaces = 5;
+constexpr char kApBridgeIfacePrefix[] = "ap_br_";
+
+template <typename Iface>
+void invalidateAndClear(std::vector<sp<Iface>>& ifaces, sp<Iface> iface) {
+ iface->invalidate();
+ ifaces.erase(std::remove(ifaces.begin(), ifaces.end(), iface), ifaces.end());
+}
+
+template <typename Iface>
+void invalidateAndClearAll(std::vector<sp<Iface>>& ifaces) {
+ for (const auto& iface : ifaces) {
+ iface->invalidate();
+ }
+ ifaces.clear();
+}
+
+template <typename Iface>
+std::vector<hidl_string> getNames(std::vector<sp<Iface>>& ifaces) {
+ std::vector<hidl_string> names;
+ for (const auto& iface : ifaces) {
+ names.emplace_back(iface->getName());
+ }
+ return names;
+}
+
+template <typename Iface>
+sp<Iface> findUsingName(std::vector<sp<Iface>>& ifaces, const std::string& name) {
+ std::vector<hidl_string> names;
+ for (const auto& iface : ifaces) {
+ if (name == iface->getName()) {
+ return iface;
+ }
+ }
+ return nullptr;
+}
+
+std::string getWlanIfaceName(unsigned idx) {
+ if (idx >= kMaxWlanIfaces) {
+ CHECK(false) << "Requested interface beyond wlan" << kMaxWlanIfaces;
+ return {};
+ }
+
+ std::array<char, PROPERTY_VALUE_MAX> buffer;
+ if (idx == 0 || idx == 1) {
+ const char* altPropName = (idx == 0) ? "wifi.interface" : "wifi.concurrent.interface";
+ auto res = property_get(altPropName, buffer.data(), nullptr);
+ if (res > 0) return buffer.data();
+ }
+ std::string propName = "wifi.interface." + std::to_string(idx);
+ auto res = property_get(propName.c_str(), buffer.data(), nullptr);
+ if (res > 0) return buffer.data();
+
+ return "wlan" + std::to_string(idx);
+}
+
+// Returns the dedicated iface name if defined.
+// Returns two ifaces in bridged mode.
+std::vector<std::string> getPredefinedApIfaceNames(bool is_bridged) {
+ std::vector<std::string> ifnames;
+ std::array<char, PROPERTY_VALUE_MAX> buffer;
+ buffer.fill(0);
+ if (property_get("ro.vendor.wifi.sap.interface", buffer.data(), nullptr) == 0) {
+ return ifnames;
+ }
+ ifnames.push_back(buffer.data());
+ if (is_bridged) {
+ buffer.fill(0);
+ if (property_get("ro.vendor.wifi.sap.concurrent.iface", buffer.data(), nullptr) == 0) {
+ return ifnames;
+ }
+ ifnames.push_back(buffer.data());
+ }
+ return ifnames;
+}
+
+std::string getPredefinedP2pIfaceName() {
+ std::array<char, PROPERTY_VALUE_MAX> primaryIfaceName;
+ char p2pParentIfname[100];
+ std::string p2pDevIfName = "";
+ std::array<char, PROPERTY_VALUE_MAX> buffer;
+ property_get("wifi.direct.interface", buffer.data(), "p2p0");
+ if (strncmp(buffer.data(), P2P_MGMT_DEVICE_PREFIX, strlen(P2P_MGMT_DEVICE_PREFIX)) == 0) {
+ /* Get the p2p parent interface name from p2p device interface name set
+ * in property */
+ strlcpy(p2pParentIfname, buffer.data() + strlen(P2P_MGMT_DEVICE_PREFIX),
+ strlen(buffer.data()) - strlen(P2P_MGMT_DEVICE_PREFIX));
+ if (property_get(kActiveWlanIfaceNameProperty, primaryIfaceName.data(), nullptr) == 0) {
+ return buffer.data();
+ }
+ /* Check if the parent interface derived from p2p device interface name
+ * is active */
+ if (strncmp(p2pParentIfname, primaryIfaceName.data(),
+ strlen(buffer.data()) - strlen(P2P_MGMT_DEVICE_PREFIX)) != 0) {
+ /*
+ * Update the predefined p2p device interface parent interface name
+ * with current active wlan interface
+ */
+ p2pDevIfName += P2P_MGMT_DEVICE_PREFIX;
+ p2pDevIfName += primaryIfaceName.data();
+ LOG(INFO) << "update the p2p device interface name to " << p2pDevIfName.c_str();
+ return p2pDevIfName;
+ }
+ }
+ return buffer.data();
+}
+
+// Returns the dedicated iface name if one is defined.
+std::string getPredefinedNanIfaceName() {
+ std::array<char, PROPERTY_VALUE_MAX> buffer;
+ if (property_get("wifi.aware.interface", buffer.data(), nullptr) == 0) {
+ return {};
+ }
+ return buffer.data();
+}
+
+void setActiveWlanIfaceNameProperty(const std::string& ifname) {
+ auto res = property_set(kActiveWlanIfaceNameProperty, ifname.data());
+ if (res != 0) {
+ PLOG(ERROR) << "Failed to set active wlan iface name property";
+ }
+}
+
+// delete files that meet either conditions:
+// 1. older than a predefined time in the wifi tombstone dir.
+// 2. Files in excess to a predefined amount, starting from the oldest ones
+bool removeOldFilesInternal() {
+ time_t now = time(0);
+ const time_t delete_files_before = now - kMaxRingBufferFileAgeSeconds;
+ std::unique_ptr<DIR, decltype(&closedir)> dir_dump(opendir(kTombstoneFolderPath), closedir);
+ if (!dir_dump) {
+ PLOG(ERROR) << "Failed to open directory";
+ return false;
+ }
+ struct dirent* dp;
+ bool success = true;
+ std::list<std::pair<const time_t, std::string>> valid_files;
+ while ((dp = readdir(dir_dump.get()))) {
+ if (dp->d_type != DT_REG) {
+ continue;
+ }
+ std::string cur_file_name(dp->d_name);
+ struct stat cur_file_stat;
+ std::string cur_file_path = kTombstoneFolderPath + cur_file_name;
+ if (stat(cur_file_path.c_str(), &cur_file_stat) == -1) {
+ PLOG(ERROR) << "Failed to get file stat for " << cur_file_path;
+ success = false;
+ continue;
+ }
+ const time_t cur_file_time = cur_file_stat.st_mtime;
+ valid_files.push_back(std::pair<const time_t, std::string>(cur_file_time, cur_file_path));
+ }
+ valid_files.sort(); // sort the list of files by last modified time from
+ // small to big.
+ uint32_t cur_file_count = valid_files.size();
+ for (auto cur_file : valid_files) {
+ if (cur_file_count > kMaxRingBufferFileNum || cur_file.first < delete_files_before) {
+ if (unlink(cur_file.second.c_str()) != 0) {
+ PLOG(ERROR) << "Error deleting file";
+ success = false;
+ }
+ cur_file_count--;
+ } else {
+ break;
+ }
+ }
+ return success;
+}
+
+// Helper function for |cpioArchiveFilesInDir|
+bool cpioWriteHeader(int out_fd, struct stat& st, const char* file_name, size_t file_name_len) {
+ const int buf_size = 32 * 1024;
+ std::array<char, buf_size> read_buf;
+ ssize_t llen = snprintf(
+ read_buf.data(), buf_size, "%s%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X",
+ kCpioMagic, static_cast<int>(st.st_ino), st.st_mode, st.st_uid, st.st_gid,
+ static_cast<int>(st.st_nlink), static_cast<int>(st.st_mtime),
+ static_cast<int>(st.st_size), major(st.st_dev), minor(st.st_dev), major(st.st_rdev),
+ minor(st.st_rdev), static_cast<uint32_t>(file_name_len), 0);
+ if (write(out_fd, read_buf.data(), llen < buf_size ? llen : buf_size - 1) == -1) {
+ PLOG(ERROR) << "Error writing cpio header to file " << file_name;
+ return false;
+ }
+ if (write(out_fd, file_name, file_name_len) == -1) {
+ PLOG(ERROR) << "Error writing filename to file " << file_name;
+ return false;
+ }
+
+ // NUL Pad header up to 4 multiple bytes.
+ llen = (llen + file_name_len) % 4;
+ if (llen != 0) {
+ const uint32_t zero = 0;
+ if (write(out_fd, &zero, 4 - llen) == -1) {
+ PLOG(ERROR) << "Error padding 0s to file " << file_name;
+ return false;
+ }
+ }
+ return true;
+}
+
+// Helper function for |cpioArchiveFilesInDir|
+size_t cpioWriteFileContent(int fd_read, int out_fd, struct stat& st) {
+ // writing content of file
+ std::array<char, 32 * 1024> read_buf;
+ ssize_t llen = st.st_size;
+ size_t n_error = 0;
+ while (llen > 0) {
+ ssize_t bytes_read = read(fd_read, read_buf.data(), read_buf.size());
+ if (bytes_read == -1) {
+ PLOG(ERROR) << "Error reading file";
+ return ++n_error;
+ }
+ llen -= bytes_read;
+ if (write(out_fd, read_buf.data(), bytes_read) == -1) {
+ PLOG(ERROR) << "Error writing data to file";
+ return ++n_error;
+ }
+ if (bytes_read == 0) { // this should never happen, but just in case
+ // to unstuck from while loop
+ PLOG(ERROR) << "Unexpected read result";
+ n_error++;
+ break;
+ }
+ }
+ llen = st.st_size % 4;
+ if (llen != 0) {
+ const uint32_t zero = 0;
+ if (write(out_fd, &zero, 4 - llen) == -1) {
+ PLOG(ERROR) << "Error padding 0s to file";
+ return ++n_error;
+ }
+ }
+ return n_error;
+}
+
+// Helper function for |cpioArchiveFilesInDir|
+bool cpioWriteFileTrailer(int out_fd) {
+ const int buf_size = 4096;
+ std::array<char, buf_size> read_buf;
+ read_buf.fill(0);
+ ssize_t llen = snprintf(read_buf.data(), 4096, "070701%040X%056X%08XTRAILER!!!", 1, 0x0b, 0);
+ if (write(out_fd, read_buf.data(), (llen < buf_size ? llen : buf_size - 1) + 4) == -1) {
+ PLOG(ERROR) << "Error writing trailing bytes";
+ return false;
+ }
+ return true;
+}
+
+// Archives all files in |input_dir| and writes result into |out_fd|
+// Logic obtained from //external/toybox/toys/posix/cpio.c "Output cpio archive"
+// portion
+size_t cpioArchiveFilesInDir(int out_fd, const char* input_dir) {
+ struct dirent* dp;
+ size_t n_error = 0;
+ std::unique_ptr<DIR, decltype(&closedir)> dir_dump(opendir(input_dir), closedir);
+ if (!dir_dump) {
+ PLOG(ERROR) << "Failed to open directory";
+ return ++n_error;
+ }
+ while ((dp = readdir(dir_dump.get()))) {
+ if (dp->d_type != DT_REG) {
+ continue;
+ }
+ std::string cur_file_name(dp->d_name);
+ struct stat st;
+ const std::string cur_file_path = kTombstoneFolderPath + cur_file_name;
+ if (stat(cur_file_path.c_str(), &st) == -1) {
+ PLOG(ERROR) << "Failed to get file stat for " << cur_file_path;
+ n_error++;
+ continue;
+ }
+ const int fd_read = open(cur_file_path.c_str(), O_RDONLY);
+ if (fd_read == -1) {
+ PLOG(ERROR) << "Failed to open file " << cur_file_path;
+ n_error++;
+ continue;
+ }
+ std::string file_name_with_last_modified_time =
+ cur_file_name + "-" + std::to_string(st.st_mtime);
+ // string.size() does not include the null terminator. The cpio FreeBSD
+ // file header expects the null character to be included in the length.
+ const size_t file_name_len = file_name_with_last_modified_time.size() + 1;
+ unique_fd file_auto_closer(fd_read);
+ if (!cpioWriteHeader(out_fd, st, file_name_with_last_modified_time.c_str(),
+ file_name_len)) {
+ return ++n_error;
+ }
+ size_t write_error = cpioWriteFileContent(fd_read, out_fd, st);
+ if (write_error) {
+ return n_error + write_error;
+ }
+ }
+ if (!cpioWriteFileTrailer(out_fd)) {
+ return ++n_error;
+ }
+ return n_error;
+}
+
+// Helper function to create a non-const char*.
+std::vector<char> makeCharVec(const std::string& str) {
+ std::vector<char> vec(str.size() + 1);
+ vec.assign(str.begin(), str.end());
+ vec.push_back('\0');
+ return vec;
+}
+
+} // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+using hidl_return_util::validateAndCall;
+using hidl_return_util::validateAndCallWithLock;
+
+WifiChip::WifiChip(ChipId chip_id, bool is_primary,
+ const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+ const std::weak_ptr<mode_controller::WifiModeController> mode_controller,
+ const std::shared_ptr<iface_util::WifiIfaceUtil> iface_util,
+ const std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags,
+ const std::function<void(const std::string&)>& handler)
+ : chip_id_(chip_id),
+ legacy_hal_(legacy_hal),
+ mode_controller_(mode_controller),
+ iface_util_(iface_util),
+ is_valid_(true),
+ current_mode_id_(feature_flags::chip_mode_ids::kInvalid),
+ modes_(feature_flags.lock()->getChipModes(is_primary)),
+ debug_ring_buffer_cb_registered_(false),
+ subsystemCallbackHandler_(handler) {
+ setActiveWlanIfaceNameProperty(kNoActiveWlanIfaceNamePropertyValue);
+}
+
+void WifiChip::invalidate() {
+ if (!writeRingbufferFilesInternal()) {
+ LOG(ERROR) << "Error writing files to flash";
+ }
+ invalidateAndRemoveAllIfaces();
+ setActiveWlanIfaceNameProperty(kNoActiveWlanIfaceNamePropertyValue);
+ legacy_hal_.reset();
+ event_cb_handler_.invalidate();
+ is_valid_ = false;
+}
+
+bool WifiChip::isValid() {
+ return is_valid_;
+}
+
+std::set<sp<V1_4::IWifiChipEventCallback>> WifiChip::getEventCallbacks() {
+ return event_cb_handler_.getCallbacks();
+}
+
+Return<void> WifiChip::getId(getId_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, &WifiChip::getIdInternal,
+ hidl_status_cb);
+}
+
+// Deprecated support for this callback
+Return<void> WifiChip::registerEventCallback(const sp<V1_0::IWifiChipEventCallback>& event_callback,
+ registerEventCallback_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::registerEventCallbackInternal, hidl_status_cb,
+ event_callback);
+}
+
+Return<void> WifiChip::getCapabilities(getCapabilities_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::getCapabilitiesInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getAvailableModes(getAvailableModes_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::getAvailableModesInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::configureChip(ChipModeId mode_id, configureChip_cb hidl_status_cb) {
+ return validateAndCallWithLock(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::configureChipInternal, hidl_status_cb, mode_id);
+}
+
+Return<void> WifiChip::getMode(getMode_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::getModeInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::requestChipDebugInfo(requestChipDebugInfo_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::requestChipDebugInfoInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::requestDriverDebugDump(requestDriverDebugDump_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::requestDriverDebugDumpInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::requestFirmwareDebugDump(requestFirmwareDebugDump_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::requestFirmwareDebugDumpInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::createApIface(createApIface_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::createApIfaceInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::createBridgedApIface(createBridgedApIface_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::createBridgedApIfaceInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getApIfaceNames(getApIfaceNames_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::getApIfaceNamesInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getApIface(const hidl_string& ifname, getApIface_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::getApIfaceInternal, hidl_status_cb, ifname);
+}
+
+Return<void> WifiChip::removeApIface(const hidl_string& ifname, removeApIface_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::removeApIfaceInternal, hidl_status_cb, ifname);
+}
+
+Return<void> WifiChip::removeIfaceInstanceFromBridgedApIface(
+ const hidl_string& ifname, const hidl_string& ifInstanceName,
+ removeIfaceInstanceFromBridgedApIface_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::removeIfaceInstanceFromBridgedApIfaceInternal, hidl_status_cb,
+ ifname, ifInstanceName);
+}
+
+Return<void> WifiChip::createNanIface(createNanIface_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::createNanIfaceInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getNanIfaceNames(getNanIfaceNames_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::getNanIfaceNamesInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getNanIface(const hidl_string& ifname, getNanIface_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::getNanIfaceInternal, hidl_status_cb, ifname);
+}
+
+Return<void> WifiChip::removeNanIface(const hidl_string& ifname, removeNanIface_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::removeNanIfaceInternal, hidl_status_cb, ifname);
+}
+
+Return<void> WifiChip::createP2pIface(createP2pIface_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::createP2pIfaceInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getP2pIfaceNames(getP2pIfaceNames_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::getP2pIfaceNamesInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getP2pIface(const hidl_string& ifname, getP2pIface_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::getP2pIfaceInternal, hidl_status_cb, ifname);
+}
+
+Return<void> WifiChip::removeP2pIface(const hidl_string& ifname, removeP2pIface_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::removeP2pIfaceInternal, hidl_status_cb, ifname);
+}
+
+Return<void> WifiChip::createStaIface(createStaIface_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::createStaIfaceInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getStaIfaceNames(getStaIfaceNames_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::getStaIfaceNamesInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getStaIface(const hidl_string& ifname, getStaIface_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::getStaIfaceInternal, hidl_status_cb, ifname);
+}
+
+Return<void> WifiChip::removeStaIface(const hidl_string& ifname, removeStaIface_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::removeStaIfaceInternal, hidl_status_cb, ifname);
+}
+
+Return<void> WifiChip::createRttController(const sp<IWifiIface>& bound_iface,
+ createRttController_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::createRttControllerInternal, hidl_status_cb, bound_iface);
+}
+
+Return<void> WifiChip::getDebugRingBuffersStatus(getDebugRingBuffersStatus_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::getDebugRingBuffersStatusInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::startLoggingToDebugRingBuffer(
+ const hidl_string& ring_name, WifiDebugRingBufferVerboseLevel verbose_level,
+ uint32_t max_interval_in_sec, uint32_t min_data_size_in_bytes,
+ startLoggingToDebugRingBuffer_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::startLoggingToDebugRingBufferInternal, hidl_status_cb,
+ ring_name, verbose_level, max_interval_in_sec, min_data_size_in_bytes);
+}
+
+Return<void> WifiChip::forceDumpToDebugRingBuffer(const hidl_string& ring_name,
+ forceDumpToDebugRingBuffer_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::forceDumpToDebugRingBufferInternal, hidl_status_cb,
+ ring_name);
+}
+
+Return<void> WifiChip::flushRingBufferToFile(flushRingBufferToFile_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::flushRingBufferToFileInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::stopLoggingToDebugRingBuffer(
+ stopLoggingToDebugRingBuffer_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::stopLoggingToDebugRingBufferInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getDebugHostWakeReasonStats(getDebugHostWakeReasonStats_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::getDebugHostWakeReasonStatsInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::enableDebugErrorAlerts(bool enable,
+ enableDebugErrorAlerts_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::enableDebugErrorAlertsInternal, hidl_status_cb, enable);
+}
+
+Return<void> WifiChip::selectTxPowerScenario(V1_1::IWifiChip::TxPowerScenario scenario,
+ selectTxPowerScenario_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::selectTxPowerScenarioInternal, hidl_status_cb, scenario);
+}
+
+Return<void> WifiChip::resetTxPowerScenario(resetTxPowerScenario_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::resetTxPowerScenarioInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::setLatencyMode(LatencyMode mode, setLatencyMode_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::setLatencyModeInternal, hidl_status_cb, mode);
+}
+
+Return<void> WifiChip::registerEventCallback_1_2(
+ const sp<V1_2::IWifiChipEventCallback>& event_callback,
+ registerEventCallback_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::registerEventCallbackInternal_1_2, hidl_status_cb,
+ event_callback);
+}
+
+Return<void> WifiChip::selectTxPowerScenario_1_2(TxPowerScenario scenario,
+ selectTxPowerScenario_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::selectTxPowerScenarioInternal_1_2, hidl_status_cb, scenario);
+}
+
+Return<void> WifiChip::getCapabilities_1_3(getCapabilities_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::getCapabilitiesInternal_1_3, hidl_status_cb);
+}
+
+Return<void> WifiChip::getCapabilities_1_5(getCapabilities_1_5_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::getCapabilitiesInternal_1_5, hidl_status_cb);
+}
+
+Return<void> WifiChip::debug(const hidl_handle& handle, const hidl_vec<hidl_string>&) {
+ if (handle != nullptr && handle->numFds >= 1) {
+ {
+ std::unique_lock<std::mutex> lk(lock_t);
+ for (const auto& item : ringbuffer_map_) {
+ forceDumpToDebugRingBufferInternal(item.first);
+ }
+ // unique_lock unlocked here
+ }
+ usleep(100 * 1000); // sleep for 100 milliseconds to wait for
+ // ringbuffer updates.
+ int fd = handle->data[0];
+ if (!writeRingbufferFilesInternal()) {
+ LOG(ERROR) << "Error writing files to flash";
+ }
+ uint32_t n_error = cpioArchiveFilesInDir(fd, kTombstoneFolderPath);
+ if (n_error != 0) {
+ LOG(ERROR) << n_error << " errors occured in cpio function";
+ }
+ fsync(fd);
+ } else {
+ LOG(ERROR) << "File handle error";
+ }
+ return Void();
+}
+
+Return<void> WifiChip::createRttController_1_4(const sp<IWifiIface>& bound_iface,
+ createRttController_1_4_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::createRttControllerInternal_1_4, hidl_status_cb, bound_iface);
+}
+
+Return<void> WifiChip::registerEventCallback_1_4(
+ const sp<V1_4::IWifiChipEventCallback>& event_callback,
+ registerEventCallback_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::registerEventCallbackInternal_1_4, hidl_status_cb,
+ event_callback);
+}
+
+Return<void> WifiChip::setMultiStaPrimaryConnection(
+ const hidl_string& ifname, setMultiStaPrimaryConnection_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::setMultiStaPrimaryConnectionInternal, hidl_status_cb, ifname);
+}
+
+Return<void> WifiChip::setMultiStaUseCase(MultiStaUseCase use_case,
+ setMultiStaUseCase_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::setMultiStaUseCaseInternal, hidl_status_cb, use_case);
+}
+
+Return<void> WifiChip::setCoexUnsafeChannels(const hidl_vec<CoexUnsafeChannel>& unsafeChannels,
+ hidl_bitfield<CoexRestriction> restrictions,
+ setCoexUnsafeChannels_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::setCoexUnsafeChannelsInternal, hidl_status_cb, unsafeChannels,
+ restrictions);
+}
+
+Return<void> WifiChip::setCountryCode(const hidl_array<int8_t, 2>& code,
+ setCountryCode_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiChip::setCountryCodeInternal, hidl_status_cb, code);
+}
+
+Return<void> WifiChip::getUsableChannels(
+ WifiBand band, hidl_bitfield<V1_5::WifiIfaceMode> ifaceModeMask,
+ hidl_bitfield<V1_5::IWifiChip::UsableChannelFilter> filterMask,
+ getUsableChannels_cb _hidl_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::getUsableChannelsInternal, _hidl_cb, band, ifaceModeMask,
+ filterMask);
+}
+
+Return<void> WifiChip::triggerSubsystemRestart(triggerSubsystemRestart_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::triggerSubsystemRestartInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::createRttController_1_6(const sp<IWifiIface>& bound_iface,
+ createRttController_1_6_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::createRttControllerInternal_1_6, hidl_status_cb, bound_iface);
+}
+
+Return<void> WifiChip::getUsableChannels_1_6(
+ WifiBand band, hidl_bitfield<V1_5::WifiIfaceMode> ifaceModeMask,
+ hidl_bitfield<V1_6::IWifiChip::UsableChannelFilter> filterMask,
+ getUsableChannels_1_6_cb _hidl_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::getUsableChannelsInternal_1_6, _hidl_cb, band, ifaceModeMask,
+ filterMask);
+}
+
+Return<void> WifiChip::getSupportedRadioCombinationsMatrix(
+ getSupportedRadioCombinationsMatrix_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::getSupportedRadioCombinationsMatrixInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getAvailableModes_1_6(getAvailableModes_1_6_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::getAvailableModesInternal_1_6, hidl_status_cb);
+}
+
+void WifiChip::invalidateAndRemoveAllIfaces() {
+ invalidateAndClearBridgedApAll();
+ invalidateAndClearAll(ap_ifaces_);
+ invalidateAndClearAll(nan_ifaces_);
+ invalidateAndClearAll(p2p_ifaces_);
+ invalidateAndClearAll(sta_ifaces_);
+ // Since all the ifaces are invalid now, all RTT controller objects
+ // using those ifaces also need to be invalidated.
+ for (const auto& rtt : rtt_controllers_) {
+ rtt->invalidate();
+ }
+ rtt_controllers_.clear();
+}
+
+void WifiChip::invalidateAndRemoveDependencies(const std::string& removed_iface_name) {
+ for (auto it = nan_ifaces_.begin(); it != nan_ifaces_.end();) {
+ auto nan_iface = *it;
+ if (nan_iface->getName() == removed_iface_name) {
+ nan_iface->invalidate();
+ for (const auto& callback : event_cb_handler_.getCallbacks()) {
+ if (!callback->onIfaceRemoved(IfaceType::NAN, removed_iface_name).isOk()) {
+ LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
+ }
+ }
+ it = nan_ifaces_.erase(it);
+ } else {
+ ++it;
+ }
+ }
+
+ for (auto it = rtt_controllers_.begin(); it != rtt_controllers_.end();) {
+ auto rtt = *it;
+ if (rtt->getIfaceName() == removed_iface_name) {
+ rtt->invalidate();
+ it = rtt_controllers_.erase(it);
+ } else {
+ ++it;
+ }
+ }
+}
+
+std::pair<WifiStatus, ChipId> WifiChip::getIdInternal() {
+ return {createWifiStatus(WifiStatusCode::SUCCESS), chip_id_};
+}
+
+WifiStatus WifiChip::registerEventCallbackInternal(
+ const sp<V1_0::IWifiChipEventCallback>& /* event_callback */) {
+ // Deprecated support for this callback.
+ return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+std::pair<WifiStatus, uint32_t> WifiChip::getCapabilitiesInternal() {
+ // Deprecated support for this callback.
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), 0};
+}
+
+std::pair<WifiStatus, std::vector<V1_0::IWifiChip::ChipMode>>
+WifiChip::getAvailableModesInternal() {
+ // Deprecated support -- use getAvailableModes_1_6 for more granular concurrency combinations.
+ std::vector<V1_0::IWifiChip::ChipMode> modes_1_0 = {};
+ for (const auto& mode_1_6 : modes_) {
+ std::vector<V1_0::IWifiChip::ChipIfaceCombination> combos_1_0;
+ for (const auto& combo_1_6 : mode_1_6.availableCombinations) {
+ std::vector<V1_0::IWifiChip::ChipIfaceCombinationLimit> limits_1_0;
+ for (const auto& limit_1_6 : combo_1_6.limits) {
+ std::vector<IfaceType> types_1_0;
+ for (IfaceConcurrencyType type_1_6 : limit_1_6.types) {
+ switch (type_1_6) {
+ case IfaceConcurrencyType::STA:
+ types_1_0.push_back(IfaceType::STA);
+ break;
+ case IfaceConcurrencyType::AP:
+ types_1_0.push_back(IfaceType::AP);
+ break;
+ case IfaceConcurrencyType::AP_BRIDGED:
+ // Ignore AP_BRIDGED
+ break;
+ case IfaceConcurrencyType::P2P:
+ types_1_0.push_back(IfaceType::P2P);
+ break;
+ case IfaceConcurrencyType::NAN:
+ types_1_0.push_back(IfaceType::NAN);
+ break;
+ }
+ }
+ if (types_1_0.empty()) {
+ continue;
+ }
+ V1_0::IWifiChip::ChipIfaceCombinationLimit limit_1_0;
+ limit_1_0.types = hidl_vec(types_1_0);
+ limit_1_0.maxIfaces = limit_1_6.maxIfaces;
+ limits_1_0.push_back(limit_1_0);
+ }
+ if (limits_1_0.empty()) {
+ continue;
+ }
+ V1_0::IWifiChip::ChipIfaceCombination combo_1_0;
+ combo_1_0.limits = hidl_vec(limits_1_0);
+ combos_1_0.push_back(combo_1_0);
+ }
+ if (combos_1_0.empty()) {
+ continue;
+ }
+ V1_0::IWifiChip::ChipMode mode_1_0;
+ mode_1_0.id = mode_1_6.id;
+ mode_1_0.availableCombinations = hidl_vec(combos_1_0);
+ modes_1_0.push_back(mode_1_0);
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), modes_1_0};
+}
+
+WifiStatus WifiChip::configureChipInternal(
+ /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock, ChipModeId mode_id) {
+ if (!isValidModeId(mode_id)) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ if (mode_id == current_mode_id_) {
+ LOG(DEBUG) << "Already in the specified mode " << mode_id;
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+ }
+ WifiStatus status = handleChipConfiguration(lock, mode_id);
+ if (status.code != WifiStatusCode::SUCCESS) {
+ for (const auto& callback : event_cb_handler_.getCallbacks()) {
+ if (!callback->onChipReconfigureFailure(status).isOk()) {
+ LOG(ERROR) << "Failed to invoke onChipReconfigureFailure callback";
+ }
+ }
+ return status;
+ }
+ for (const auto& callback : event_cb_handler_.getCallbacks()) {
+ if (!callback->onChipReconfigured(mode_id).isOk()) {
+ LOG(ERROR) << "Failed to invoke onChipReconfigured callback";
+ }
+ }
+ current_mode_id_ = mode_id;
+ LOG(INFO) << "Configured chip in mode " << mode_id;
+ setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
+
+ legacy_hal_.lock()->registerSubsystemRestartCallbackHandler(subsystemCallbackHandler_);
+
+ return status;
+}
+
+std::pair<WifiStatus, uint32_t> WifiChip::getModeInternal() {
+ if (!isValidModeId(current_mode_id_)) {
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), current_mode_id_};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), current_mode_id_};
+}
+
+std::pair<WifiStatus, V1_4::IWifiChip::ChipDebugInfo> WifiChip::requestChipDebugInfoInternal() {
+ V1_4::IWifiChip::ChipDebugInfo result;
+ legacy_hal::wifi_error legacy_status;
+ std::string driver_desc;
+ const auto ifname = getFirstActiveWlanIfaceName();
+ std::tie(legacy_status, driver_desc) = legacy_hal_.lock()->getDriverVersion(ifname);
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ LOG(ERROR) << "Failed to get driver version: " << legacyErrorToString(legacy_status);
+ WifiStatus status =
+ createWifiStatusFromLegacyError(legacy_status, "failed to get driver version");
+ return {status, result};
+ }
+ result.driverDescription = driver_desc.c_str();
+
+ std::string firmware_desc;
+ std::tie(legacy_status, firmware_desc) = legacy_hal_.lock()->getFirmwareVersion(ifname);
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ LOG(ERROR) << "Failed to get firmware version: " << legacyErrorToString(legacy_status);
+ WifiStatus status =
+ createWifiStatusFromLegacyError(legacy_status, "failed to get firmware version");
+ return {status, result};
+ }
+ result.firmwareDescription = firmware_desc.c_str();
+
+ return {createWifiStatus(WifiStatusCode::SUCCESS), result};
+}
+
+std::pair<WifiStatus, std::vector<uint8_t>> WifiChip::requestDriverDebugDumpInternal() {
+ legacy_hal::wifi_error legacy_status;
+ std::vector<uint8_t> driver_dump;
+ std::tie(legacy_status, driver_dump) =
+ legacy_hal_.lock()->requestDriverMemoryDump(getFirstActiveWlanIfaceName());
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ LOG(ERROR) << "Failed to get driver debug dump: " << legacyErrorToString(legacy_status);
+ return {createWifiStatusFromLegacyError(legacy_status), std::vector<uint8_t>()};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), driver_dump};
+}
+
+std::pair<WifiStatus, std::vector<uint8_t>> WifiChip::requestFirmwareDebugDumpInternal() {
+ legacy_hal::wifi_error legacy_status;
+ std::vector<uint8_t> firmware_dump;
+ std::tie(legacy_status, firmware_dump) =
+ legacy_hal_.lock()->requestFirmwareMemoryDump(getFirstActiveWlanIfaceName());
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ LOG(ERROR) << "Failed to get firmware debug dump: " << legacyErrorToString(legacy_status);
+ return {createWifiStatusFromLegacyError(legacy_status), {}};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), firmware_dump};
+}
+
+WifiStatus WifiChip::createVirtualApInterface(const std::string& apVirtIf) {
+ legacy_hal::wifi_error legacy_status;
+ legacy_status = legacy_hal_.lock()->createVirtualInterface(
+ apVirtIf, hidl_struct_util::convertHidlIfaceTypeToLegacy(IfaceType::AP));
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ LOG(ERROR) << "Failed to add interface: " << apVirtIf << " "
+ << legacyErrorToString(legacy_status);
+ return createWifiStatusFromLegacyError(legacy_status);
+ }
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+sp<WifiApIface> WifiChip::newWifiApIface(std::string& ifname) {
+ std::vector<std::string> ap_instances;
+ for (auto const& it : br_ifaces_ap_instances_) {
+ if (it.first == ifname) {
+ ap_instances = it.second;
+ }
+ }
+ sp<WifiApIface> iface = new WifiApIface(ifname, ap_instances, legacy_hal_, iface_util_);
+ ap_ifaces_.push_back(iface);
+ for (const auto& callback : event_cb_handler_.getCallbacks()) {
+ if (!callback->onIfaceAdded(IfaceType::AP, ifname).isOk()) {
+ LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
+ }
+ }
+ setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
+ return iface;
+}
+
+std::pair<WifiStatus, sp<V1_5::IWifiApIface>> WifiChip::createApIfaceInternal() {
+ if (!canCurrentModeSupportConcurrencyTypeWithCurrentTypes(IfaceConcurrencyType::AP)) {
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
+ }
+ std::string ifname = allocateApIfaceName();
+ WifiStatus status = createVirtualApInterface(ifname);
+ if (status.code != WifiStatusCode::SUCCESS) {
+ return {status, {}};
+ }
+ sp<WifiApIface> iface = newWifiApIface(ifname);
+ return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
+}
+
+std::pair<WifiStatus, sp<V1_5::IWifiApIface>> WifiChip::createBridgedApIfaceInternal() {
+ if (!canCurrentModeSupportConcurrencyTypeWithCurrentTypes(IfaceConcurrencyType::AP_BRIDGED)) {
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
+ }
+ std::vector<std::string> ap_instances = allocateBridgedApInstanceNames();
+ if (ap_instances.size() < 2) {
+ LOG(ERROR) << "Fail to allocate two instances";
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
+ }
+ std::string br_ifname = kApBridgeIfacePrefix + ap_instances[0];
+ for (int i = 0; i < 2; i++) {
+ WifiStatus status = createVirtualApInterface(ap_instances[i]);
+ if (status.code != WifiStatusCode::SUCCESS) {
+ if (i != 0) { // The failure happened when creating second virtual
+ // iface.
+ legacy_hal_.lock()->deleteVirtualInterface(
+ ap_instances.front()); // Remove the first virtual iface.
+ }
+ return {status, {}};
+ }
+ }
+ br_ifaces_ap_instances_[br_ifname] = ap_instances;
+ if (!iface_util_->createBridge(br_ifname)) {
+ LOG(ERROR) << "Failed createBridge - br_name=" << br_ifname.c_str();
+ deleteApIface(br_ifname);
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
+ }
+ for (auto const& instance : ap_instances) {
+ // Bind ap instance interface to AP bridge
+ if (!iface_util_->addIfaceToBridge(br_ifname, instance)) {
+ LOG(ERROR) << "Failed add if to Bridge - if_name=" << instance.c_str();
+ deleteApIface(br_ifname);
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
+ }
+ }
+ sp<WifiApIface> iface = newWifiApIface(br_ifname);
+ return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
+}
+
+std::pair<WifiStatus, std::vector<hidl_string>> WifiChip::getApIfaceNamesInternal() {
+ if (ap_ifaces_.empty()) {
+ return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(ap_ifaces_)};
+}
+
+std::pair<WifiStatus, sp<V1_5::IWifiApIface>> WifiChip::getApIfaceInternal(
+ const std::string& ifname) {
+ const auto iface = findUsingName(ap_ifaces_, ifname);
+ if (!iface.get()) {
+ return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
+}
+
+WifiStatus WifiChip::removeApIfaceInternal(const std::string& ifname) {
+ const auto iface = findUsingName(ap_ifaces_, ifname);
+ if (!iface.get()) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ // Invalidate & remove any dependent objects first.
+ // Note: This is probably not required because we never create
+ // nan/rtt objects over AP iface. But, there is no harm to do it
+ // here and not make that assumption all over the place.
+ invalidateAndRemoveDependencies(ifname);
+ deleteApIface(ifname);
+ invalidateAndClear(ap_ifaces_, iface);
+ for (const auto& callback : event_cb_handler_.getCallbacks()) {
+ if (!callback->onIfaceRemoved(IfaceType::AP, ifname).isOk()) {
+ LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
+ }
+ }
+ setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+WifiStatus WifiChip::removeIfaceInstanceFromBridgedApIfaceInternal(
+ const std::string& ifname, const std::string& ifInstanceName) {
+ const auto iface = findUsingName(ap_ifaces_, ifname);
+ if (!iface.get() || ifInstanceName.empty()) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ // Requires to remove one of the instance in bridge mode
+ for (auto const& it : br_ifaces_ap_instances_) {
+ if (it.first == ifname) {
+ std::vector<std::string> ap_instances = it.second;
+ for (auto const& iface : ap_instances) {
+ if (iface == ifInstanceName) {
+ if (!iface_util_->removeIfaceFromBridge(it.first, iface)) {
+ LOG(ERROR) << "Failed to remove interface: " << ifInstanceName << " from "
+ << ifname;
+ return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE);
+ }
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->deleteVirtualInterface(iface);
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ LOG(ERROR) << "Failed to del interface: " << iface << " "
+ << legacyErrorToString(legacy_status);
+ return createWifiStatusFromLegacyError(legacy_status);
+ }
+ ap_instances.erase(
+ std::remove(ap_instances.begin(), ap_instances.end(), ifInstanceName),
+ ap_instances.end());
+ br_ifaces_ap_instances_[ifname] = ap_instances;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ iface->removeInstance(ifInstanceName);
+ setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
+
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+std::pair<WifiStatus, sp<V1_4::IWifiNanIface>> WifiChip::createNanIfaceInternal() {
+ if (!canCurrentModeSupportConcurrencyTypeWithCurrentTypes(IfaceConcurrencyType::NAN)) {
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
+ }
+ bool is_dedicated_iface = true;
+ std::string ifname = getPredefinedNanIfaceName();
+ if (ifname.empty() || !iface_util_->ifNameToIndex(ifname)) {
+ // Use the first shared STA iface (wlan0) if a dedicated aware iface is
+ // not defined.
+ ifname = getFirstActiveWlanIfaceName();
+ is_dedicated_iface = false;
+ }
+ sp<WifiNanIface> iface = new WifiNanIface(ifname, is_dedicated_iface, legacy_hal_, iface_util_);
+ nan_ifaces_.push_back(iface);
+ for (const auto& callback : event_cb_handler_.getCallbacks()) {
+ if (!callback->onIfaceAdded(IfaceType::NAN, ifname).isOk()) {
+ LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
+ }
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
+}
+
+std::pair<WifiStatus, std::vector<hidl_string>> WifiChip::getNanIfaceNamesInternal() {
+ if (nan_ifaces_.empty()) {
+ return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(nan_ifaces_)};
+}
+
+std::pair<WifiStatus, sp<V1_4::IWifiNanIface>> WifiChip::getNanIfaceInternal(
+ const std::string& ifname) {
+ const auto iface = findUsingName(nan_ifaces_, ifname);
+ if (!iface.get()) {
+ return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
+}
+
+WifiStatus WifiChip::removeNanIfaceInternal(const std::string& ifname) {
+ const auto iface = findUsingName(nan_ifaces_, ifname);
+ if (!iface.get()) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ invalidateAndClear(nan_ifaces_, iface);
+ for (const auto& callback : event_cb_handler_.getCallbacks()) {
+ if (!callback->onIfaceRemoved(IfaceType::NAN, ifname).isOk()) {
+ LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
+ }
+ }
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+std::pair<WifiStatus, sp<IWifiP2pIface>> WifiChip::createP2pIfaceInternal() {
+ if (!canCurrentModeSupportConcurrencyTypeWithCurrentTypes(IfaceConcurrencyType::P2P)) {
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
+ }
+ std::string ifname = getPredefinedP2pIfaceName();
+ sp<WifiP2pIface> iface = new WifiP2pIface(ifname, legacy_hal_);
+ p2p_ifaces_.push_back(iface);
+ for (const auto& callback : event_cb_handler_.getCallbacks()) {
+ if (!callback->onIfaceAdded(IfaceType::P2P, ifname).isOk()) {
+ LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
+ }
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
+}
+
+std::pair<WifiStatus, std::vector<hidl_string>> WifiChip::getP2pIfaceNamesInternal() {
+ if (p2p_ifaces_.empty()) {
+ return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(p2p_ifaces_)};
+}
+
+std::pair<WifiStatus, sp<IWifiP2pIface>> WifiChip::getP2pIfaceInternal(const std::string& ifname) {
+ const auto iface = findUsingName(p2p_ifaces_, ifname);
+ if (!iface.get()) {
+ return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
+}
+
+WifiStatus WifiChip::removeP2pIfaceInternal(const std::string& ifname) {
+ const auto iface = findUsingName(p2p_ifaces_, ifname);
+ if (!iface.get()) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ invalidateAndClear(p2p_ifaces_, iface);
+ for (const auto& callback : event_cb_handler_.getCallbacks()) {
+ if (!callback->onIfaceRemoved(IfaceType::P2P, ifname).isOk()) {
+ LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
+ }
+ }
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+std::pair<WifiStatus, sp<V1_6::IWifiStaIface>> WifiChip::createStaIfaceInternal() {
+ if (!canCurrentModeSupportConcurrencyTypeWithCurrentTypes(IfaceConcurrencyType::STA)) {
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
+ }
+ std::string ifname = allocateStaIfaceName();
+ legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->createVirtualInterface(
+ ifname, hidl_struct_util::convertHidlIfaceTypeToLegacy(IfaceType::STA));
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ LOG(ERROR) << "Failed to add interface: " << ifname << " "
+ << legacyErrorToString(legacy_status);
+ return {createWifiStatusFromLegacyError(legacy_status), {}};
+ }
+ sp<WifiStaIface> iface = new WifiStaIface(ifname, legacy_hal_, iface_util_);
+ sta_ifaces_.push_back(iface);
+ for (const auto& callback : event_cb_handler_.getCallbacks()) {
+ if (!callback->onIfaceAdded(IfaceType::STA, ifname).isOk()) {
+ LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
+ }
+ }
+ setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
+ return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
+}
+
+std::pair<WifiStatus, std::vector<hidl_string>> WifiChip::getStaIfaceNamesInternal() {
+ if (sta_ifaces_.empty()) {
+ return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(sta_ifaces_)};
+}
+
+std::pair<WifiStatus, sp<V1_6::IWifiStaIface>> WifiChip::getStaIfaceInternal(
+ const std::string& ifname) {
+ const auto iface = findUsingName(sta_ifaces_, ifname);
+ if (!iface.get()) {
+ return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
+}
+
+WifiStatus WifiChip::removeStaIfaceInternal(const std::string& ifname) {
+ const auto iface = findUsingName(sta_ifaces_, ifname);
+ if (!iface.get()) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ // Invalidate & remove any dependent objects first.
+ invalidateAndRemoveDependencies(ifname);
+ legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->deleteVirtualInterface(ifname);
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ LOG(ERROR) << "Failed to remove interface: " << ifname << " "
+ << legacyErrorToString(legacy_status);
+ }
+ invalidateAndClear(sta_ifaces_, iface);
+ for (const auto& callback : event_cb_handler_.getCallbacks()) {
+ if (!callback->onIfaceRemoved(IfaceType::STA, ifname).isOk()) {
+ LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
+ }
+ }
+ setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+std::pair<WifiStatus, sp<V1_0::IWifiRttController>> WifiChip::createRttControllerInternal(
+ const sp<IWifiIface>& /*bound_iface*/) {
+ LOG(ERROR) << "createRttController is not supported on this HAL";
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
+}
+
+std::pair<WifiStatus, std::vector<WifiDebugRingBufferStatus>>
+WifiChip::getDebugRingBuffersStatusInternal() {
+ legacy_hal::wifi_error legacy_status;
+ std::vector<legacy_hal::wifi_ring_buffer_status> legacy_ring_buffer_status_vec;
+ std::tie(legacy_status, legacy_ring_buffer_status_vec) =
+ legacy_hal_.lock()->getRingBuffersStatus(getFirstActiveWlanIfaceName());
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ return {createWifiStatusFromLegacyError(legacy_status), {}};
+ }
+ std::vector<WifiDebugRingBufferStatus> hidl_ring_buffer_status_vec;
+ if (!hidl_struct_util::convertLegacyVectorOfDebugRingBufferStatusToHidl(
+ legacy_ring_buffer_status_vec, &hidl_ring_buffer_status_vec)) {
+ return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_ring_buffer_status_vec};
+}
+
+WifiStatus WifiChip::startLoggingToDebugRingBufferInternal(
+ const hidl_string& ring_name, WifiDebugRingBufferVerboseLevel verbose_level,
+ uint32_t max_interval_in_sec, uint32_t min_data_size_in_bytes) {
+ WifiStatus status = registerDebugRingBufferCallback();
+ if (status.code != WifiStatusCode::SUCCESS) {
+ return status;
+ }
+ legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->startRingBufferLogging(
+ getFirstActiveWlanIfaceName(), ring_name,
+ static_cast<std::underlying_type<WifiDebugRingBufferVerboseLevel>::type>(verbose_level),
+ max_interval_in_sec, min_data_size_in_bytes);
+ ringbuffer_map_.insert(
+ std::pair<std::string, Ringbuffer>(ring_name, Ringbuffer(kMaxBufferSizeBytes)));
+ // if verbose logging enabled, turn up HAL daemon logging as well.
+ if (verbose_level < WifiDebugRingBufferVerboseLevel::VERBOSE) {
+ android::base::SetMinimumLogSeverity(android::base::DEBUG);
+ } else {
+ android::base::SetMinimumLogSeverity(android::base::VERBOSE);
+ }
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiChip::forceDumpToDebugRingBufferInternal(const hidl_string& ring_name) {
+ WifiStatus status = registerDebugRingBufferCallback();
+ if (status.code != WifiStatusCode::SUCCESS) {
+ return status;
+ }
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->getRingBufferData(getFirstActiveWlanIfaceName(), ring_name);
+
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiChip::flushRingBufferToFileInternal() {
+ if (!writeRingbufferFilesInternal()) {
+ LOG(ERROR) << "Error writing files to flash";
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+ }
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+WifiStatus WifiChip::stopLoggingToDebugRingBufferInternal() {
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->deregisterRingBufferCallbackHandler(getFirstActiveWlanIfaceName());
+ if (legacy_status == legacy_hal::WIFI_SUCCESS) {
+ debug_ring_buffer_cb_registered_ = false;
+ }
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, WifiDebugHostWakeReasonStats>
+WifiChip::getDebugHostWakeReasonStatsInternal() {
+ legacy_hal::wifi_error legacy_status;
+ legacy_hal::WakeReasonStats legacy_stats;
+ std::tie(legacy_status, legacy_stats) =
+ legacy_hal_.lock()->getWakeReasonStats(getFirstActiveWlanIfaceName());
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ return {createWifiStatusFromLegacyError(legacy_status), {}};
+ }
+ WifiDebugHostWakeReasonStats hidl_stats;
+ if (!hidl_struct_util::convertLegacyWakeReasonStatsToHidl(legacy_stats, &hidl_stats)) {
+ return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_stats};
+}
+
+WifiStatus WifiChip::enableDebugErrorAlertsInternal(bool enable) {
+ legacy_hal::wifi_error legacy_status;
+ if (enable) {
+ android::wp<WifiChip> weak_ptr_this(this);
+ const auto& on_alert_callback = [weak_ptr_this](int32_t error_code,
+ std::vector<uint8_t> debug_data) {
+ const auto shared_ptr_this = weak_ptr_this.promote();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->onDebugErrorAlert(error_code, debug_data).isOk()) {
+ LOG(ERROR) << "Failed to invoke onDebugErrorAlert callback";
+ }
+ }
+ };
+ legacy_status = legacy_hal_.lock()->registerErrorAlertCallbackHandler(
+ getFirstActiveWlanIfaceName(), on_alert_callback);
+ } else {
+ legacy_status = legacy_hal_.lock()->deregisterErrorAlertCallbackHandler(
+ getFirstActiveWlanIfaceName());
+ }
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiChip::selectTxPowerScenarioInternal(V1_1::IWifiChip::TxPowerScenario scenario) {
+ auto legacy_status = legacy_hal_.lock()->selectTxPowerScenario(
+ getFirstActiveWlanIfaceName(),
+ hidl_struct_util::convertHidlTxPowerScenarioToLegacy(scenario));
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiChip::resetTxPowerScenarioInternal() {
+ auto legacy_status = legacy_hal_.lock()->resetTxPowerScenario(getFirstActiveWlanIfaceName());
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiChip::setLatencyModeInternal(LatencyMode mode) {
+ auto legacy_status = legacy_hal_.lock()->setLatencyMode(
+ getFirstActiveWlanIfaceName(), hidl_struct_util::convertHidlLatencyModeToLegacy(mode));
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiChip::registerEventCallbackInternal_1_2(
+ const sp<V1_2::IWifiChipEventCallback>& /* event_callback */) {
+ // Deprecated support for this callback.
+ return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiChip::selectTxPowerScenarioInternal_1_2(TxPowerScenario scenario) {
+ auto legacy_status = legacy_hal_.lock()->selectTxPowerScenario(
+ getFirstActiveWlanIfaceName(),
+ hidl_struct_util::convertHidlTxPowerScenarioToLegacy_1_2(scenario));
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, uint32_t> WifiChip::getCapabilitiesInternal_1_3() {
+ // Deprecated support for this callback.
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), 0};
+}
+
+std::pair<WifiStatus, uint32_t> WifiChip::getCapabilitiesInternal_1_5() {
+ legacy_hal::wifi_error legacy_status;
+ uint64_t legacy_feature_set;
+ uint32_t legacy_logger_feature_set;
+ const auto ifname = getFirstActiveWlanIfaceName();
+ std::tie(legacy_status, legacy_feature_set) =
+ legacy_hal_.lock()->getSupportedFeatureSet(ifname);
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ return {createWifiStatusFromLegacyError(legacy_status), 0};
+ }
+ std::tie(legacy_status, legacy_logger_feature_set) =
+ legacy_hal_.lock()->getLoggerSupportedFeatureSet(ifname);
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ // some devices don't support querying logger feature set
+ legacy_logger_feature_set = 0;
+ }
+ uint32_t hidl_caps;
+ if (!hidl_struct_util::convertLegacyFeaturesToHidlChipCapabilities(
+ legacy_feature_set, legacy_logger_feature_set, &hidl_caps)) {
+ return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), 0};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
+}
+
+std::pair<WifiStatus, sp<V1_4::IWifiRttController>> WifiChip::createRttControllerInternal_1_4(
+ const sp<IWifiIface>& /*bound_iface*/) {
+ LOG(ERROR) << "createRttController_1_4 is not supported on this HAL";
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
+}
+
+WifiStatus WifiChip::registerEventCallbackInternal_1_4(
+ const sp<V1_4::IWifiChipEventCallback>& event_callback) {
+ if (!event_cb_handler_.addCallback(event_callback)) {
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+ }
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+WifiStatus WifiChip::setMultiStaPrimaryConnectionInternal(const std::string& ifname) {
+ auto legacy_status = legacy_hal_.lock()->multiStaSetPrimaryConnection(ifname);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiChip::setMultiStaUseCaseInternal(MultiStaUseCase use_case) {
+ auto legacy_status = legacy_hal_.lock()->multiStaSetUseCase(
+ hidl_struct_util::convertHidlMultiStaUseCaseToLegacy(use_case));
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiChip::setCoexUnsafeChannelsInternal(std::vector<CoexUnsafeChannel> unsafe_channels,
+ uint32_t restrictions) {
+ std::vector<legacy_hal::wifi_coex_unsafe_channel> legacy_unsafe_channels;
+ if (!hidl_struct_util::convertHidlVectorOfCoexUnsafeChannelToLegacy(unsafe_channels,
+ &legacy_unsafe_channels)) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ uint32_t legacy_restrictions = 0;
+ if (restrictions & CoexRestriction::WIFI_DIRECT) {
+ legacy_restrictions |= legacy_hal::wifi_coex_restriction::WIFI_DIRECT;
+ }
+ if (restrictions & CoexRestriction::SOFTAP) {
+ legacy_restrictions |= legacy_hal::wifi_coex_restriction::SOFTAP;
+ }
+ if (restrictions & CoexRestriction::WIFI_AWARE) {
+ legacy_restrictions |= legacy_hal::wifi_coex_restriction::WIFI_AWARE;
+ }
+ auto legacy_status =
+ legacy_hal_.lock()->setCoexUnsafeChannels(legacy_unsafe_channels, legacy_restrictions);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiChip::setCountryCodeInternal(const std::array<int8_t, 2>& code) {
+ auto legacy_status = legacy_hal_.lock()->setCountryCode(getFirstActiveWlanIfaceName(), code);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, std::vector<V1_5::WifiUsableChannel>> WifiChip::getUsableChannelsInternal(
+ WifiBand /*band*/, uint32_t /*ifaceModeMask*/, uint32_t /*filterMask*/) {
+ LOG(ERROR) << "getUsableChannels is not supported on this HAL";
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
+}
+
+WifiStatus WifiChip::triggerSubsystemRestartInternal() {
+ auto legacy_status = legacy_hal_.lock()->triggerSubsystemRestart();
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, sp<V1_6::IWifiRttController>> WifiChip::createRttControllerInternal_1_6(
+ const sp<IWifiIface>& bound_iface) {
+ if (sta_ifaces_.size() == 0 &&
+ !canCurrentModeSupportConcurrencyTypeWithCurrentTypes(IfaceConcurrencyType::STA)) {
+ LOG(ERROR) << "createRttControllerInternal_1_6: Chip cannot support STAs "
+ "(and RTT by extension)";
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
+ }
+ sp<WifiRttController> rtt =
+ new WifiRttController(getFirstActiveWlanIfaceName(), bound_iface, legacy_hal_);
+ rtt_controllers_.emplace_back(rtt);
+ return {createWifiStatus(WifiStatusCode::SUCCESS), rtt};
+}
+
+std::pair<WifiStatus, std::vector<V1_6::WifiUsableChannel>> WifiChip::getUsableChannelsInternal_1_6(
+ WifiBand band, uint32_t ifaceModeMask, uint32_t filterMask) {
+ legacy_hal::wifi_error legacy_status;
+ std::vector<legacy_hal::wifi_usable_channel> legacy_usable_channels;
+ std::tie(legacy_status, legacy_usable_channels) = legacy_hal_.lock()->getUsableChannels(
+ hidl_struct_util::convertHidlWifiBandToLegacyMacBand(band),
+ hidl_struct_util::convertHidlWifiIfaceModeToLegacy(ifaceModeMask),
+ hidl_struct_util::convertHidlUsableChannelFilterToLegacy(filterMask));
+
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ return {createWifiStatusFromLegacyError(legacy_status), {}};
+ }
+ std::vector<V1_6::WifiUsableChannel> hidl_usable_channels;
+ if (!hidl_struct_util::convertLegacyWifiUsableChannelsToHidl(legacy_usable_channels,
+ &hidl_usable_channels)) {
+ return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_usable_channels};
+}
+
+std::pair<WifiStatus, V1_6::WifiRadioCombinationMatrix>
+WifiChip::getSupportedRadioCombinationsMatrixInternal() {
+ legacy_hal::wifi_error legacy_status;
+ legacy_hal::wifi_radio_combination_matrix* legacy_matrix;
+
+ std::tie(legacy_status, legacy_matrix) =
+ legacy_hal_.lock()->getSupportedRadioCombinationsMatrix();
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ LOG(ERROR) << "Failed to get SupportedRadioCombinations matrix from legacy HAL: "
+ << legacyErrorToString(legacy_status);
+ return {createWifiStatusFromLegacyError(legacy_status), {}};
+ }
+
+ V1_6::WifiRadioCombinationMatrix hidl_matrix;
+ if (!hidl_struct_util::convertLegacyRadioCombinationsMatrixToHidl(legacy_matrix,
+ &hidl_matrix)) {
+ LOG(ERROR) << "Failed convertLegacyRadioCombinationsMatrixToHidl() ";
+ return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), {}};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_matrix};
+}
+
+std::pair<WifiStatus, std::vector<V1_6::IWifiChip::ChipMode>>
+WifiChip::getAvailableModesInternal_1_6() {
+ return {createWifiStatus(WifiStatusCode::SUCCESS), modes_};
+}
+
+WifiStatus WifiChip::handleChipConfiguration(
+ /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock, ChipModeId mode_id) {
+ // If the chip is already configured in a different mode, stop
+ // the legacy HAL and then start it after firmware mode change.
+ if (isValidModeId(current_mode_id_)) {
+ LOG(INFO) << "Reconfiguring chip from mode " << current_mode_id_ << " to mode " << mode_id;
+ invalidateAndRemoveAllIfaces();
+ legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->stop(lock, []() {});
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ LOG(ERROR) << "Failed to stop legacy HAL: " << legacyErrorToString(legacy_status);
+ return createWifiStatusFromLegacyError(legacy_status);
+ }
+ }
+ // Firmware mode change not needed for V2 devices.
+ bool success = true;
+ if (mode_id == feature_flags::chip_mode_ids::kV1Sta) {
+ success = mode_controller_.lock()->changeFirmwareMode(IfaceType::STA);
+ } else if (mode_id == feature_flags::chip_mode_ids::kV1Ap) {
+ success = mode_controller_.lock()->changeFirmwareMode(IfaceType::AP);
+ }
+ if (!success) {
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+ }
+ legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->start();
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ LOG(ERROR) << "Failed to start legacy HAL: " << legacyErrorToString(legacy_status);
+ return createWifiStatusFromLegacyError(legacy_status);
+ }
+ // Every time the HAL is restarted, we need to register the
+ // radio mode change callback.
+ WifiStatus status = registerRadioModeChangeCallback();
+ if (status.code != WifiStatusCode::SUCCESS) {
+ // This probably is not a critical failure?
+ LOG(ERROR) << "Failed to register radio mode change callback";
+ }
+ // Extract and save the version information into property.
+ std::pair<WifiStatus, V1_4::IWifiChip::ChipDebugInfo> version_info;
+ version_info = WifiChip::requestChipDebugInfoInternal();
+ if (WifiStatusCode::SUCCESS == version_info.first.code) {
+ property_set("vendor.wlan.firmware.version",
+ version_info.second.firmwareDescription.c_str());
+ property_set("vendor.wlan.driver.version", version_info.second.driverDescription.c_str());
+ }
+
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+WifiStatus WifiChip::registerDebugRingBufferCallback() {
+ if (debug_ring_buffer_cb_registered_) {
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+ }
+
+ android::wp<WifiChip> weak_ptr_this(this);
+ const auto& on_ring_buffer_data_callback =
+ [weak_ptr_this](const std::string& name, const std::vector<uint8_t>& data,
+ const legacy_hal::wifi_ring_buffer_status& status) {
+ const auto shared_ptr_this = weak_ptr_this.promote();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ WifiDebugRingBufferStatus hidl_status;
+ Ringbuffer::AppendStatus appendstatus;
+ if (!hidl_struct_util::convertLegacyDebugRingBufferStatusToHidl(status,
+ &hidl_status)) {
+ LOG(ERROR) << "Error converting ring buffer status";
+ return;
+ }
+ {
+ std::unique_lock<std::mutex> lk(shared_ptr_this->lock_t);
+ const auto& target = shared_ptr_this->ringbuffer_map_.find(name);
+ if (target != shared_ptr_this->ringbuffer_map_.end()) {
+ Ringbuffer& cur_buffer = target->second;
+ appendstatus = cur_buffer.append(data);
+ } else {
+ LOG(ERROR) << "Ringname " << name << " not found";
+ return;
+ }
+ // unique_lock unlocked here
+ }
+ if (appendstatus == Ringbuffer::AppendStatus::FAIL_RING_BUFFER_CORRUPTED) {
+ LOG(ERROR) << "Ringname " << name << " is corrupted. Clear the ring buffer";
+ shared_ptr_this->writeRingbufferFilesInternal();
+ return;
+ }
+
+ };
+ legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->registerRingBufferCallbackHandler(
+ getFirstActiveWlanIfaceName(), on_ring_buffer_data_callback);
+
+ if (legacy_status == legacy_hal::WIFI_SUCCESS) {
+ debug_ring_buffer_cb_registered_ = true;
+ }
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiChip::registerRadioModeChangeCallback() {
+ android::wp<WifiChip> weak_ptr_this(this);
+ const auto& on_radio_mode_change_callback =
+ [weak_ptr_this](const std::vector<legacy_hal::WifiMacInfo>& mac_infos) {
+ const auto shared_ptr_this = weak_ptr_this.promote();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ std::vector<V1_4::IWifiChipEventCallback::RadioModeInfo> hidl_radio_mode_infos;
+ if (!hidl_struct_util::convertLegacyWifiMacInfosToHidl(mac_infos,
+ &hidl_radio_mode_infos)) {
+ LOG(ERROR) << "Error converting wifi mac info";
+ return;
+ }
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->onRadioModeChange_1_4(hidl_radio_mode_infos).isOk()) {
+ LOG(ERROR) << "Failed to invoke onRadioModeChange_1_4"
+ << " callback on: " << toString(callback);
+ }
+ }
+ };
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->registerRadioModeChangeCallbackHandler(
+ getFirstActiveWlanIfaceName(), on_radio_mode_change_callback);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::vector<V1_6::IWifiChip::ChipConcurrencyCombination>
+WifiChip::getCurrentModeConcurrencyCombinations() {
+ if (!isValidModeId(current_mode_id_)) {
+ LOG(ERROR) << "Chip not configured in a mode yet";
+ return {};
+ }
+ for (const auto& mode : modes_) {
+ if (mode.id == current_mode_id_) {
+ return mode.availableCombinations;
+ }
+ }
+ CHECK(0) << "Expected to find concurrency combinations for current mode!";
+ return {};
+}
+
+// Returns a map indexed by IfaceConcurrencyType with the number of ifaces currently
+// created of the corresponding concurrency type.
+std::map<IfaceConcurrencyType, size_t> WifiChip::getCurrentConcurrencyCombination() {
+ std::map<IfaceConcurrencyType, size_t> iface_counts;
+ uint32_t num_ap = 0;
+ uint32_t num_ap_bridged = 0;
+ for (const auto& ap_iface : ap_ifaces_) {
+ std::string ap_iface_name = ap_iface->getName();
+ if (br_ifaces_ap_instances_.count(ap_iface_name) > 0 &&
+ br_ifaces_ap_instances_[ap_iface_name].size() > 1) {
+ num_ap_bridged++;
+ } else {
+ num_ap++;
+ }
+ }
+ iface_counts[IfaceConcurrencyType::AP] = num_ap;
+ iface_counts[IfaceConcurrencyType::AP_BRIDGED] = num_ap_bridged;
+ iface_counts[IfaceConcurrencyType::NAN] = nan_ifaces_.size();
+ iface_counts[IfaceConcurrencyType::P2P] = p2p_ifaces_.size();
+ iface_counts[IfaceConcurrencyType::STA] = sta_ifaces_.size();
+ return iface_counts;
+}
+
+// This expands the provided concurrency combinations to a more parseable
+// form. Returns a vector of available combinations possible with the number
+// of each concurrency type in the combination.
+// This method is a port of HalDeviceManager.expandConcurrencyCombos() from framework.
+std::vector<std::map<IfaceConcurrencyType, size_t>> WifiChip::expandConcurrencyCombinations(
+ const V1_6::IWifiChip::ChipConcurrencyCombination& combination) {
+ uint32_t num_expanded_combos = 1;
+ for (const auto& limit : combination.limits) {
+ for (uint32_t i = 0; i < limit.maxIfaces; i++) {
+ num_expanded_combos *= limit.types.size();
+ }
+ }
+
+ // Allocate the vector of expanded combos and reset all concurrency type counts to 0
+ // in each combo.
+ std::vector<std::map<IfaceConcurrencyType, size_t>> expanded_combos;
+ expanded_combos.resize(num_expanded_combos);
+ for (auto& expanded_combo : expanded_combos) {
+ for (const auto type :
+ {IfaceConcurrencyType::AP, IfaceConcurrencyType::AP_BRIDGED, IfaceConcurrencyType::NAN,
+ IfaceConcurrencyType::P2P, IfaceConcurrencyType::STA}) {
+ expanded_combo[type] = 0;
+ }
+ }
+ uint32_t span = num_expanded_combos;
+ for (const auto& limit : combination.limits) {
+ for (uint32_t i = 0; i < limit.maxIfaces; i++) {
+ span /= limit.types.size();
+ for (uint32_t k = 0; k < num_expanded_combos; ++k) {
+ const auto iface_type = limit.types[(k / span) % limit.types.size()];
+ expanded_combos[k][iface_type]++;
+ }
+ }
+ }
+ return expanded_combos;
+}
+
+bool WifiChip::canExpandedConcurrencyComboSupportConcurrencyTypeWithCurrentTypes(
+ const std::map<IfaceConcurrencyType, size_t>& expanded_combo,
+ IfaceConcurrencyType requested_type) {
+ const auto current_combo = getCurrentConcurrencyCombination();
+
+ // Check if we have space for 1 more iface of |type| in this combo
+ for (const auto type :
+ {IfaceConcurrencyType::AP, IfaceConcurrencyType::AP_BRIDGED, IfaceConcurrencyType::NAN,
+ IfaceConcurrencyType::P2P, IfaceConcurrencyType::STA}) {
+ size_t num_ifaces_needed = current_combo.at(type);
+ if (type == requested_type) {
+ num_ifaces_needed++;
+ }
+ size_t num_ifaces_allowed = expanded_combo.at(type);
+ if (num_ifaces_needed > num_ifaces_allowed) {
+ return false;
+ }
+ }
+ return true;
+}
+
+// This method does the following:
+// a) Enumerate all possible concurrency combos by expanding the current
+// ChipConcurrencyCombination.
+// b) Check if the requested concurrency type can be added to the current mode
+// with the concurrency combination that is already active.
+bool WifiChip::canCurrentModeSupportConcurrencyTypeWithCurrentTypes(
+ IfaceConcurrencyType requested_type) {
+ if (!isValidModeId(current_mode_id_)) {
+ LOG(ERROR) << "Chip not configured in a mode yet";
+ return false;
+ }
+ const auto combinations = getCurrentModeConcurrencyCombinations();
+ for (const auto& combination : combinations) {
+ const auto expanded_combos = expandConcurrencyCombinations(combination);
+ for (const auto& expanded_combo : expanded_combos) {
+ if (canExpandedConcurrencyComboSupportConcurrencyTypeWithCurrentTypes(expanded_combo,
+ requested_type)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+// Note: This does not consider concurrency types already active. It only checks if the
+// provided expanded concurrency combination can support the requested combo.
+bool WifiChip::canExpandedConcurrencyComboSupportConcurrencyCombo(
+ const std::map<IfaceConcurrencyType, size_t>& expanded_combo,
+ const std::map<IfaceConcurrencyType, size_t>& req_combo) {
+ // Check if we have space for 1 more |type| in this combo
+ for (const auto type :
+ {IfaceConcurrencyType::AP, IfaceConcurrencyType::AP_BRIDGED, IfaceConcurrencyType::NAN,
+ IfaceConcurrencyType::P2P, IfaceConcurrencyType::STA}) {
+ if (req_combo.count(type) == 0) {
+ // Concurrency type not in the req_combo.
+ continue;
+ }
+ size_t num_ifaces_needed = req_combo.at(type);
+ size_t num_ifaces_allowed = expanded_combo.at(type);
+ if (num_ifaces_needed > num_ifaces_allowed) {
+ return false;
+ }
+ }
+ return true;
+}
+// This method does the following:
+// a) Enumerate all possible concurrency combos by expanding the current
+// ChipConcurrencyCombination.
+// b) Check if the requested concurrency combo can be added to the current mode.
+// Note: This does not consider concurrency types already active. It only checks if the
+// current mode can support the requested combo.
+bool WifiChip::canCurrentModeSupportConcurrencyCombo(
+ const std::map<IfaceConcurrencyType, size_t>& req_combo) {
+ if (!isValidModeId(current_mode_id_)) {
+ LOG(ERROR) << "Chip not configured in a mode yet";
+ return false;
+ }
+ const auto combinations = getCurrentModeConcurrencyCombinations();
+ for (const auto& combination : combinations) {
+ const auto expanded_combos = expandConcurrencyCombinations(combination);
+ for (const auto& expanded_combo : expanded_combos) {
+ if (canExpandedConcurrencyComboSupportConcurrencyCombo(expanded_combo, req_combo)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+// This method does the following:
+// a) Enumerate all possible concurrency combos by expanding the current
+// ChipConcurrencyCombination.
+// b) Check if the requested concurrency type can be added to the current mode.
+bool WifiChip::canCurrentModeSupportConcurrencyType(IfaceConcurrencyType requested_type) {
+ // Check if we can support at least 1 of the requested concurrency type.
+ std::map<IfaceConcurrencyType, size_t> req_iface_combo;
+ req_iface_combo[requested_type] = 1;
+ return canCurrentModeSupportConcurrencyCombo(req_iface_combo);
+}
+
+bool WifiChip::isValidModeId(ChipModeId mode_id) {
+ for (const auto& mode : modes_) {
+ if (mode.id == mode_id) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool WifiChip::isStaApConcurrencyAllowedInCurrentMode() {
+ // Check if we can support at least 1 STA & 1 AP concurrently.
+ std::map<IfaceConcurrencyType, size_t> req_iface_combo;
+ req_iface_combo[IfaceConcurrencyType::STA] = 1;
+ req_iface_combo[IfaceConcurrencyType::AP] = 1;
+ return canCurrentModeSupportConcurrencyCombo(req_iface_combo);
+}
+
+bool WifiChip::isDualStaConcurrencyAllowedInCurrentMode() {
+ // Check if we can support at least 2 STA concurrently.
+ std::map<IfaceConcurrencyType, size_t> req_iface_combo;
+ req_iface_combo[IfaceConcurrencyType::STA] = 2;
+ return canCurrentModeSupportConcurrencyCombo(req_iface_combo);
+}
+
+std::string WifiChip::getFirstActiveWlanIfaceName() {
+ if (sta_ifaces_.size() > 0) return sta_ifaces_[0]->getName();
+ if (ap_ifaces_.size() > 0) {
+ // If the first active wlan iface is bridged iface.
+ // Return first instance name.
+ for (auto const& it : br_ifaces_ap_instances_) {
+ if (it.first == ap_ifaces_[0]->getName()) {
+ return it.second[0];
+ }
+ }
+ return ap_ifaces_[0]->getName();
+ }
+ // This could happen if the chip call is made before any STA/AP
+ // iface is created. Default to wlan0 for such cases.
+ LOG(WARNING) << "No active wlan interfaces in use! Using default";
+ return getWlanIfaceNameWithType(IfaceType::STA, 0);
+}
+
+// Return the first wlan (wlan0, wlan1 etc.) starting from |start_idx|
+// not already in use.
+// Note: This doesn't check the actual presence of these interfaces.
+std::string WifiChip::allocateApOrStaIfaceName(IfaceType type, uint32_t start_idx) {
+ for (unsigned idx = start_idx; idx < kMaxWlanIfaces; idx++) {
+ const auto ifname = getWlanIfaceNameWithType(type, idx);
+ if (findUsingNameFromBridgedApInstances(ifname)) continue;
+ if (findUsingName(ap_ifaces_, ifname)) continue;
+ if (findUsingName(sta_ifaces_, ifname)) continue;
+ return ifname;
+ }
+ // This should never happen. We screwed up somewhere if it did.
+ CHECK(false) << "All wlan interfaces in use already!";
+ return {};
+}
+
+uint32_t WifiChip::startIdxOfApIface() {
+ if (isDualStaConcurrencyAllowedInCurrentMode()) {
+ // When the HAL support dual STAs, AP should start with idx 2.
+ return 2;
+ } else if (isStaApConcurrencyAllowedInCurrentMode()) {
+ // When the HAL support STA + AP but it doesn't support dual STAs.
+ // AP should start with idx 1.
+ return 1;
+ }
+ // No concurrency support.
+ return 0;
+}
+
+// AP iface names start with idx 1 for modes supporting
+// concurrent STA and not dual AP, else start with idx 0.
+std::string WifiChip::allocateApIfaceName() {
+ // Check if we have a dedicated iface for AP.
+ std::vector<std::string> ifnames = getPredefinedApIfaceNames(true);
+ for (auto const& ifname : ifnames) {
+ if (findUsingName(ap_ifaces_, ifname)) continue;
+ return ifname;
+ }
+ return allocateApOrStaIfaceName(IfaceType::AP, startIdxOfApIface());
+}
+
+std::vector<std::string> WifiChip::allocateBridgedApInstanceNames() {
+ // Check if we have a dedicated iface for AP.
+ std::vector<std::string> instances = getPredefinedApIfaceNames(true);
+ if (instances.size() == 2) {
+ return instances;
+ } else {
+ int num_ifaces_need_to_allocate = 2 - instances.size();
+ for (int i = 0; i < num_ifaces_need_to_allocate; i++) {
+ std::string instance_name =
+ allocateApOrStaIfaceName(IfaceType::AP, startIdxOfApIface() + i);
+ if (!instance_name.empty()) {
+ instances.push_back(instance_name);
+ }
+ }
+ }
+ return instances;
+}
+
+// STA iface names start with idx 0.
+// Primary STA iface will always be 0.
+std::string WifiChip::allocateStaIfaceName() {
+ return allocateApOrStaIfaceName(IfaceType::STA, 0);
+}
+
+bool WifiChip::writeRingbufferFilesInternal() {
+ if (!removeOldFilesInternal()) {
+ LOG(ERROR) << "Error occurred while deleting old tombstone files";
+ return false;
+ }
+ // write ringbuffers to file
+ {
+ std::unique_lock<std::mutex> lk(lock_t);
+ for (auto& item : ringbuffer_map_) {
+ Ringbuffer& cur_buffer = item.second;
+ if (cur_buffer.getData().empty()) {
+ continue;
+ }
+ const std::string file_path_raw = kTombstoneFolderPath + item.first + "XXXXXXXXXX";
+ const int dump_fd = mkstemp(makeCharVec(file_path_raw).data());
+ if (dump_fd == -1) {
+ PLOG(ERROR) << "create file failed";
+ return false;
+ }
+ unique_fd file_auto_closer(dump_fd);
+ for (const auto& cur_block : cur_buffer.getData()) {
+ if (cur_block.size() <= 0 || cur_block.size() > kMaxBufferSizeBytes) {
+ PLOG(ERROR) << "Ring buffer: " << item.first
+ << " is corrupted. Invalid block size: " << cur_block.size();
+ break;
+ }
+ if (write(dump_fd, cur_block.data(), sizeof(cur_block[0]) * cur_block.size()) ==
+ -1) {
+ PLOG(ERROR) << "Error writing to file";
+ }
+ }
+ cur_buffer.clear();
+ }
+ // unique_lock unlocked here
+ }
+ return true;
+}
+
+std::string WifiChip::getWlanIfaceNameWithType(IfaceType type, unsigned idx) {
+ std::string ifname;
+
+ // let the legacy hal override the interface name
+ legacy_hal::wifi_error err = legacy_hal_.lock()->getSupportedIfaceName((uint32_t)type, ifname);
+ if (err == legacy_hal::WIFI_SUCCESS) return ifname;
+
+ return getWlanIfaceName(idx);
+}
+
+void WifiChip::invalidateAndClearBridgedApAll() {
+ for (auto const& it : br_ifaces_ap_instances_) {
+ for (auto const& iface : it.second) {
+ iface_util_->removeIfaceFromBridge(it.first, iface);
+ legacy_hal_.lock()->deleteVirtualInterface(iface);
+ }
+ iface_util_->deleteBridge(it.first);
+ }
+ br_ifaces_ap_instances_.clear();
+}
+
+void WifiChip::deleteApIface(const std::string& if_name) {
+ if (if_name.empty()) return;
+ // delete bridged interfaces if have
+ for (auto const& it : br_ifaces_ap_instances_) {
+ if (it.first == if_name) {
+ for (auto const& iface : it.second) {
+ iface_util_->removeIfaceFromBridge(if_name, iface);
+ legacy_hal_.lock()->deleteVirtualInterface(iface);
+ }
+ iface_util_->deleteBridge(if_name);
+ br_ifaces_ap_instances_.erase(if_name);
+ // ifname is bridged AP, return here.
+ return;
+ }
+ }
+
+ // No bridged AP case, delete AP iface
+ legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->deleteVirtualInterface(if_name);
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ LOG(ERROR) << "Failed to remove interface: " << if_name << " "
+ << legacyErrorToString(legacy_status);
+ }
+}
+
+bool WifiChip::findUsingNameFromBridgedApInstances(const std::string& name) {
+ for (auto const& it : br_ifaces_ap_instances_) {
+ if (it.first == name) {
+ return true;
+ }
+ for (auto const& iface : it.second) {
+ if (iface == name) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.6/default/wifi_chip.h b/wifi/1.6/default/wifi_chip.h
new file mode 100644
index 0000000..e8ddaa6
--- /dev/null
+++ b/wifi/1.6/default/wifi_chip.h
@@ -0,0 +1,317 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_CHIP_H_
+#define WIFI_CHIP_H_
+
+// HACK: NAN is a macro defined in math.h, which can be included in various
+// headers. This wifi HAL uses an enum called NAN, which does not compile when
+// the macro is defined. Undefine NAN to work around it.
+#undef NAN
+
+#include <list>
+#include <map>
+#include <mutex>
+
+#include <android-base/macros.h>
+#include <android/hardware/wifi/1.6/IWifiChip.h>
+#include <android/hardware/wifi/1.6/IWifiRttController.h>
+#include <android/hardware/wifi/1.6/IWifiStaIface.h>
+
+#include "hidl_callback_util.h"
+#include "ringbuffer.h"
+#include "wifi_ap_iface.h"
+#include "wifi_feature_flags.h"
+#include "wifi_legacy_hal.h"
+#include "wifi_mode_controller.h"
+#include "wifi_nan_iface.h"
+#include "wifi_p2p_iface.h"
+#include "wifi_rtt_controller.h"
+#include "wifi_sta_iface.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+using namespace android::hardware::wifi::V1_0;
+using V1_5::WifiBand;
+
+/**
+ * HIDL interface object used to control a Wifi HAL chip instance.
+ * Since there is only a single chip instance used today, there is no
+ * identifying handle information stored here.
+ */
+class WifiChip : public V1_6::IWifiChip {
+ public:
+ WifiChip(ChipId chip_id, bool is_primary,
+ const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+ const std::weak_ptr<mode_controller::WifiModeController> mode_controller,
+ const std::shared_ptr<iface_util::WifiIfaceUtil> iface_util,
+ const std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags,
+ const std::function<void(const std::string&)>& subsystemCallbackHandler);
+ // HIDL does not provide a built-in mechanism to let the server invalidate
+ // a HIDL interface object after creation. If any client process holds onto
+ // a reference to the object in their context, any method calls on that
+ // reference will continue to be directed to the server.
+ //
+ // However Wifi HAL needs to control the lifetime of these objects. So, add
+ // a public |invalidate| method to |WifiChip| and it's child objects. This
+ // will be used to mark an object invalid when either:
+ // a) Wifi HAL is stopped, or
+ // b) Wifi Chip is reconfigured.
+ //
+ // All HIDL method implementations should check if the object is still
+ // marked valid before processing them.
+ void invalidate();
+ bool isValid();
+ std::set<sp<V1_4::IWifiChipEventCallback>> getEventCallbacks();
+
+ // HIDL methods exposed.
+ Return<void> getId(getId_cb hidl_status_cb) override;
+ // Deprecated support for this callback
+ Return<void> registerEventCallback(const sp<V1_0::IWifiChipEventCallback>& event_callback,
+ registerEventCallback_cb hidl_status_cb) override;
+ Return<void> getCapabilities(getCapabilities_cb hidl_status_cb) override;
+ Return<void> getAvailableModes(getAvailableModes_cb hidl_status_cb) override;
+ Return<void> configureChip(ChipModeId mode_id, configureChip_cb hidl_status_cb) override;
+ Return<void> getMode(getMode_cb hidl_status_cb) override;
+ Return<void> requestChipDebugInfo(requestChipDebugInfo_cb hidl_status_cb) override;
+ Return<void> requestDriverDebugDump(requestDriverDebugDump_cb hidl_status_cb) override;
+ Return<void> requestFirmwareDebugDump(requestFirmwareDebugDump_cb hidl_status_cb) override;
+ Return<void> createApIface(createApIface_cb hidl_status_cb) override;
+ Return<void> createBridgedApIface(createBridgedApIface_cb hidl_status_cb) override;
+ Return<void> getApIfaceNames(getApIfaceNames_cb hidl_status_cb) override;
+ Return<void> getApIface(const hidl_string& ifname, getApIface_cb hidl_status_cb) override;
+ Return<void> removeApIface(const hidl_string& ifname, removeApIface_cb hidl_status_cb) override;
+ Return<void> removeIfaceInstanceFromBridgedApIface(
+ const hidl_string& brIfaceName, const hidl_string& ifaceInstanceName,
+ removeIfaceInstanceFromBridgedApIface_cb hidl_status_cb) override;
+ Return<void> createNanIface(createNanIface_cb hidl_status_cb) override;
+ Return<void> getNanIfaceNames(getNanIfaceNames_cb hidl_status_cb) override;
+ Return<void> getNanIface(const hidl_string& ifname, getNanIface_cb hidl_status_cb) override;
+ Return<void> removeNanIface(const hidl_string& ifname,
+ removeNanIface_cb hidl_status_cb) override;
+ Return<void> createP2pIface(createP2pIface_cb hidl_status_cb) override;
+ Return<void> getP2pIfaceNames(getP2pIfaceNames_cb hidl_status_cb) override;
+ Return<void> getP2pIface(const hidl_string& ifname, getP2pIface_cb hidl_status_cb) override;
+ Return<void> removeP2pIface(const hidl_string& ifname,
+ removeP2pIface_cb hidl_status_cb) override;
+ Return<void> createStaIface(createStaIface_cb hidl_status_cb) override;
+ Return<void> getStaIfaceNames(getStaIfaceNames_cb hidl_status_cb) override;
+ Return<void> getStaIface(const hidl_string& ifname, getStaIface_cb hidl_status_cb) override;
+ Return<void> removeStaIface(const hidl_string& ifname,
+ removeStaIface_cb hidl_status_cb) override;
+ Return<void> createRttController(const sp<IWifiIface>& bound_iface,
+ createRttController_cb hidl_status_cb) override;
+ Return<void> getDebugRingBuffersStatus(getDebugRingBuffersStatus_cb hidl_status_cb) override;
+ Return<void> startLoggingToDebugRingBuffer(
+ const hidl_string& ring_name, WifiDebugRingBufferVerboseLevel verbose_level,
+ uint32_t max_interval_in_sec, uint32_t min_data_size_in_bytes,
+ startLoggingToDebugRingBuffer_cb hidl_status_cb) override;
+ Return<void> forceDumpToDebugRingBuffer(const hidl_string& ring_name,
+ forceDumpToDebugRingBuffer_cb hidl_status_cb) override;
+ Return<void> flushRingBufferToFile(flushRingBufferToFile_cb hidl_status_cb) override;
+ Return<void> stopLoggingToDebugRingBuffer(
+ stopLoggingToDebugRingBuffer_cb hidl_status_cb) override;
+ Return<void> getDebugHostWakeReasonStats(
+ getDebugHostWakeReasonStats_cb hidl_status_cb) override;
+ Return<void> enableDebugErrorAlerts(bool enable,
+ enableDebugErrorAlerts_cb hidl_status_cb) override;
+ Return<void> selectTxPowerScenario(V1_1::IWifiChip::TxPowerScenario scenario,
+ selectTxPowerScenario_cb hidl_status_cb) override;
+ Return<void> resetTxPowerScenario(resetTxPowerScenario_cb hidl_status_cb) override;
+ Return<void> setLatencyMode(LatencyMode mode, setLatencyMode_cb hidl_status_cb) override;
+ Return<void> registerEventCallback_1_2(const sp<V1_2::IWifiChipEventCallback>& event_callback,
+ registerEventCallback_1_2_cb hidl_status_cb) override;
+ Return<void> selectTxPowerScenario_1_2(TxPowerScenario scenario,
+ selectTxPowerScenario_cb hidl_status_cb) override;
+ Return<void> getCapabilities_1_3(getCapabilities_cb hidl_status_cb) override;
+ Return<void> getCapabilities_1_5(getCapabilities_1_5_cb hidl_status_cb) override;
+ Return<void> debug(const hidl_handle& handle, const hidl_vec<hidl_string>& options) override;
+ Return<void> createRttController_1_4(const sp<IWifiIface>& bound_iface,
+ createRttController_1_4_cb hidl_status_cb) override;
+ Return<void> registerEventCallback_1_4(const sp<V1_4::IWifiChipEventCallback>& event_callback,
+ registerEventCallback_1_4_cb hidl_status_cb) override;
+ Return<void> setMultiStaPrimaryConnection(
+ const hidl_string& ifname, setMultiStaPrimaryConnection_cb hidl_status_cb) override;
+ Return<void> setMultiStaUseCase(MultiStaUseCase use_case,
+ setMultiStaUseCase_cb hidl_status_cb) override;
+ Return<void> setCoexUnsafeChannels(const hidl_vec<CoexUnsafeChannel>& unsafe_channels,
+ hidl_bitfield<IfaceType> restrictions,
+ setCoexUnsafeChannels_cb hidl_status_cb) override;
+ Return<void> setCountryCode(const hidl_array<int8_t, 2>& code,
+ setCountryCode_cb _hidl_cb) override;
+ Return<void> getUsableChannels(WifiBand band, hidl_bitfield<V1_5::WifiIfaceMode> ifaceModeMask,
+ hidl_bitfield<V1_5::IWifiChip::UsableChannelFilter> filterMask,
+ getUsableChannels_cb _hidl_cb) override;
+ Return<void> triggerSubsystemRestart(triggerSubsystemRestart_cb hidl_status_cb) override;
+ Return<void> createRttController_1_6(const sp<IWifiIface>& bound_iface,
+ createRttController_1_6_cb hidl_status_cb) override;
+ Return<void> getUsableChannels_1_6(WifiBand band,
+ hidl_bitfield<V1_5::WifiIfaceMode> ifaceModeMask,
+ hidl_bitfield<UsableChannelFilter> filterMask,
+ getUsableChannels_1_6_cb _hidl_cb) override;
+ Return<void> getSupportedRadioCombinationsMatrix(
+ getSupportedRadioCombinationsMatrix_cb hidl_status_cb) override;
+ Return<void> getAvailableModes_1_6(getAvailableModes_1_6_cb hidl_status_cb) override;
+
+ private:
+ void invalidateAndRemoveAllIfaces();
+ // When a STA iface is removed any dependent NAN-ifaces/RTT-controllers are
+ // invalidated & removed.
+ void invalidateAndRemoveDependencies(const std::string& removed_iface_name);
+
+ // Corresponding worker functions for the HIDL methods.
+ std::pair<WifiStatus, ChipId> getIdInternal();
+ // Deprecated support for this callback
+ WifiStatus registerEventCallbackInternal(
+ const sp<V1_0::IWifiChipEventCallback>& event_callback);
+ std::pair<WifiStatus, uint32_t> getCapabilitiesInternal();
+ std::pair<WifiStatus, std::vector<V1_0::IWifiChip::ChipMode>> getAvailableModesInternal();
+ WifiStatus configureChipInternal(std::unique_lock<std::recursive_mutex>* lock,
+ ChipModeId mode_id);
+ std::pair<WifiStatus, uint32_t> getModeInternal();
+ std::pair<WifiStatus, IWifiChip::ChipDebugInfo> requestChipDebugInfoInternal();
+ std::pair<WifiStatus, std::vector<uint8_t>> requestDriverDebugDumpInternal();
+ std::pair<WifiStatus, std::vector<uint8_t>> requestFirmwareDebugDumpInternal();
+ sp<WifiApIface> newWifiApIface(std::string& ifname);
+ WifiStatus createVirtualApInterface(const std::string& apVirtIf);
+ std::pair<WifiStatus, sp<V1_5::IWifiApIface>> createApIfaceInternal();
+ std::pair<WifiStatus, sp<V1_5::IWifiApIface>> createBridgedApIfaceInternal();
+ std::pair<WifiStatus, std::vector<hidl_string>> getApIfaceNamesInternal();
+ std::pair<WifiStatus, sp<V1_5::IWifiApIface>> getApIfaceInternal(const std::string& ifname);
+ WifiStatus removeApIfaceInternal(const std::string& ifname);
+ WifiStatus removeIfaceInstanceFromBridgedApIfaceInternal(const std::string& brIfaceName,
+ const std::string& ifInstanceName);
+ std::pair<WifiStatus, sp<V1_4::IWifiNanIface>> createNanIfaceInternal();
+ std::pair<WifiStatus, std::vector<hidl_string>> getNanIfaceNamesInternal();
+ std::pair<WifiStatus, sp<V1_4::IWifiNanIface>> getNanIfaceInternal(const std::string& ifname);
+ WifiStatus removeNanIfaceInternal(const std::string& ifname);
+ std::pair<WifiStatus, sp<IWifiP2pIface>> createP2pIfaceInternal();
+ std::pair<WifiStatus, std::vector<hidl_string>> getP2pIfaceNamesInternal();
+ std::pair<WifiStatus, sp<IWifiP2pIface>> getP2pIfaceInternal(const std::string& ifname);
+ WifiStatus removeP2pIfaceInternal(const std::string& ifname);
+ std::pair<WifiStatus, sp<V1_6::IWifiStaIface>> createStaIfaceInternal();
+ std::pair<WifiStatus, std::vector<hidl_string>> getStaIfaceNamesInternal();
+ std::pair<WifiStatus, sp<V1_6::IWifiStaIface>> getStaIfaceInternal(const std::string& ifname);
+ WifiStatus removeStaIfaceInternal(const std::string& ifname);
+ std::pair<WifiStatus, sp<V1_0::IWifiRttController>> createRttControllerInternal(
+ const sp<IWifiIface>& bound_iface);
+ std::pair<WifiStatus, std::vector<WifiDebugRingBufferStatus>>
+ getDebugRingBuffersStatusInternal();
+ WifiStatus startLoggingToDebugRingBufferInternal(const hidl_string& ring_name,
+ WifiDebugRingBufferVerboseLevel verbose_level,
+ uint32_t max_interval_in_sec,
+ uint32_t min_data_size_in_bytes);
+ WifiStatus forceDumpToDebugRingBufferInternal(const hidl_string& ring_name);
+ WifiStatus flushRingBufferToFileInternal();
+ WifiStatus stopLoggingToDebugRingBufferInternal();
+ std::pair<WifiStatus, WifiDebugHostWakeReasonStats> getDebugHostWakeReasonStatsInternal();
+ WifiStatus enableDebugErrorAlertsInternal(bool enable);
+ WifiStatus selectTxPowerScenarioInternal(V1_1::IWifiChip::TxPowerScenario scenario);
+ WifiStatus resetTxPowerScenarioInternal();
+ WifiStatus setLatencyModeInternal(LatencyMode mode);
+ WifiStatus registerEventCallbackInternal_1_2(
+ const sp<V1_2::IWifiChipEventCallback>& event_callback);
+ WifiStatus selectTxPowerScenarioInternal_1_2(TxPowerScenario scenario);
+ std::pair<WifiStatus, uint32_t> getCapabilitiesInternal_1_3();
+ std::pair<WifiStatus, uint32_t> getCapabilitiesInternal_1_5();
+ std::pair<WifiStatus, sp<V1_4::IWifiRttController>> createRttControllerInternal_1_4(
+ const sp<IWifiIface>& bound_iface);
+ WifiStatus registerEventCallbackInternal_1_4(
+ const sp<V1_4::IWifiChipEventCallback>& event_callback);
+ WifiStatus setMultiStaPrimaryConnectionInternal(const std::string& ifname);
+ WifiStatus setMultiStaUseCaseInternal(MultiStaUseCase use_case);
+ WifiStatus setCoexUnsafeChannelsInternal(std::vector<CoexUnsafeChannel> unsafe_channels,
+ uint32_t restrictions);
+ WifiStatus setCountryCodeInternal(const std::array<int8_t, 2>& code);
+ std::pair<WifiStatus, std::vector<V1_5::WifiUsableChannel>> getUsableChannelsInternal(
+ WifiBand band, uint32_t ifaceModeMask, uint32_t filterMask);
+ WifiStatus handleChipConfiguration(std::unique_lock<std::recursive_mutex>* lock,
+ ChipModeId mode_id);
+ WifiStatus registerDebugRingBufferCallback();
+ WifiStatus registerRadioModeChangeCallback();
+ std::vector<V1_6::IWifiChip::ChipConcurrencyCombination>
+ getCurrentModeConcurrencyCombinations();
+ std::map<IfaceConcurrencyType, size_t> getCurrentConcurrencyCombination();
+ std::vector<std::map<IfaceConcurrencyType, size_t>> expandConcurrencyCombinations(
+ const V1_6::IWifiChip::ChipConcurrencyCombination& combination);
+ bool canExpandedConcurrencyComboSupportConcurrencyTypeWithCurrentTypes(
+ const std::map<IfaceConcurrencyType, size_t>& expanded_combo,
+ IfaceConcurrencyType requested_type);
+ bool canCurrentModeSupportConcurrencyTypeWithCurrentTypes(IfaceConcurrencyType requested_type);
+ bool canExpandedConcurrencyComboSupportConcurrencyCombo(
+ const std::map<IfaceConcurrencyType, size_t>& expanded_combo,
+ const std::map<IfaceConcurrencyType, size_t>& req_combo);
+ bool canCurrentModeSupportConcurrencyCombo(
+ const std::map<IfaceConcurrencyType, size_t>& req_combo);
+ bool canCurrentModeSupportConcurrencyType(IfaceConcurrencyType requested_type);
+ bool isValidModeId(ChipModeId mode_id);
+ bool isStaApConcurrencyAllowedInCurrentMode();
+ bool isDualStaConcurrencyAllowedInCurrentMode();
+ uint32_t startIdxOfApIface();
+ std::string getFirstActiveWlanIfaceName();
+ std::string allocateApOrStaIfaceName(IfaceType type, uint32_t start_idx);
+ std::string allocateApIfaceName();
+ std::vector<std::string> allocateBridgedApInstanceNames();
+ std::string allocateStaIfaceName();
+ bool writeRingbufferFilesInternal();
+ std::string getWlanIfaceNameWithType(IfaceType type, unsigned idx);
+ void invalidateAndClearBridgedApAll();
+ void deleteApIface(const std::string& if_name);
+ bool findUsingNameFromBridgedApInstances(const std::string& name);
+ WifiStatus triggerSubsystemRestartInternal();
+ std::pair<WifiStatus, sp<V1_6::IWifiRttController>> createRttControllerInternal_1_6(
+ const sp<IWifiIface>& bound_iface);
+ std::pair<WifiStatus, std::vector<V1_6::WifiUsableChannel>> getUsableChannelsInternal_1_6(
+ WifiBand band, uint32_t ifaceModeMask, uint32_t filterMask);
+ std::pair<WifiStatus, WifiRadioCombinationMatrix> getSupportedRadioCombinationsMatrixInternal();
+ std::pair<WifiStatus, std::vector<V1_6::IWifiChip::ChipMode>> getAvailableModesInternal_1_6();
+
+ ChipId chip_id_;
+ std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+ std::weak_ptr<mode_controller::WifiModeController> mode_controller_;
+ std::shared_ptr<iface_util::WifiIfaceUtil> iface_util_;
+ std::vector<sp<WifiApIface>> ap_ifaces_;
+ std::vector<sp<WifiNanIface>> nan_ifaces_;
+ std::vector<sp<WifiP2pIface>> p2p_ifaces_;
+ std::vector<sp<WifiStaIface>> sta_ifaces_;
+ std::vector<sp<WifiRttController>> rtt_controllers_;
+ std::map<std::string, Ringbuffer> ringbuffer_map_;
+ bool is_valid_;
+ // Members pertaining to chip configuration.
+ uint32_t current_mode_id_;
+ std::mutex lock_t;
+ std::vector<V1_6::IWifiChip::ChipMode> modes_;
+ // The legacy ring buffer callback API has only a global callback
+ // registration mechanism. Use this to check if we have already
+ // registered a callback.
+ bool debug_ring_buffer_cb_registered_;
+ hidl_callback_util::HidlCallbackHandler<V1_4::IWifiChipEventCallback> event_cb_handler_;
+
+ const std::function<void(const std::string&)> subsystemCallbackHandler_;
+ std::map<std::string, std::vector<std::string>> br_ifaces_ap_instances_;
+ DISALLOW_COPY_AND_ASSIGN(WifiChip);
+};
+
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+
+#endif // WIFI_CHIP_H_
diff --git a/wifi/1.6/default/wifi_feature_flags.cpp b/wifi/1.6/default/wifi_feature_flags.cpp
new file mode 100644
index 0000000..e80a3cd
--- /dev/null
+++ b/wifi/1.6/default/wifi_feature_flags.cpp
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string>
+
+#include <android-base/logging.h>
+#include <cutils/properties.h>
+
+#include "wifi_feature_flags.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace feature_flags {
+
+using V1_0::ChipModeId;
+using V1_0::IWifiChip;
+using V1_6::IfaceConcurrencyType;
+
+/* The chip may either have a single mode supporting any number of combinations,
+ * or a fixed dual-mode (so it involves firmware loading to switch between
+ * modes) setting. If there is a need to support more modes, it needs to be
+ * implemented manually in WiFi HAL (see changeFirmwareMode in
+ * WifiChip::handleChipConfiguration).
+ *
+ * Supported combinations are defined in device's makefile, for example:
+ * WIFI_HAL_INTERFACE_COMBINATIONS := {{{STA, AP}, 1}, {{P2P, NAN}, 1}},
+ * WIFI_HAL_INTERFACE_COMBINATIONS += {{{STA}, 1}, {{AP}, 2}}
+ * What means:
+ * Interface concurrency combination 1: 1 STA or AP and 1 P2P or NAN concurrent iface
+ * operations.
+ * Interface concurrency combination 2: 1 STA and 2 AP concurrent iface operations.
+ *
+ * For backward compatibility, the following makefile flags can be used to
+ * generate combinations list:
+ * - WIFI_HIDL_FEATURE_DUAL_INTERFACE
+ * - WIFI_HIDL_FEATURE_DISABLE_AP
+ * - WIFI_HIDL_FEATURE_AWARE
+ * However, they are ignored if WIFI_HAL_INTERFACE_COMBINATIONS was provided.
+ * With WIFI_HIDL_FEATURE_DUAL_INTERFACE flag set, there is a single mode with
+ * two concurrency combinations:
+ * Interface Concurrency Combination 1: Will support 1 STA and 1 P2P or NAN (optional)
+ * concurrent iface operations.
+ * Interface Concurrency Combination 2: Will support 1 STA and 1 AP concurrent
+ * iface operations.
+ *
+ * The only dual-mode configuration supported is for alternating STA and AP
+ * mode, that may involve firmware reloading. In such case, there are 2 separate
+ * modes of operation with 1 concurrency combination each:
+ * Mode 1 (STA mode): Will support 1 STA and 1 P2P or NAN (optional)
+ * concurrent iface operations.
+ * Mode 2 (AP mode): Will support 1 AP iface operation.
+ *
+ * If Aware is enabled, the concurrency combination will be modified to support either
+ * P2P or NAN in place of just P2P.
+ */
+// clang-format off
+#ifdef WIFI_HAL_INTERFACE_COMBINATIONS
+constexpr ChipModeId kMainModeId = chip_mode_ids::kV3;
+#elif defined(WIFI_HIDL_FEATURE_DUAL_INTERFACE)
+// former V2 (fixed dual interface) setup expressed as V3
+constexpr ChipModeId kMainModeId = chip_mode_ids::kV3;
+# ifdef WIFI_HIDL_FEATURE_DISABLE_AP
+# ifdef WIFI_HIDL_FEATURE_AWARE
+// 1 STA + 1 of (P2P or NAN)
+# define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{P2P, NAN}, 1}}
+# else
+// 1 STA + 1 P2P
+# define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{P2P}, 1}}
+# endif
+# else
+# ifdef WIFI_HIDL_FEATURE_AWARE
+// (1 STA + 1 AP) or (1 STA + 1 of (P2P or NAN))
+# define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{AP}, 1}},\
+ {{{STA}, 1}, {{P2P, NAN}, 1}}
+# else
+// (1 STA + 1 AP) or (1 STA + 1 P2P)
+# define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{AP}, 1}},\
+ {{{STA}, 1}, {{P2P}, 1}}
+# endif
+# endif
+#else
+// V1 (fixed single interface, dual-mode chip)
+constexpr ChipModeId kMainModeId = chip_mode_ids::kV1Sta;
+# ifdef WIFI_HIDL_FEATURE_AWARE
+// 1 STA + 1 of (P2P or NAN)
+# define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{P2P, NAN}, 1}}
+# else
+// 1 STA + 1 P2P
+# define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{P2P}, 1}}
+# endif
+
+# ifndef WIFI_HIDL_FEATURE_DISABLE_AP
+# define WIFI_HAL_INTERFACE_COMBINATIONS_AP {{{AP}, 1}}
+# endif
+#endif
+// clang-format on
+
+/**
+ * Helper class to convert a collection of combination limits to a combination.
+ *
+ * The main point here is to simplify the syntax required by
+ * WIFI_HAL_INTERFACE_COMBINATIONS.
+ */
+struct ChipConcurrencyCombination
+ : public hidl_vec<V1_6::IWifiChip::ChipConcurrencyCombinationLimit> {
+ ChipConcurrencyCombination(
+ const std::initializer_list<V1_6::IWifiChip::ChipConcurrencyCombinationLimit> list)
+ : hidl_vec(list) {}
+
+ operator V1_6::IWifiChip::ChipConcurrencyCombination() const { return {*this}; }
+
+ static hidl_vec<V1_6::IWifiChip::ChipConcurrencyCombination> make_vec(
+ const std::initializer_list<ChipConcurrencyCombination> list) {
+ return hidl_vec<V1_6::IWifiChip::ChipConcurrencyCombination>( //
+ std::begin(list), std::end(list));
+ }
+};
+
+#define STA IfaceConcurrencyType::STA
+#define AP IfaceConcurrencyType::AP
+#define AP_BRIDGED IfaceConcurrencyType::AP_BRIDGED
+#define P2P IfaceConcurrencyType::P2P
+#define NAN IfaceConcurrencyType::NAN
+static const std::vector<V1_6::IWifiChip::ChipMode> kChipModesPrimary{
+ {kMainModeId, ChipConcurrencyCombination::make_vec({WIFI_HAL_INTERFACE_COMBINATIONS})},
+#ifdef WIFI_HAL_INTERFACE_COMBINATIONS_AP
+ {chip_mode_ids::kV1Ap,
+ ChipConcurrencyCombination::make_vec({WIFI_HAL_INTERFACE_COMBINATIONS_AP})},
+#endif
+};
+
+static const std::vector<V1_6::IWifiChip::ChipMode> kChipModesSecondary{
+#ifdef WIFI_HAL_INTERFACE_COMBINATIONS_SECONDARY_CHIP
+ {chip_mode_ids::kV3,
+ ChipConcurrencyCombination::make_vec({WIFI_HAL_INTERFACE_COMBINATIONS_SECONDARY_CHIP})},
+#endif
+};
+
+constexpr char kDebugPresetInterfaceCombinationIdxProperty[] =
+ "persist.vendor.debug.wifi.hal.preset_interface_combination_idx";
+// List of pre-defined concurrency combinations that can be enabled at runtime via
+// setting the property: "kDebugPresetInterfaceCombinationIdxProperty" to the
+// corresponding index value.
+static const std::vector<std::pair<std::string, std::vector<V1_6::IWifiChip::ChipMode>>>
+ kDebugChipModes{// Legacy combination - No STA/AP concurrencies.
+ // 0 - (1 AP) or (1 STA + 1 of (P2P or NAN))
+ {"No STA/AP Concurrency",
+ {{kMainModeId, ChipConcurrencyCombination::make_vec(
+ {{{{AP}, 1}}, {{{STA}, 1}, {{P2P, NAN}, 1}}})}}},
+
+ // STA + AP concurrency
+ // 1 - (1 STA + 1 AP) or (1 STA + 1 of (P2P or NAN))
+ {"STA + AP Concurrency",
+ {{kMainModeId,
+ ChipConcurrencyCombination::make_vec(
+ {{{{STA}, 1}, {{AP}, 1}}, {{{STA}, 1}, {{P2P, NAN}, 1}}})}}},
+
+ // STA + STA concurrency
+ // 2 - (1 STA + 1 AP) or (2 STA + 1 of (P2P or NAN))
+ {"Dual STA Concurrency",
+ {{kMainModeId,
+ ChipConcurrencyCombination::make_vec(
+ {{{{STA}, 1}, {{AP}, 1}}, {{{STA}, 2}, {{P2P, NAN}, 1}}})}}},
+
+ // AP + AP + STA concurrency
+ // 3 - (1 STA + 2 AP) or (1 STA + 1 of (P2P or NAN))
+ {"Dual AP Concurrency",
+ {{kMainModeId,
+ ChipConcurrencyCombination::make_vec(
+ {{{{STA}, 1}, {{AP}, 2}}, {{{STA}, 1}, {{P2P, NAN}, 1}}})}}},
+
+ // STA + STA concurrency and AP + AP + STA concurrency
+ // 4 - (1 STA + 2 AP) or (2 STA + 1 of (P2P or NAN))
+ {"Dual STA & Dual AP Concurrency",
+ {{kMainModeId,
+ ChipConcurrencyCombination::make_vec(
+ {{{{STA}, 1}, {{AP}, 2}}, {{{STA}, 2}, {{P2P, NAN}, 1}}})}}},
+
+ // STA + STA concurrency
+ // 5 - (1 STA + 1 AP (bridged or single) | P2P | NAN), or (2 STA))
+ {"Dual STA or STA plus single other interface",
+ {{kMainModeId, ChipConcurrencyCombination::make_vec(
+ {{{{STA}, 1}, {{P2P, NAN, AP, AP_BRIDGED}, 1}},
+ {{{STA}, 2}}})}}}};
+
+#undef STA
+#undef AP
+#undef P2P
+#undef NAN
+
+#ifdef WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION
+#pragma message \
+ "WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION is deprecated; override " \
+ "'config_wifi_ap_randomization_supported' in " \
+ "frameworks/base/core/res/res/values/config.xml in the device overlay " \
+ "instead"
+#endif // WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION
+
+WifiFeatureFlags::WifiFeatureFlags() {}
+
+std::vector<V1_6::IWifiChip::ChipMode> WifiFeatureFlags::getChipModesForPrimary() {
+ std::array<char, PROPERTY_VALUE_MAX> buffer;
+ auto res = property_get(kDebugPresetInterfaceCombinationIdxProperty, buffer.data(), nullptr);
+ // Debug property not set, use the device preset concurrency combination.
+ if (res <= 0) return kChipModesPrimary;
+
+ // Debug property set, use one of the debug preset concurrency combination.
+ unsigned long idx = std::stoul(buffer.data());
+ if (idx >= kDebugChipModes.size()) {
+ LOG(ERROR) << "Invalid index set in property: "
+ << kDebugPresetInterfaceCombinationIdxProperty;
+ return kChipModesPrimary;
+ }
+ std::string name;
+ std::vector<V1_6::IWifiChip::ChipMode> chip_modes;
+ std::tie(name, chip_modes) = kDebugChipModes[idx];
+ LOG(INFO) << "Using debug chip mode: <" << name
+ << "> set via property: " << kDebugPresetInterfaceCombinationIdxProperty;
+ return chip_modes;
+}
+
+std::vector<V1_6::IWifiChip::ChipMode> WifiFeatureFlags::getChipModes(bool is_primary) {
+ return (is_primary) ? getChipModesForPrimary() : kChipModesSecondary;
+}
+
+} // namespace feature_flags
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.6/default/wifi_feature_flags.h b/wifi/1.6/default/wifi_feature_flags.h
new file mode 100644
index 0000000..1635341
--- /dev/null
+++ b/wifi/1.6/default/wifi_feature_flags.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_FEATURE_FLAGS_H_
+#define WIFI_FEATURE_FLAGS_H_
+
+#include <android/hardware/wifi/1.6/IWifiChip.h>
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace feature_flags {
+
+namespace chip_mode_ids {
+// These mode ID's should be unique (even across combo versions). Refer to
+// handleChipConfiguration() for it's usage.
+constexpr V1_0::ChipModeId kInvalid = UINT32_MAX;
+// Mode ID's for V1
+constexpr V1_0::ChipModeId kV1Sta = 0;
+constexpr V1_0::ChipModeId kV1Ap = 1;
+// Mode ID for V3
+constexpr V1_0::ChipModeId kV3 = 3;
+} // namespace chip_mode_ids
+
+class WifiFeatureFlags {
+ public:
+ WifiFeatureFlags();
+ virtual ~WifiFeatureFlags() = default;
+
+ virtual std::vector<V1_6::IWifiChip::ChipMode> getChipModes(bool is_primary);
+
+ private:
+ std::vector<V1_6::IWifiChip::ChipMode> getChipModesForPrimary();
+};
+
+} // namespace feature_flags
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+
+#endif // WIFI_FEATURE_FLAGS_H_
diff --git a/wifi/1.6/default/wifi_iface_util.cpp b/wifi/1.6/default/wifi_iface_util.cpp
new file mode 100644
index 0000000..d55e4f8
--- /dev/null
+++ b/wifi/1.6/default/wifi_iface_util.cpp
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <net/if.h>
+#include <cstddef>
+#include <iostream>
+#include <limits>
+#include <random>
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <private/android_filesystem_config.h>
+
+#undef NAN
+#include "wifi_iface_util.h"
+
+namespace {
+// Constants to set the local bit & clear the multicast bit.
+constexpr uint8_t kMacAddressMulticastMask = 0x01;
+constexpr uint8_t kMacAddressLocallyAssignedMask = 0x02;
+} // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace iface_util {
+
+WifiIfaceUtil::WifiIfaceUtil(const std::weak_ptr<wifi_system::InterfaceTool> iface_tool,
+ const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal)
+ : iface_tool_(iface_tool),
+ legacy_hal_(legacy_hal),
+ random_mac_address_(nullptr),
+ event_handlers_map_() {}
+
+std::array<uint8_t, 6> WifiIfaceUtil::getFactoryMacAddress(const std::string& iface_name) {
+ return iface_tool_.lock()->GetFactoryMacAddress(iface_name.c_str());
+}
+
+bool WifiIfaceUtil::setMacAddress(const std::string& iface_name,
+ const std::array<uint8_t, 6>& mac) {
+#ifndef WIFI_AVOID_IFACE_RESET_MAC_CHANGE
+ legacy_hal::wifi_error legacy_status;
+ uint64_t legacy_feature_set;
+ std::tie(legacy_status, legacy_feature_set) =
+ legacy_hal_.lock()->getSupportedFeatureSet(iface_name);
+
+ if (!(legacy_feature_set & WIFI_FEATURE_DYNAMIC_SET_MAC) &&
+ !iface_tool_.lock()->SetUpState(iface_name.c_str(), false)) {
+ LOG(ERROR) << "SetUpState(false) failed.";
+ return false;
+ }
+#endif
+ bool success = iface_tool_.lock()->SetMacAddress(iface_name.c_str(), mac);
+#ifndef WIFI_AVOID_IFACE_RESET_MAC_CHANGE
+ if (!(legacy_feature_set & WIFI_FEATURE_DYNAMIC_SET_MAC) &&
+ !iface_tool_.lock()->SetUpState(iface_name.c_str(), true)) {
+ LOG(ERROR) << "SetUpState(true) failed. Wait for driver ready.";
+ // Wait for driver ready and try to set iface UP again
+ if (legacy_hal_.lock()->waitForDriverReady() != legacy_hal::WIFI_SUCCESS) {
+ LOG(ERROR) << "SetUpState(true) wait for driver ready failed.";
+ return false;
+ }
+ if (!iface_tool_.lock()->SetUpState(iface_name.c_str(), true)) {
+ LOG(ERROR) << "SetUpState(true) failed after retry.";
+ return false;
+ }
+ }
+#endif
+ IfaceEventHandlers event_handlers = {};
+ const auto it = event_handlers_map_.find(iface_name);
+ if (it != event_handlers_map_.end()) {
+ event_handlers = it->second;
+ }
+ if (event_handlers.on_state_toggle_off_on != nullptr) {
+ event_handlers.on_state_toggle_off_on(iface_name);
+ }
+ if (!success) {
+ LOG(ERROR) << "SetMacAddress failed on " << iface_name;
+ } else {
+ LOG(DEBUG) << "SetMacAddress succeeded on " << iface_name;
+ }
+ return success;
+}
+
+std::array<uint8_t, 6> WifiIfaceUtil::getOrCreateRandomMacAddress() {
+ if (random_mac_address_) {
+ return *random_mac_address_.get();
+ }
+ random_mac_address_ = std::make_unique<std::array<uint8_t, 6>>(createRandomMacAddress());
+ return *random_mac_address_.get();
+}
+
+void WifiIfaceUtil::registerIfaceEventHandlers(const std::string& iface_name,
+ IfaceEventHandlers handlers) {
+ event_handlers_map_[iface_name] = handlers;
+}
+
+void WifiIfaceUtil::unregisterIfaceEventHandlers(const std::string& iface_name) {
+ event_handlers_map_.erase(iface_name);
+}
+
+std::array<uint8_t, 6> WifiIfaceUtil::createRandomMacAddress() {
+ std::array<uint8_t, 6> address = {};
+ std::random_device rd;
+ std::default_random_engine engine(rd());
+ std::uniform_int_distribution<uint8_t> dist(std::numeric_limits<uint8_t>::min(),
+ std::numeric_limits<uint8_t>::max());
+ for (size_t i = 0; i < address.size(); i++) {
+ address[i] = dist(engine);
+ }
+ // Set the local bit and clear the multicast bit.
+ address[0] |= kMacAddressLocallyAssignedMask;
+ address[0] &= ~kMacAddressMulticastMask;
+ return address;
+}
+
+bool WifiIfaceUtil::setUpState(const std::string& iface_name, bool request_up) {
+ if (!iface_tool_.lock()->SetUpState(iface_name.c_str(), request_up)) {
+ LOG(ERROR) << "SetUpState to " << request_up << " failed";
+ return false;
+ }
+ return true;
+}
+
+unsigned WifiIfaceUtil::ifNameToIndex(const std::string& iface_name) {
+ return if_nametoindex(iface_name.c_str());
+}
+
+bool WifiIfaceUtil::createBridge(const std::string& br_name) {
+ if (!iface_tool_.lock()->createBridge(br_name)) {
+ return false;
+ }
+
+ if (!iface_tool_.lock()->SetUpState(br_name.c_str(), true)) {
+ LOG(ERROR) << "bridge SetUpState(true) failed.";
+ }
+ return true;
+}
+
+bool WifiIfaceUtil::deleteBridge(const std::string& br_name) {
+ if (!iface_tool_.lock()->SetUpState(br_name.c_str(), false)) {
+ LOG(INFO) << "SetUpState(false) failed for bridge=" << br_name.c_str();
+ }
+
+ return iface_tool_.lock()->deleteBridge(br_name);
+}
+
+bool WifiIfaceUtil::addIfaceToBridge(const std::string& br_name, const std::string& if_name) {
+ return iface_tool_.lock()->addIfaceToBridge(br_name, if_name);
+}
+
+bool WifiIfaceUtil::removeIfaceFromBridge(const std::string& br_name, const std::string& if_name) {
+ return iface_tool_.lock()->removeIfaceFromBridge(br_name, if_name);
+}
+
+} // namespace iface_util
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.6/default/wifi_iface_util.h b/wifi/1.6/default/wifi_iface_util.h
new file mode 100644
index 0000000..c5db5de
--- /dev/null
+++ b/wifi/1.6/default/wifi_iface_util.h
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ */
+
+#ifndef WIFI_IFACE_UTIL_H_
+#define WIFI_IFACE_UTIL_H_
+
+#include <wifi_system/interface_tool.h>
+
+#include <android/hardware/wifi/1.0/IWifi.h>
+
+#include "wifi_legacy_hal.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace iface_util {
+
+// Iface event handlers.
+struct IfaceEventHandlers {
+ // Callback to be invoked when the iface is set down & up for MAC address
+ // change.
+ std::function<void(const std::string& iface_name)> on_state_toggle_off_on;
+};
+
+/**
+ * Util class for common iface operations.
+ */
+class WifiIfaceUtil {
+ public:
+ WifiIfaceUtil(const std::weak_ptr<wifi_system::InterfaceTool> iface_tool,
+ const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
+ virtual ~WifiIfaceUtil() = default;
+
+ virtual std::array<uint8_t, 6> getFactoryMacAddress(const std::string& iface_name);
+ virtual bool setMacAddress(const std::string& iface_name, const std::array<uint8_t, 6>& mac);
+ // Get or create a random MAC address. The MAC address returned from
+ // this method will remain the same throughout the lifetime of the HAL
+ // daemon. (So, changes on every reboot)
+ virtual std::array<uint8_t, 6> getOrCreateRandomMacAddress();
+
+ // Register for any iface event callbacks for the provided interface.
+ virtual void registerIfaceEventHandlers(const std::string& iface_name,
+ IfaceEventHandlers handlers);
+ virtual void unregisterIfaceEventHandlers(const std::string& iface_name);
+ virtual bool setUpState(const std::string& iface_name, bool request_up);
+ virtual unsigned ifNameToIndex(const std::string& iface_name);
+
+ virtual bool createBridge(const std::string& br_name);
+
+ virtual bool deleteBridge(const std::string& br_name);
+
+ virtual bool addIfaceToBridge(const std::string& br_name, const std::string& if_name);
+
+ virtual bool removeIfaceFromBridge(const std::string& br_name, const std::string& if_name);
+ // Get a random MAC address.
+ virtual std::array<uint8_t, 6> createRandomMacAddress();
+
+ private:
+ std::weak_ptr<wifi_system::InterfaceTool> iface_tool_;
+ std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+ std::unique_ptr<std::array<uint8_t, 6>> random_mac_address_;
+ std::map<std::string, IfaceEventHandlers> event_handlers_map_;
+};
+
+} // namespace iface_util
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+
+#endif // WIFI_IFACE_UTIL_H_
diff --git a/wifi/1.6/default/wifi_legacy_hal.cpp b/wifi/1.6/default/wifi_legacy_hal.cpp
new file mode 100644
index 0000000..43cb7c4
--- /dev/null
+++ b/wifi/1.6/default/wifi_legacy_hal.cpp
@@ -0,0 +1,1654 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <array>
+#include <chrono>
+
+#include <android-base/logging.h>
+#include <cutils/properties.h>
+#include <net/if.h>
+
+#include "hidl_sync_util.h"
+#include "wifi_legacy_hal.h"
+#include "wifi_legacy_hal_stubs.h"
+
+namespace {
+// Constants ported over from the legacy HAL calling code
+// (com_android_server_wifi_WifiNative.cpp). This will all be thrown
+// away when this shim layer is replaced by the real vendor
+// implementation.
+static constexpr uint32_t kMaxVersionStringLength = 256;
+static constexpr uint32_t kMaxCachedGscanResults = 64;
+static constexpr uint32_t kMaxGscanFrequenciesForBand = 64;
+static constexpr uint32_t kLinkLayerStatsDataMpduSizeThreshold = 128;
+static constexpr uint32_t kMaxWakeReasonStatsArraySize = 32;
+static constexpr uint32_t kMaxRingBuffers = 10;
+static constexpr uint32_t kMaxWifiUsableChannels = 256;
+static constexpr uint32_t kMaxSupportedRadioCombinationsMatrixLength = 256;
+// need a long timeout (1000ms) for chips that unload their driver.
+static constexpr uint32_t kMaxStopCompleteWaitMs = 1000;
+static constexpr char kDriverPropName[] = "wlan.driver.status";
+
+// Helper function to create a non-const char* for legacy Hal API's.
+std::vector<char> makeCharVec(const std::string& str) {
+ std::vector<char> vec(str.size() + 1);
+ vec.assign(str.begin(), str.end());
+ vec.push_back('\0');
+ return vec;
+}
+} // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace legacy_hal {
+
+// Legacy HAL functions accept "C" style function pointers, so use global
+// functions to pass to the legacy HAL function and store the corresponding
+// std::function methods to be invoked.
+//
+// Callback to be invoked once |stop| is complete
+std::function<void(wifi_handle handle)> on_stop_complete_internal_callback;
+void onAsyncStopComplete(wifi_handle handle) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_stop_complete_internal_callback) {
+ on_stop_complete_internal_callback(handle);
+ // Invalidate this callback since we don't want this firing again.
+ on_stop_complete_internal_callback = nullptr;
+ }
+}
+
+// Callback to be invoked for driver dump.
+std::function<void(char*, int)> on_driver_memory_dump_internal_callback;
+void onSyncDriverMemoryDump(char* buffer, int buffer_size) {
+ if (on_driver_memory_dump_internal_callback) {
+ on_driver_memory_dump_internal_callback(buffer, buffer_size);
+ }
+}
+
+// Callback to be invoked for firmware dump.
+std::function<void(char*, int)> on_firmware_memory_dump_internal_callback;
+void onSyncFirmwareMemoryDump(char* buffer, int buffer_size) {
+ if (on_firmware_memory_dump_internal_callback) {
+ on_firmware_memory_dump_internal_callback(buffer, buffer_size);
+ }
+}
+
+// Callback to be invoked for Gscan events.
+std::function<void(wifi_request_id, wifi_scan_event)> on_gscan_event_internal_callback;
+void onAsyncGscanEvent(wifi_request_id id, wifi_scan_event event) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_gscan_event_internal_callback) {
+ on_gscan_event_internal_callback(id, event);
+ }
+}
+
+// Callback to be invoked for Gscan full results.
+std::function<void(wifi_request_id, wifi_scan_result*, uint32_t)>
+ on_gscan_full_result_internal_callback;
+void onAsyncGscanFullResult(wifi_request_id id, wifi_scan_result* result,
+ uint32_t buckets_scanned) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_gscan_full_result_internal_callback) {
+ on_gscan_full_result_internal_callback(id, result, buckets_scanned);
+ }
+}
+
+// Callback to be invoked for link layer stats results.
+std::function<void((wifi_request_id, wifi_iface_stat*, int, wifi_radio_stat*))>
+ on_link_layer_stats_result_internal_callback;
+void onSyncLinkLayerStatsResult(wifi_request_id id, wifi_iface_stat* iface_stat, int num_radios,
+ wifi_radio_stat* radio_stat) {
+ if (on_link_layer_stats_result_internal_callback) {
+ on_link_layer_stats_result_internal_callback(id, iface_stat, num_radios, radio_stat);
+ }
+}
+
+// Callback to be invoked for rssi threshold breach.
+std::function<void((wifi_request_id, uint8_t*, int8_t))>
+ on_rssi_threshold_breached_internal_callback;
+void onAsyncRssiThresholdBreached(wifi_request_id id, uint8_t* bssid, int8_t rssi) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_rssi_threshold_breached_internal_callback) {
+ on_rssi_threshold_breached_internal_callback(id, bssid, rssi);
+ }
+}
+
+// Callback to be invoked for ring buffer data indication.
+std::function<void(char*, char*, int, wifi_ring_buffer_status*)>
+ on_ring_buffer_data_internal_callback;
+void onAsyncRingBufferData(char* ring_name, char* buffer, int buffer_size,
+ wifi_ring_buffer_status* status) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_ring_buffer_data_internal_callback) {
+ on_ring_buffer_data_internal_callback(ring_name, buffer, buffer_size, status);
+ }
+}
+
+// Callback to be invoked for error alert indication.
+std::function<void(wifi_request_id, char*, int, int)> on_error_alert_internal_callback;
+void onAsyncErrorAlert(wifi_request_id id, char* buffer, int buffer_size, int err_code) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_error_alert_internal_callback) {
+ on_error_alert_internal_callback(id, buffer, buffer_size, err_code);
+ }
+}
+
+// Callback to be invoked for radio mode change indication.
+std::function<void(wifi_request_id, uint32_t, wifi_mac_info*)>
+ on_radio_mode_change_internal_callback;
+void onAsyncRadioModeChange(wifi_request_id id, uint32_t num_macs, wifi_mac_info* mac_infos) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_radio_mode_change_internal_callback) {
+ on_radio_mode_change_internal_callback(id, num_macs, mac_infos);
+ }
+}
+
+// Callback to be invoked to report subsystem restart
+std::function<void(const char*)> on_subsystem_restart_internal_callback;
+void onAsyncSubsystemRestart(const char* error) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_subsystem_restart_internal_callback) {
+ on_subsystem_restart_internal_callback(error);
+ }
+}
+
+// Callback to be invoked for rtt results results.
+std::function<void(wifi_request_id, unsigned num_results, wifi_rtt_result* rtt_results[])>
+ on_rtt_results_internal_callback;
+void onAsyncRttResults(wifi_request_id id, unsigned num_results, wifi_rtt_result* rtt_results[]) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_rtt_results_internal_callback) {
+ on_rtt_results_internal_callback(id, num_results, rtt_results);
+ on_rtt_results_internal_callback = nullptr;
+ }
+}
+
+// Callbacks for the various NAN operations.
+// NOTE: These have very little conversions to perform before invoking the user
+// callbacks.
+// So, handle all of them here directly to avoid adding an unnecessary layer.
+std::function<void(transaction_id, const NanResponseMsg&)> on_nan_notify_response_user_callback;
+void onAysncNanNotifyResponse(transaction_id id, NanResponseMsg* msg) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_nan_notify_response_user_callback && msg) {
+ on_nan_notify_response_user_callback(id, *msg);
+ }
+}
+
+std::function<void(const NanPublishRepliedInd&)> on_nan_event_publish_replied_user_callback;
+void onAysncNanEventPublishReplied(NanPublishRepliedInd* /* event */) {
+ LOG(ERROR) << "onAysncNanEventPublishReplied triggered";
+}
+
+std::function<void(const NanPublishTerminatedInd&)> on_nan_event_publish_terminated_user_callback;
+void onAysncNanEventPublishTerminated(NanPublishTerminatedInd* event) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_nan_event_publish_terminated_user_callback && event) {
+ on_nan_event_publish_terminated_user_callback(*event);
+ }
+}
+
+std::function<void(const NanMatchInd&)> on_nan_event_match_user_callback;
+void onAysncNanEventMatch(NanMatchInd* event) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_nan_event_match_user_callback && event) {
+ on_nan_event_match_user_callback(*event);
+ }
+}
+
+std::function<void(const NanMatchExpiredInd&)> on_nan_event_match_expired_user_callback;
+void onAysncNanEventMatchExpired(NanMatchExpiredInd* event) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_nan_event_match_expired_user_callback && event) {
+ on_nan_event_match_expired_user_callback(*event);
+ }
+}
+
+std::function<void(const NanSubscribeTerminatedInd&)>
+ on_nan_event_subscribe_terminated_user_callback;
+void onAysncNanEventSubscribeTerminated(NanSubscribeTerminatedInd* event) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_nan_event_subscribe_terminated_user_callback && event) {
+ on_nan_event_subscribe_terminated_user_callback(*event);
+ }
+}
+
+std::function<void(const NanFollowupInd&)> on_nan_event_followup_user_callback;
+void onAysncNanEventFollowup(NanFollowupInd* event) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_nan_event_followup_user_callback && event) {
+ on_nan_event_followup_user_callback(*event);
+ }
+}
+
+std::function<void(const NanDiscEngEventInd&)> on_nan_event_disc_eng_event_user_callback;
+void onAysncNanEventDiscEngEvent(NanDiscEngEventInd* event) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_nan_event_disc_eng_event_user_callback && event) {
+ on_nan_event_disc_eng_event_user_callback(*event);
+ }
+}
+
+std::function<void(const NanDisabledInd&)> on_nan_event_disabled_user_callback;
+void onAysncNanEventDisabled(NanDisabledInd* event) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_nan_event_disabled_user_callback && event) {
+ on_nan_event_disabled_user_callback(*event);
+ }
+}
+
+std::function<void(const NanTCAInd&)> on_nan_event_tca_user_callback;
+void onAysncNanEventTca(NanTCAInd* event) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_nan_event_tca_user_callback && event) {
+ on_nan_event_tca_user_callback(*event);
+ }
+}
+
+std::function<void(const NanBeaconSdfPayloadInd&)> on_nan_event_beacon_sdf_payload_user_callback;
+void onAysncNanEventBeaconSdfPayload(NanBeaconSdfPayloadInd* event) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_nan_event_beacon_sdf_payload_user_callback && event) {
+ on_nan_event_beacon_sdf_payload_user_callback(*event);
+ }
+}
+
+std::function<void(const NanDataPathRequestInd&)> on_nan_event_data_path_request_user_callback;
+void onAysncNanEventDataPathRequest(NanDataPathRequestInd* event) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_nan_event_data_path_request_user_callback && event) {
+ on_nan_event_data_path_request_user_callback(*event);
+ }
+}
+std::function<void(const NanDataPathConfirmInd&)> on_nan_event_data_path_confirm_user_callback;
+void onAysncNanEventDataPathConfirm(NanDataPathConfirmInd* event) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_nan_event_data_path_confirm_user_callback && event) {
+ on_nan_event_data_path_confirm_user_callback(*event);
+ }
+}
+
+std::function<void(const NanDataPathEndInd&)> on_nan_event_data_path_end_user_callback;
+void onAysncNanEventDataPathEnd(NanDataPathEndInd* event) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_nan_event_data_path_end_user_callback && event) {
+ on_nan_event_data_path_end_user_callback(*event);
+ }
+}
+
+std::function<void(const NanTransmitFollowupInd&)> on_nan_event_transmit_follow_up_user_callback;
+void onAysncNanEventTransmitFollowUp(NanTransmitFollowupInd* event) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_nan_event_transmit_follow_up_user_callback && event) {
+ on_nan_event_transmit_follow_up_user_callback(*event);
+ }
+}
+
+std::function<void(const NanRangeRequestInd&)> on_nan_event_range_request_user_callback;
+void onAysncNanEventRangeRequest(NanRangeRequestInd* event) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_nan_event_range_request_user_callback && event) {
+ on_nan_event_range_request_user_callback(*event);
+ }
+}
+
+std::function<void(const NanRangeReportInd&)> on_nan_event_range_report_user_callback;
+void onAysncNanEventRangeReport(NanRangeReportInd* event) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_nan_event_range_report_user_callback && event) {
+ on_nan_event_range_report_user_callback(*event);
+ }
+}
+
+std::function<void(const NanDataPathScheduleUpdateInd&)> on_nan_event_schedule_update_user_callback;
+void onAsyncNanEventScheduleUpdate(NanDataPathScheduleUpdateInd* event) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_nan_event_schedule_update_user_callback && event) {
+ on_nan_event_schedule_update_user_callback(*event);
+ }
+}
+
+// Callbacks for the various TWT operations.
+std::function<void(const TwtSetupResponse&)> on_twt_event_setup_response_callback;
+void onAsyncTwtEventSetupResponse(TwtSetupResponse* event) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_twt_event_setup_response_callback && event) {
+ on_twt_event_setup_response_callback(*event);
+ }
+}
+
+std::function<void(const TwtTeardownCompletion&)> on_twt_event_teardown_completion_callback;
+void onAsyncTwtEventTeardownCompletion(TwtTeardownCompletion* event) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_twt_event_teardown_completion_callback && event) {
+ on_twt_event_teardown_completion_callback(*event);
+ }
+}
+
+std::function<void(const TwtInfoFrameReceived&)> on_twt_event_info_frame_received_callback;
+void onAsyncTwtEventInfoFrameReceived(TwtInfoFrameReceived* event) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_twt_event_info_frame_received_callback && event) {
+ on_twt_event_info_frame_received_callback(*event);
+ }
+}
+
+std::function<void(const TwtDeviceNotify&)> on_twt_event_device_notify_callback;
+void onAsyncTwtEventDeviceNotify(TwtDeviceNotify* event) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_twt_event_device_notify_callback && event) {
+ on_twt_event_device_notify_callback(*event);
+ }
+}
+
+// Callback to report current CHRE NAN state
+std::function<void(chre_nan_rtt_state)> on_chre_nan_rtt_internal_callback;
+void onAsyncChreNanRttState(chre_nan_rtt_state state) {
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (on_chre_nan_rtt_internal_callback) {
+ on_chre_nan_rtt_internal_callback(state);
+ }
+}
+
+// Callback to report cached scan results
+std::function<void(wifi_cached_scan_report*)> on_cached_scan_results_internal_callback;
+void onSyncCachedScanResults(wifi_cached_scan_report* cache_report) {
+ if (on_cached_scan_results_internal_callback) {
+ on_cached_scan_results_internal_callback(cache_report);
+ }
+}
+
+// End of the free-standing "C" style callbacks.
+
+WifiLegacyHal::WifiLegacyHal(const std::weak_ptr<wifi_system::InterfaceTool> iface_tool,
+ const wifi_hal_fn& fn, bool is_primary)
+ : global_func_table_(fn),
+ global_handle_(nullptr),
+ awaiting_event_loop_termination_(false),
+ is_started_(false),
+ iface_tool_(iface_tool),
+ is_primary_(is_primary) {}
+
+wifi_error WifiLegacyHal::initialize() {
+ LOG(DEBUG) << "Initialize legacy HAL";
+ // this now does nothing, since HAL function table is provided
+ // to the constructor
+ return WIFI_SUCCESS;
+}
+
+wifi_error WifiLegacyHal::start() {
+ // Ensure that we're starting in a good state.
+ CHECK(global_func_table_.wifi_initialize && !global_handle_ && iface_name_to_handle_.empty() &&
+ !awaiting_event_loop_termination_);
+ if (is_started_) {
+ LOG(DEBUG) << "Legacy HAL already started";
+ return WIFI_SUCCESS;
+ }
+ LOG(DEBUG) << "Waiting for the driver ready";
+ wifi_error status = global_func_table_.wifi_wait_for_driver_ready();
+ if (status == WIFI_ERROR_TIMED_OUT || status == WIFI_ERROR_UNKNOWN) {
+ LOG(ERROR) << "Failed or timed out awaiting driver ready";
+ return status;
+ }
+
+ if (is_primary_) {
+ property_set(kDriverPropName, "ok");
+
+ if (!iface_tool_.lock()->SetWifiUpState(true)) {
+ LOG(ERROR) << "Failed to set WiFi interface up";
+ return WIFI_ERROR_UNKNOWN;
+ }
+ }
+
+ LOG(DEBUG) << "Starting legacy HAL";
+ status = global_func_table_.wifi_initialize(&global_handle_);
+ if (status != WIFI_SUCCESS || !global_handle_) {
+ LOG(ERROR) << "Failed to retrieve global handle";
+ return status;
+ }
+ std::thread(&WifiLegacyHal::runEventLoop, this).detach();
+ status = retrieveIfaceHandles();
+ if (status != WIFI_SUCCESS || iface_name_to_handle_.empty()) {
+ LOG(ERROR) << "Failed to retrieve wlan interface handle";
+ return status;
+ }
+ LOG(DEBUG) << "Legacy HAL start complete";
+ is_started_ = true;
+ return WIFI_SUCCESS;
+}
+
+wifi_error WifiLegacyHal::stop(
+ /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock,
+ const std::function<void()>& on_stop_complete_user_callback) {
+ if (!is_started_) {
+ LOG(DEBUG) << "Legacy HAL already stopped";
+ on_stop_complete_user_callback();
+ return WIFI_SUCCESS;
+ }
+ LOG(DEBUG) << "Stopping legacy HAL";
+ on_stop_complete_internal_callback = [on_stop_complete_user_callback,
+ this](wifi_handle handle) {
+ CHECK_EQ(global_handle_, handle) << "Handle mismatch";
+ LOG(INFO) << "Legacy HAL stop complete callback received";
+ // Invalidate all the internal pointers now that the HAL is
+ // stopped.
+ invalidate();
+ if (is_primary_) iface_tool_.lock()->SetWifiUpState(false);
+ on_stop_complete_user_callback();
+ is_started_ = false;
+ };
+ awaiting_event_loop_termination_ = true;
+ global_func_table_.wifi_cleanup(global_handle_, onAsyncStopComplete);
+ const auto status =
+ stop_wait_cv_.wait_for(*lock, std::chrono::milliseconds(kMaxStopCompleteWaitMs),
+ [this] { return !awaiting_event_loop_termination_; });
+ if (!status) {
+ LOG(ERROR) << "Legacy HAL stop failed or timed out";
+ return WIFI_ERROR_UNKNOWN;
+ }
+ LOG(DEBUG) << "Legacy HAL stop complete";
+ return WIFI_SUCCESS;
+}
+
+bool WifiLegacyHal::isStarted() {
+ return is_started_;
+}
+
+wifi_error WifiLegacyHal::waitForDriverReady() {
+ return global_func_table_.wifi_wait_for_driver_ready();
+}
+
+std::pair<wifi_error, std::string> WifiLegacyHal::getDriverVersion(const std::string& iface_name) {
+ std::array<char, kMaxVersionStringLength> buffer;
+ buffer.fill(0);
+ wifi_error status = global_func_table_.wifi_get_driver_version(getIfaceHandle(iface_name),
+ buffer.data(), buffer.size());
+ return {status, buffer.data()};
+}
+
+std::pair<wifi_error, std::string> WifiLegacyHal::getFirmwareVersion(
+ const std::string& iface_name) {
+ std::array<char, kMaxVersionStringLength> buffer;
+ buffer.fill(0);
+ wifi_error status = global_func_table_.wifi_get_firmware_version(getIfaceHandle(iface_name),
+ buffer.data(), buffer.size());
+ return {status, buffer.data()};
+}
+
+std::pair<wifi_error, std::vector<uint8_t>> WifiLegacyHal::requestDriverMemoryDump(
+ const std::string& iface_name) {
+ std::vector<uint8_t> driver_dump;
+ on_driver_memory_dump_internal_callback = [&driver_dump](char* buffer, int buffer_size) {
+ driver_dump.insert(driver_dump.end(), reinterpret_cast<uint8_t*>(buffer),
+ reinterpret_cast<uint8_t*>(buffer) + buffer_size);
+ };
+ wifi_error status = global_func_table_.wifi_get_driver_memory_dump(getIfaceHandle(iface_name),
+ {onSyncDriverMemoryDump});
+ on_driver_memory_dump_internal_callback = nullptr;
+ return {status, std::move(driver_dump)};
+}
+
+std::pair<wifi_error, std::vector<uint8_t>> WifiLegacyHal::requestFirmwareMemoryDump(
+ const std::string& iface_name) {
+ std::vector<uint8_t> firmware_dump;
+ on_firmware_memory_dump_internal_callback = [&firmware_dump](char* buffer, int buffer_size) {
+ firmware_dump.insert(firmware_dump.end(), reinterpret_cast<uint8_t*>(buffer),
+ reinterpret_cast<uint8_t*>(buffer) + buffer_size);
+ };
+ wifi_error status = global_func_table_.wifi_get_firmware_memory_dump(
+ getIfaceHandle(iface_name), {onSyncFirmwareMemoryDump});
+ on_firmware_memory_dump_internal_callback = nullptr;
+ return {status, std::move(firmware_dump)};
+}
+
+std::pair<wifi_error, uint64_t> WifiLegacyHal::getSupportedFeatureSet(
+ const std::string& iface_name) {
+ feature_set set = 0, chip_set = 0;
+ wifi_error status = WIFI_SUCCESS;
+
+ static_assert(sizeof(set) == sizeof(uint64_t),
+ "Some feature_flags can not be represented in output");
+ wifi_interface_handle iface_handle = getIfaceHandle(iface_name);
+
+ global_func_table_.wifi_get_chip_feature_set(
+ global_handle_, &chip_set); /* ignore error, chip_set will stay 0 */
+
+ if (iface_handle) {
+ status = global_func_table_.wifi_get_supported_feature_set(iface_handle, &set);
+ }
+ return {status, static_cast<uint64_t>(set | chip_set)};
+}
+
+std::pair<wifi_error, PacketFilterCapabilities> WifiLegacyHal::getPacketFilterCapabilities(
+ const std::string& iface_name) {
+ PacketFilterCapabilities caps;
+ wifi_error status = global_func_table_.wifi_get_packet_filter_capabilities(
+ getIfaceHandle(iface_name), &caps.version, &caps.max_len);
+ return {status, caps};
+}
+
+wifi_error WifiLegacyHal::setPacketFilter(const std::string& iface_name,
+ const std::vector<uint8_t>& program) {
+ return global_func_table_.wifi_set_packet_filter(getIfaceHandle(iface_name), program.data(),
+ program.size());
+}
+
+std::pair<wifi_error, std::vector<uint8_t>> WifiLegacyHal::readApfPacketFilterData(
+ const std::string& iface_name) {
+ PacketFilterCapabilities caps;
+ wifi_error status = global_func_table_.wifi_get_packet_filter_capabilities(
+ getIfaceHandle(iface_name), &caps.version, &caps.max_len);
+ if (status != WIFI_SUCCESS) {
+ return {status, {}};
+ }
+
+ // Size the buffer to read the entire program & work memory.
+ std::vector<uint8_t> buffer(caps.max_len);
+
+ status = global_func_table_.wifi_read_packet_filter(
+ getIfaceHandle(iface_name), /*src_offset=*/0, buffer.data(), buffer.size());
+ return {status, std::move(buffer)};
+}
+
+std::pair<wifi_error, wifi_gscan_capabilities> WifiLegacyHal::getGscanCapabilities(
+ const std::string& iface_name) {
+ wifi_gscan_capabilities caps;
+ wifi_error status =
+ global_func_table_.wifi_get_gscan_capabilities(getIfaceHandle(iface_name), &caps);
+ return {status, caps};
+}
+
+wifi_error WifiLegacyHal::startGscan(
+ const std::string& iface_name, wifi_request_id id, const wifi_scan_cmd_params& params,
+ const std::function<void(wifi_request_id)>& on_failure_user_callback,
+ const on_gscan_results_callback& on_results_user_callback,
+ const on_gscan_full_result_callback& on_full_result_user_callback) {
+ // If there is already an ongoing background scan, reject new scan requests.
+ if (on_gscan_event_internal_callback || on_gscan_full_result_internal_callback) {
+ return WIFI_ERROR_NOT_AVAILABLE;
+ }
+
+ // This callback will be used to either trigger |on_results_user_callback|
+ // or |on_failure_user_callback|.
+ on_gscan_event_internal_callback = [iface_name, on_failure_user_callback,
+ on_results_user_callback,
+ this](wifi_request_id id, wifi_scan_event event) {
+ switch (event) {
+ case WIFI_SCAN_RESULTS_AVAILABLE:
+ case WIFI_SCAN_THRESHOLD_NUM_SCANS:
+ case WIFI_SCAN_THRESHOLD_PERCENT: {
+ wifi_error status;
+ std::vector<wifi_cached_scan_results> cached_scan_results;
+ std::tie(status, cached_scan_results) = getGscanCachedResults(iface_name);
+ if (status == WIFI_SUCCESS) {
+ on_results_user_callback(id, cached_scan_results);
+ return;
+ }
+ FALLTHROUGH_INTENDED;
+ }
+ // Fall through if failed. Failure to retrieve cached scan
+ // results should trigger a background scan failure.
+ case WIFI_SCAN_FAILED:
+ on_failure_user_callback(id);
+ on_gscan_event_internal_callback = nullptr;
+ on_gscan_full_result_internal_callback = nullptr;
+ return;
+ }
+ LOG(FATAL) << "Unexpected gscan event received: " << event;
+ };
+
+ on_gscan_full_result_internal_callback = [on_full_result_user_callback](
+ wifi_request_id id, wifi_scan_result* result,
+ uint32_t buckets_scanned) {
+ if (result) {
+ on_full_result_user_callback(id, result, buckets_scanned);
+ }
+ };
+
+ wifi_scan_result_handler handler = {onAsyncGscanFullResult, onAsyncGscanEvent};
+ wifi_error status =
+ global_func_table_.wifi_start_gscan(id, getIfaceHandle(iface_name), params, handler);
+ if (status != WIFI_SUCCESS) {
+ on_gscan_event_internal_callback = nullptr;
+ on_gscan_full_result_internal_callback = nullptr;
+ }
+ return status;
+}
+
+wifi_error WifiLegacyHal::stopGscan(const std::string& iface_name, wifi_request_id id) {
+ // If there is no an ongoing background scan, reject stop requests.
+ // TODO(b/32337212): This needs to be handled by the HIDL object because we
+ // need to return the NOT_STARTED error code.
+ if (!on_gscan_event_internal_callback && !on_gscan_full_result_internal_callback) {
+ return WIFI_ERROR_NOT_AVAILABLE;
+ }
+ wifi_error status = global_func_table_.wifi_stop_gscan(id, getIfaceHandle(iface_name));
+ // If the request Id is wrong, don't stop the ongoing background scan. Any
+ // other error should be treated as the end of background scan.
+ if (status != WIFI_ERROR_INVALID_REQUEST_ID) {
+ on_gscan_event_internal_callback = nullptr;
+ on_gscan_full_result_internal_callback = nullptr;
+ }
+ return status;
+}
+
+std::pair<wifi_error, std::vector<uint32_t>> WifiLegacyHal::getValidFrequenciesForBand(
+ const std::string& iface_name, wifi_band band) {
+ static_assert(sizeof(uint32_t) >= sizeof(wifi_channel),
+ "Wifi Channel cannot be represented in output");
+ std::vector<uint32_t> freqs;
+ freqs.resize(kMaxGscanFrequenciesForBand);
+ int32_t num_freqs = 0;
+ wifi_error status = global_func_table_.wifi_get_valid_channels(
+ getIfaceHandle(iface_name), band, freqs.size(),
+ reinterpret_cast<wifi_channel*>(freqs.data()), &num_freqs);
+ CHECK(num_freqs >= 0 && static_cast<uint32_t>(num_freqs) <= kMaxGscanFrequenciesForBand);
+ freqs.resize(num_freqs);
+ return {status, std::move(freqs)};
+}
+
+wifi_error WifiLegacyHal::setDfsFlag(const std::string& iface_name, bool dfs_on) {
+ return global_func_table_.wifi_set_nodfs_flag(getIfaceHandle(iface_name), dfs_on ? 0 : 1);
+}
+
+wifi_error WifiLegacyHal::enableLinkLayerStats(const std::string& iface_name, bool debug) {
+ wifi_link_layer_params params;
+ params.mpdu_size_threshold = kLinkLayerStatsDataMpduSizeThreshold;
+ params.aggressive_statistics_gathering = debug;
+ return global_func_table_.wifi_set_link_stats(getIfaceHandle(iface_name), params);
+}
+
+wifi_error WifiLegacyHal::disableLinkLayerStats(const std::string& iface_name) {
+ // TODO: Do we care about these responses?
+ uint32_t clear_mask_rsp;
+ uint8_t stop_rsp;
+ return global_func_table_.wifi_clear_link_stats(getIfaceHandle(iface_name), 0xFFFFFFFF,
+ &clear_mask_rsp, 1, &stop_rsp);
+}
+
+std::pair<wifi_error, LinkLayerStats> WifiLegacyHal::getLinkLayerStats(
+ const std::string& iface_name) {
+ LinkLayerStats link_stats{};
+ LinkLayerStats* link_stats_ptr = &link_stats;
+
+ on_link_layer_stats_result_internal_callback = [&link_stats_ptr](
+ wifi_request_id /* id */,
+ wifi_iface_stat* iface_stats_ptr,
+ int num_radios,
+ wifi_radio_stat* radio_stats_ptr) {
+ wifi_radio_stat* l_radio_stats_ptr;
+ wifi_peer_info* l_peer_info_stats_ptr;
+
+ if (iface_stats_ptr != nullptr) {
+ link_stats_ptr->iface = *iface_stats_ptr;
+ l_peer_info_stats_ptr = iface_stats_ptr->peer_info;
+ for (uint32_t i = 0; i < iface_stats_ptr->num_peers; i++) {
+ WifiPeerInfo peer;
+ peer.peer_info = *l_peer_info_stats_ptr;
+ if (l_peer_info_stats_ptr->num_rate > 0) {
+ /* Copy the rate stats */
+ peer.rate_stats.assign(
+ l_peer_info_stats_ptr->rate_stats,
+ l_peer_info_stats_ptr->rate_stats + l_peer_info_stats_ptr->num_rate);
+ }
+ peer.peer_info.num_rate = 0;
+ link_stats_ptr->peers.push_back(peer);
+ l_peer_info_stats_ptr =
+ (wifi_peer_info*)((u8*)l_peer_info_stats_ptr + sizeof(wifi_peer_info) +
+ (sizeof(wifi_rate_stat) *
+ l_peer_info_stats_ptr->num_rate));
+ }
+ link_stats_ptr->iface.num_peers = 0;
+ } else {
+ LOG(ERROR) << "Invalid iface stats in link layer stats";
+ }
+ if (num_radios <= 0 || radio_stats_ptr == nullptr) {
+ LOG(ERROR) << "Invalid radio stats in link layer stats";
+ return;
+ }
+ l_radio_stats_ptr = radio_stats_ptr;
+ for (int i = 0; i < num_radios; i++) {
+ LinkLayerRadioStats radio;
+
+ radio.stats = *l_radio_stats_ptr;
+ // Copy over the tx level array to the separate vector.
+ if (l_radio_stats_ptr->num_tx_levels > 0 &&
+ l_radio_stats_ptr->tx_time_per_levels != nullptr) {
+ radio.tx_time_per_levels.assign(
+ l_radio_stats_ptr->tx_time_per_levels,
+ l_radio_stats_ptr->tx_time_per_levels + l_radio_stats_ptr->num_tx_levels);
+ }
+ radio.stats.num_tx_levels = 0;
+ radio.stats.tx_time_per_levels = nullptr;
+ /* Copy over the channel stat to separate vector */
+ if (l_radio_stats_ptr->num_channels > 0) {
+ /* Copy the channel stats */
+ radio.channel_stats.assign(
+ l_radio_stats_ptr->channels,
+ l_radio_stats_ptr->channels + l_radio_stats_ptr->num_channels);
+ }
+ link_stats_ptr->radios.push_back(radio);
+ l_radio_stats_ptr =
+ (wifi_radio_stat*)((u8*)l_radio_stats_ptr + sizeof(wifi_radio_stat) +
+ (sizeof(wifi_channel_stat) *
+ l_radio_stats_ptr->num_channels));
+ }
+ };
+
+ wifi_error status = global_func_table_.wifi_get_link_stats(0, getIfaceHandle(iface_name),
+ {onSyncLinkLayerStatsResult});
+ on_link_layer_stats_result_internal_callback = nullptr;
+ return {status, link_stats};
+}
+
+wifi_error WifiLegacyHal::startRssiMonitoring(
+ const std::string& iface_name, wifi_request_id id, int8_t max_rssi, int8_t min_rssi,
+ const on_rssi_threshold_breached_callback& on_threshold_breached_user_callback) {
+ if (on_rssi_threshold_breached_internal_callback) {
+ return WIFI_ERROR_NOT_AVAILABLE;
+ }
+ on_rssi_threshold_breached_internal_callback = [on_threshold_breached_user_callback](
+ wifi_request_id id, uint8_t* bssid_ptr,
+ int8_t rssi) {
+ if (!bssid_ptr) {
+ return;
+ }
+ std::array<uint8_t, 6> bssid_arr;
+ // |bssid_ptr| pointer is assumed to have 6 bytes for the mac
+ // address.
+ std::copy(bssid_ptr, bssid_ptr + 6, std::begin(bssid_arr));
+ on_threshold_breached_user_callback(id, bssid_arr, rssi);
+ };
+ wifi_error status = global_func_table_.wifi_start_rssi_monitoring(
+ id, getIfaceHandle(iface_name), max_rssi, min_rssi, {onAsyncRssiThresholdBreached});
+ if (status != WIFI_SUCCESS) {
+ on_rssi_threshold_breached_internal_callback = nullptr;
+ }
+ return status;
+}
+
+wifi_error WifiLegacyHal::stopRssiMonitoring(const std::string& iface_name, wifi_request_id id) {
+ if (!on_rssi_threshold_breached_internal_callback) {
+ return WIFI_ERROR_NOT_AVAILABLE;
+ }
+ wifi_error status =
+ global_func_table_.wifi_stop_rssi_monitoring(id, getIfaceHandle(iface_name));
+ // If the request Id is wrong, don't stop the ongoing rssi monitoring. Any
+ // other error should be treated as the end of background scan.
+ if (status != WIFI_ERROR_INVALID_REQUEST_ID) {
+ on_rssi_threshold_breached_internal_callback = nullptr;
+ }
+ return status;
+}
+
+std::pair<wifi_error, wifi_roaming_capabilities> WifiLegacyHal::getRoamingCapabilities(
+ const std::string& iface_name) {
+ wifi_roaming_capabilities caps;
+ wifi_error status =
+ global_func_table_.wifi_get_roaming_capabilities(getIfaceHandle(iface_name), &caps);
+ return {status, caps};
+}
+
+wifi_error WifiLegacyHal::configureRoaming(const std::string& iface_name,
+ const wifi_roaming_config& config) {
+ wifi_roaming_config config_internal = config;
+ return global_func_table_.wifi_configure_roaming(getIfaceHandle(iface_name), &config_internal);
+}
+
+wifi_error WifiLegacyHal::enableFirmwareRoaming(const std::string& iface_name,
+ fw_roaming_state_t state) {
+ return global_func_table_.wifi_enable_firmware_roaming(getIfaceHandle(iface_name), state);
+}
+
+wifi_error WifiLegacyHal::configureNdOffload(const std::string& iface_name, bool enable) {
+ return global_func_table_.wifi_configure_nd_offload(getIfaceHandle(iface_name), enable);
+}
+
+wifi_error WifiLegacyHal::startSendingOffloadedPacket(const std::string& iface_name,
+ uint32_t cmd_id, uint16_t ether_type,
+ const std::vector<uint8_t>& ip_packet_data,
+ const std::array<uint8_t, 6>& src_address,
+ const std::array<uint8_t, 6>& dst_address,
+ uint32_t period_in_ms) {
+ std::vector<uint8_t> ip_packet_data_internal(ip_packet_data);
+ std::vector<uint8_t> src_address_internal(src_address.data(),
+ src_address.data() + src_address.size());
+ std::vector<uint8_t> dst_address_internal(dst_address.data(),
+ dst_address.data() + dst_address.size());
+ return global_func_table_.wifi_start_sending_offloaded_packet(
+ cmd_id, getIfaceHandle(iface_name), ether_type, ip_packet_data_internal.data(),
+ ip_packet_data_internal.size(), src_address_internal.data(),
+ dst_address_internal.data(), period_in_ms);
+}
+
+wifi_error WifiLegacyHal::stopSendingOffloadedPacket(const std::string& iface_name,
+ uint32_t cmd_id) {
+ return global_func_table_.wifi_stop_sending_offloaded_packet(cmd_id,
+ getIfaceHandle(iface_name));
+}
+
+wifi_error WifiLegacyHal::selectTxPowerScenario(const std::string& iface_name,
+ wifi_power_scenario scenario) {
+ return global_func_table_.wifi_select_tx_power_scenario(getIfaceHandle(iface_name), scenario);
+}
+
+wifi_error WifiLegacyHal::resetTxPowerScenario(const std::string& iface_name) {
+ return global_func_table_.wifi_reset_tx_power_scenario(getIfaceHandle(iface_name));
+}
+
+wifi_error WifiLegacyHal::setLatencyMode(const std::string& iface_name, wifi_latency_mode mode) {
+ return global_func_table_.wifi_set_latency_mode(getIfaceHandle(iface_name), mode);
+}
+
+wifi_error WifiLegacyHal::setThermalMitigationMode(wifi_thermal_mode mode,
+ uint32_t completion_window) {
+ return global_func_table_.wifi_set_thermal_mitigation_mode(global_handle_, mode,
+ completion_window);
+}
+
+wifi_error WifiLegacyHal::setDscpToAccessCategoryMapping(uint32_t start, uint32_t end,
+ uint32_t access_category) {
+ return global_func_table_.wifi_map_dscp_access_category(global_handle_, start, end,
+ access_category);
+}
+
+wifi_error WifiLegacyHal::resetDscpToAccessCategoryMapping() {
+ return global_func_table_.wifi_reset_dscp_mapping(global_handle_);
+}
+
+std::pair<wifi_error, uint32_t> WifiLegacyHal::getLoggerSupportedFeatureSet(
+ const std::string& iface_name) {
+ uint32_t supported_feature_flags = 0;
+ wifi_error status = WIFI_SUCCESS;
+
+ wifi_interface_handle iface_handle = getIfaceHandle(iface_name);
+
+ if (iface_handle) {
+ status = global_func_table_.wifi_get_logger_supported_feature_set(iface_handle,
+ &supported_feature_flags);
+ }
+ return {status, supported_feature_flags};
+}
+
+wifi_error WifiLegacyHal::startPktFateMonitoring(const std::string& iface_name) {
+ return global_func_table_.wifi_start_pkt_fate_monitoring(getIfaceHandle(iface_name));
+}
+
+std::pair<wifi_error, std::vector<wifi_tx_report>> WifiLegacyHal::getTxPktFates(
+ const std::string& iface_name) {
+ std::vector<wifi_tx_report> tx_pkt_fates;
+ tx_pkt_fates.resize(MAX_FATE_LOG_LEN);
+ size_t num_fates = 0;
+ wifi_error status = global_func_table_.wifi_get_tx_pkt_fates(
+ getIfaceHandle(iface_name), tx_pkt_fates.data(), tx_pkt_fates.size(), &num_fates);
+ CHECK(num_fates <= MAX_FATE_LOG_LEN);
+ tx_pkt_fates.resize(num_fates);
+ return {status, std::move(tx_pkt_fates)};
+}
+
+std::pair<wifi_error, std::vector<wifi_rx_report>> WifiLegacyHal::getRxPktFates(
+ const std::string& iface_name) {
+ std::vector<wifi_rx_report> rx_pkt_fates;
+ rx_pkt_fates.resize(MAX_FATE_LOG_LEN);
+ size_t num_fates = 0;
+ wifi_error status = global_func_table_.wifi_get_rx_pkt_fates(
+ getIfaceHandle(iface_name), rx_pkt_fates.data(), rx_pkt_fates.size(), &num_fates);
+ CHECK(num_fates <= MAX_FATE_LOG_LEN);
+ rx_pkt_fates.resize(num_fates);
+ return {status, std::move(rx_pkt_fates)};
+}
+
+std::pair<wifi_error, WakeReasonStats> WifiLegacyHal::getWakeReasonStats(
+ const std::string& iface_name) {
+ WakeReasonStats stats;
+ stats.cmd_event_wake_cnt.resize(kMaxWakeReasonStatsArraySize);
+ stats.driver_fw_local_wake_cnt.resize(kMaxWakeReasonStatsArraySize);
+
+ // This legacy struct needs separate memory to store the variable sized wake
+ // reason types.
+ stats.wake_reason_cnt.cmd_event_wake_cnt =
+ reinterpret_cast<int32_t*>(stats.cmd_event_wake_cnt.data());
+ stats.wake_reason_cnt.cmd_event_wake_cnt_sz = stats.cmd_event_wake_cnt.size();
+ stats.wake_reason_cnt.cmd_event_wake_cnt_used = 0;
+ stats.wake_reason_cnt.driver_fw_local_wake_cnt =
+ reinterpret_cast<int32_t*>(stats.driver_fw_local_wake_cnt.data());
+ stats.wake_reason_cnt.driver_fw_local_wake_cnt_sz = stats.driver_fw_local_wake_cnt.size();
+ stats.wake_reason_cnt.driver_fw_local_wake_cnt_used = 0;
+
+ wifi_error status = global_func_table_.wifi_get_wake_reason_stats(getIfaceHandle(iface_name),
+ &stats.wake_reason_cnt);
+
+ CHECK(stats.wake_reason_cnt.cmd_event_wake_cnt_used >= 0 &&
+ static_cast<uint32_t>(stats.wake_reason_cnt.cmd_event_wake_cnt_used) <=
+ kMaxWakeReasonStatsArraySize);
+ stats.cmd_event_wake_cnt.resize(stats.wake_reason_cnt.cmd_event_wake_cnt_used);
+ stats.wake_reason_cnt.cmd_event_wake_cnt = nullptr;
+
+ CHECK(stats.wake_reason_cnt.driver_fw_local_wake_cnt_used >= 0 &&
+ static_cast<uint32_t>(stats.wake_reason_cnt.driver_fw_local_wake_cnt_used) <=
+ kMaxWakeReasonStatsArraySize);
+ stats.driver_fw_local_wake_cnt.resize(stats.wake_reason_cnt.driver_fw_local_wake_cnt_used);
+ stats.wake_reason_cnt.driver_fw_local_wake_cnt = nullptr;
+
+ return {status, stats};
+}
+
+wifi_error WifiLegacyHal::registerRingBufferCallbackHandler(
+ const std::string& iface_name, const on_ring_buffer_data_callback& on_user_data_callback) {
+ if (on_ring_buffer_data_internal_callback) {
+ return WIFI_ERROR_NOT_AVAILABLE;
+ }
+ on_ring_buffer_data_internal_callback = [on_user_data_callback](
+ char* ring_name, char* buffer, int buffer_size,
+ wifi_ring_buffer_status* status) {
+ if (status && buffer) {
+ std::vector<uint8_t> buffer_vector(reinterpret_cast<uint8_t*>(buffer),
+ reinterpret_cast<uint8_t*>(buffer) + buffer_size);
+ on_user_data_callback(ring_name, buffer_vector, *status);
+ }
+ };
+ wifi_error status = global_func_table_.wifi_set_log_handler(0, getIfaceHandle(iface_name),
+ {onAsyncRingBufferData});
+ if (status != WIFI_SUCCESS) {
+ on_ring_buffer_data_internal_callback = nullptr;
+ }
+ return status;
+}
+
+wifi_error WifiLegacyHal::deregisterRingBufferCallbackHandler(const std::string& iface_name) {
+ if (!on_ring_buffer_data_internal_callback) {
+ return WIFI_ERROR_NOT_AVAILABLE;
+ }
+ on_ring_buffer_data_internal_callback = nullptr;
+ return global_func_table_.wifi_reset_log_handler(0, getIfaceHandle(iface_name));
+}
+
+std::pair<wifi_error, std::vector<wifi_ring_buffer_status>> WifiLegacyHal::getRingBuffersStatus(
+ const std::string& iface_name) {
+ std::vector<wifi_ring_buffer_status> ring_buffers_status;
+ ring_buffers_status.resize(kMaxRingBuffers);
+ uint32_t num_rings = kMaxRingBuffers;
+ wifi_error status = global_func_table_.wifi_get_ring_buffers_status(
+ getIfaceHandle(iface_name), &num_rings, ring_buffers_status.data());
+ CHECK(num_rings <= kMaxRingBuffers);
+ ring_buffers_status.resize(num_rings);
+ return {status, std::move(ring_buffers_status)};
+}
+
+wifi_error WifiLegacyHal::startRingBufferLogging(const std::string& iface_name,
+ const std::string& ring_name,
+ uint32_t verbose_level, uint32_t max_interval_sec,
+ uint32_t min_data_size) {
+ return global_func_table_.wifi_start_logging(getIfaceHandle(iface_name), verbose_level, 0,
+ max_interval_sec, min_data_size,
+ makeCharVec(ring_name).data());
+}
+
+wifi_error WifiLegacyHal::getRingBufferData(const std::string& iface_name,
+ const std::string& ring_name) {
+ return global_func_table_.wifi_get_ring_data(getIfaceHandle(iface_name),
+ makeCharVec(ring_name).data());
+}
+
+wifi_error WifiLegacyHal::registerErrorAlertCallbackHandler(
+ const std::string& iface_name, const on_error_alert_callback& on_user_alert_callback) {
+ if (on_error_alert_internal_callback) {
+ return WIFI_ERROR_NOT_AVAILABLE;
+ }
+ on_error_alert_internal_callback = [on_user_alert_callback](wifi_request_id id, char* buffer,
+ int buffer_size, int err_code) {
+ if (buffer) {
+ CHECK(id == 0);
+ on_user_alert_callback(
+ err_code,
+ std::vector<uint8_t>(reinterpret_cast<uint8_t*>(buffer),
+ reinterpret_cast<uint8_t*>(buffer) + buffer_size));
+ }
+ };
+ wifi_error status = global_func_table_.wifi_set_alert_handler(0, getIfaceHandle(iface_name),
+ {onAsyncErrorAlert});
+ if (status != WIFI_SUCCESS) {
+ on_error_alert_internal_callback = nullptr;
+ }
+ return status;
+}
+
+wifi_error WifiLegacyHal::deregisterErrorAlertCallbackHandler(const std::string& iface_name) {
+ if (!on_error_alert_internal_callback) {
+ return WIFI_ERROR_NOT_AVAILABLE;
+ }
+ on_error_alert_internal_callback = nullptr;
+ return global_func_table_.wifi_reset_alert_handler(0, getIfaceHandle(iface_name));
+}
+
+wifi_error WifiLegacyHal::registerRadioModeChangeCallbackHandler(
+ const std::string& iface_name,
+ const on_radio_mode_change_callback& on_user_change_callback) {
+ if (on_radio_mode_change_internal_callback) {
+ return WIFI_ERROR_NOT_AVAILABLE;
+ }
+ on_radio_mode_change_internal_callback = [on_user_change_callback](
+ wifi_request_id /* id */, uint32_t num_macs,
+ wifi_mac_info* mac_infos_arr) {
+ if (num_macs > 0 && mac_infos_arr) {
+ std::vector<WifiMacInfo> mac_infos_vec;
+ for (uint32_t i = 0; i < num_macs; i++) {
+ WifiMacInfo mac_info;
+ mac_info.wlan_mac_id = mac_infos_arr[i].wlan_mac_id;
+ mac_info.mac_band = mac_infos_arr[i].mac_band;
+ for (int32_t j = 0; j < mac_infos_arr[i].num_iface; j++) {
+ WifiIfaceInfo iface_info;
+ iface_info.name = mac_infos_arr[i].iface_info[j].iface_name;
+ iface_info.channel = mac_infos_arr[i].iface_info[j].channel;
+ mac_info.iface_infos.push_back(iface_info);
+ }
+ mac_infos_vec.push_back(mac_info);
+ }
+ on_user_change_callback(mac_infos_vec);
+ }
+ };
+ wifi_error status = global_func_table_.wifi_set_radio_mode_change_handler(
+ 0, getIfaceHandle(iface_name), {onAsyncRadioModeChange});
+ if (status != WIFI_SUCCESS) {
+ on_radio_mode_change_internal_callback = nullptr;
+ }
+ return status;
+}
+
+wifi_error WifiLegacyHal::registerSubsystemRestartCallbackHandler(
+ const on_subsystem_restart_callback& on_restart_callback) {
+ if (on_subsystem_restart_internal_callback) {
+ return WIFI_ERROR_NOT_AVAILABLE;
+ }
+ on_subsystem_restart_internal_callback = [on_restart_callback](const char* error) {
+ on_restart_callback(error);
+ };
+ wifi_error status = global_func_table_.wifi_set_subsystem_restart_handler(
+ global_handle_, {onAsyncSubsystemRestart});
+ if (status != WIFI_SUCCESS) {
+ on_subsystem_restart_internal_callback = nullptr;
+ }
+ return status;
+}
+
+wifi_error WifiLegacyHal::startRttRangeRequest(
+ const std::string& iface_name, wifi_request_id id,
+ const std::vector<wifi_rtt_config>& rtt_configs,
+ const on_rtt_results_callback& on_results_user_callback) {
+ if (on_rtt_results_internal_callback) {
+ return WIFI_ERROR_NOT_AVAILABLE;
+ }
+
+ on_rtt_results_internal_callback = [on_results_user_callback](wifi_request_id id,
+ unsigned num_results,
+ wifi_rtt_result* rtt_results[]) {
+ if (num_results > 0 && !rtt_results) {
+ LOG(ERROR) << "Unexpected nullptr in RTT results";
+ return;
+ }
+ std::vector<const wifi_rtt_result*> rtt_results_vec;
+ std::copy_if(rtt_results, rtt_results + num_results, back_inserter(rtt_results_vec),
+ [](wifi_rtt_result* rtt_result) { return rtt_result != nullptr; });
+ on_results_user_callback(id, rtt_results_vec);
+ };
+
+ std::vector<wifi_rtt_config> rtt_configs_internal(rtt_configs);
+ wifi_error status = global_func_table_.wifi_rtt_range_request(
+ id, getIfaceHandle(iface_name), rtt_configs.size(), rtt_configs_internal.data(),
+ {onAsyncRttResults});
+ if (status != WIFI_SUCCESS) {
+ on_rtt_results_internal_callback = nullptr;
+ }
+ return status;
+}
+
+wifi_error WifiLegacyHal::cancelRttRangeRequest(
+ const std::string& iface_name, wifi_request_id id,
+ const std::vector<std::array<uint8_t, 6>>& mac_addrs) {
+ if (!on_rtt_results_internal_callback) {
+ return WIFI_ERROR_NOT_AVAILABLE;
+ }
+ static_assert(sizeof(mac_addr) == sizeof(std::array<uint8_t, 6>), "MAC address size mismatch");
+ // TODO: How do we handle partial cancels (i.e only a subset of enabled mac
+ // addressed are cancelled).
+ std::vector<std::array<uint8_t, 6>> mac_addrs_internal(mac_addrs);
+ wifi_error status = global_func_table_.wifi_rtt_range_cancel(
+ id, getIfaceHandle(iface_name), mac_addrs.size(),
+ reinterpret_cast<mac_addr*>(mac_addrs_internal.data()));
+ // If the request Id is wrong, don't stop the ongoing range request. Any
+ // other error should be treated as the end of rtt ranging.
+ if (status != WIFI_ERROR_INVALID_REQUEST_ID) {
+ on_rtt_results_internal_callback = nullptr;
+ }
+ return status;
+}
+
+std::pair<wifi_error, wifi_rtt_capabilities> WifiLegacyHal::getRttCapabilities(
+ const std::string& iface_name) {
+ wifi_rtt_capabilities rtt_caps;
+ wifi_error status =
+ global_func_table_.wifi_get_rtt_capabilities(getIfaceHandle(iface_name), &rtt_caps);
+ return {status, rtt_caps};
+}
+
+std::pair<wifi_error, wifi_rtt_responder> WifiLegacyHal::getRttResponderInfo(
+ const std::string& iface_name) {
+ wifi_rtt_responder rtt_responder;
+ wifi_error status = global_func_table_.wifi_rtt_get_responder_info(getIfaceHandle(iface_name),
+ &rtt_responder);
+ return {status, rtt_responder};
+}
+
+wifi_error WifiLegacyHal::enableRttResponder(const std::string& iface_name, wifi_request_id id,
+ const wifi_channel_info& channel_hint,
+ uint32_t max_duration_secs,
+ const wifi_rtt_responder& info) {
+ wifi_rtt_responder info_internal(info);
+ return global_func_table_.wifi_enable_responder(id, getIfaceHandle(iface_name), channel_hint,
+ max_duration_secs, &info_internal);
+}
+
+wifi_error WifiLegacyHal::disableRttResponder(const std::string& iface_name, wifi_request_id id) {
+ return global_func_table_.wifi_disable_responder(id, getIfaceHandle(iface_name));
+}
+
+wifi_error WifiLegacyHal::setRttLci(const std::string& iface_name, wifi_request_id id,
+ const wifi_lci_information& info) {
+ wifi_lci_information info_internal(info);
+ return global_func_table_.wifi_set_lci(id, getIfaceHandle(iface_name), &info_internal);
+}
+
+wifi_error WifiLegacyHal::setRttLcr(const std::string& iface_name, wifi_request_id id,
+ const wifi_lcr_information& info) {
+ wifi_lcr_information info_internal(info);
+ return global_func_table_.wifi_set_lcr(id, getIfaceHandle(iface_name), &info_internal);
+}
+
+wifi_error WifiLegacyHal::nanRegisterCallbackHandlers(const std::string& iface_name,
+ const NanCallbackHandlers& user_callbacks) {
+ on_nan_notify_response_user_callback = user_callbacks.on_notify_response;
+ on_nan_event_publish_terminated_user_callback = user_callbacks.on_event_publish_terminated;
+ on_nan_event_match_user_callback = user_callbacks.on_event_match;
+ on_nan_event_match_expired_user_callback = user_callbacks.on_event_match_expired;
+ on_nan_event_subscribe_terminated_user_callback = user_callbacks.on_event_subscribe_terminated;
+ on_nan_event_followup_user_callback = user_callbacks.on_event_followup;
+ on_nan_event_disc_eng_event_user_callback = user_callbacks.on_event_disc_eng_event;
+ on_nan_event_disabled_user_callback = user_callbacks.on_event_disabled;
+ on_nan_event_tca_user_callback = user_callbacks.on_event_tca;
+ on_nan_event_beacon_sdf_payload_user_callback = user_callbacks.on_event_beacon_sdf_payload;
+ on_nan_event_data_path_request_user_callback = user_callbacks.on_event_data_path_request;
+ on_nan_event_data_path_confirm_user_callback = user_callbacks.on_event_data_path_confirm;
+ on_nan_event_data_path_end_user_callback = user_callbacks.on_event_data_path_end;
+ on_nan_event_transmit_follow_up_user_callback = user_callbacks.on_event_transmit_follow_up;
+ on_nan_event_range_request_user_callback = user_callbacks.on_event_range_request;
+ on_nan_event_range_report_user_callback = user_callbacks.on_event_range_report;
+ on_nan_event_schedule_update_user_callback = user_callbacks.on_event_schedule_update;
+
+ return global_func_table_.wifi_nan_register_handler(
+ getIfaceHandle(iface_name),
+ {onAysncNanNotifyResponse, onAysncNanEventPublishReplied,
+ onAysncNanEventPublishTerminated, onAysncNanEventMatch, onAysncNanEventMatchExpired,
+ onAysncNanEventSubscribeTerminated, onAysncNanEventFollowup,
+ onAysncNanEventDiscEngEvent, onAysncNanEventDisabled, onAysncNanEventTca,
+ onAysncNanEventBeaconSdfPayload, onAysncNanEventDataPathRequest,
+ onAysncNanEventDataPathConfirm, onAysncNanEventDataPathEnd,
+ onAysncNanEventTransmitFollowUp, onAysncNanEventRangeRequest,
+ onAysncNanEventRangeReport, onAsyncNanEventScheduleUpdate});
+}
+
+wifi_error WifiLegacyHal::nanEnableRequest(const std::string& iface_name, transaction_id id,
+ const NanEnableRequest& msg) {
+ NanEnableRequest msg_internal(msg);
+ return global_func_table_.wifi_nan_enable_request(id, getIfaceHandle(iface_name),
+ &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanDisableRequest(const std::string& iface_name, transaction_id id) {
+ return global_func_table_.wifi_nan_disable_request(id, getIfaceHandle(iface_name));
+}
+
+wifi_error WifiLegacyHal::nanPublishRequest(const std::string& iface_name, transaction_id id,
+ const NanPublishRequest& msg) {
+ NanPublishRequest msg_internal(msg);
+ return global_func_table_.wifi_nan_publish_request(id, getIfaceHandle(iface_name),
+ &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanPublishCancelRequest(const std::string& iface_name, transaction_id id,
+ const NanPublishCancelRequest& msg) {
+ NanPublishCancelRequest msg_internal(msg);
+ return global_func_table_.wifi_nan_publish_cancel_request(id, getIfaceHandle(iface_name),
+ &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanSubscribeRequest(const std::string& iface_name, transaction_id id,
+ const NanSubscribeRequest& msg) {
+ NanSubscribeRequest msg_internal(msg);
+ return global_func_table_.wifi_nan_subscribe_request(id, getIfaceHandle(iface_name),
+ &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanSubscribeCancelRequest(const std::string& iface_name,
+ transaction_id id,
+ const NanSubscribeCancelRequest& msg) {
+ NanSubscribeCancelRequest msg_internal(msg);
+ return global_func_table_.wifi_nan_subscribe_cancel_request(id, getIfaceHandle(iface_name),
+ &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanTransmitFollowupRequest(const std::string& iface_name,
+ transaction_id id,
+ const NanTransmitFollowupRequest& msg) {
+ NanTransmitFollowupRequest msg_internal(msg);
+ return global_func_table_.wifi_nan_transmit_followup_request(id, getIfaceHandle(iface_name),
+ &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanStatsRequest(const std::string& iface_name, transaction_id id,
+ const NanStatsRequest& msg) {
+ NanStatsRequest msg_internal(msg);
+ return global_func_table_.wifi_nan_stats_request(id, getIfaceHandle(iface_name), &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanConfigRequest(const std::string& iface_name, transaction_id id,
+ const NanConfigRequest& msg) {
+ NanConfigRequest msg_internal(msg);
+ return global_func_table_.wifi_nan_config_request(id, getIfaceHandle(iface_name),
+ &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanTcaRequest(const std::string& iface_name, transaction_id id,
+ const NanTCARequest& msg) {
+ NanTCARequest msg_internal(msg);
+ return global_func_table_.wifi_nan_tca_request(id, getIfaceHandle(iface_name), &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanBeaconSdfPayloadRequest(const std::string& iface_name,
+ transaction_id id,
+ const NanBeaconSdfPayloadRequest& msg) {
+ NanBeaconSdfPayloadRequest msg_internal(msg);
+ return global_func_table_.wifi_nan_beacon_sdf_payload_request(id, getIfaceHandle(iface_name),
+ &msg_internal);
+}
+
+std::pair<wifi_error, NanVersion> WifiLegacyHal::nanGetVersion() {
+ NanVersion version;
+ wifi_error status = global_func_table_.wifi_nan_get_version(global_handle_, &version);
+ return {status, version};
+}
+
+wifi_error WifiLegacyHal::nanGetCapabilities(const std::string& iface_name, transaction_id id) {
+ return global_func_table_.wifi_nan_get_capabilities(id, getIfaceHandle(iface_name));
+}
+
+wifi_error WifiLegacyHal::nanDataInterfaceCreate(const std::string& iface_name, transaction_id id,
+ const std::string& data_iface_name) {
+ return global_func_table_.wifi_nan_data_interface_create(id, getIfaceHandle(iface_name),
+ makeCharVec(data_iface_name).data());
+}
+
+wifi_error WifiLegacyHal::nanDataInterfaceDelete(const std::string& iface_name, transaction_id id,
+ const std::string& data_iface_name) {
+ return global_func_table_.wifi_nan_data_interface_delete(id, getIfaceHandle(iface_name),
+ makeCharVec(data_iface_name).data());
+}
+
+wifi_error WifiLegacyHal::nanDataRequestInitiator(const std::string& iface_name, transaction_id id,
+ const NanDataPathInitiatorRequest& msg) {
+ NanDataPathInitiatorRequest msg_internal(msg);
+ return global_func_table_.wifi_nan_data_request_initiator(id, getIfaceHandle(iface_name),
+ &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanDataIndicationResponse(const std::string& iface_name,
+ transaction_id id,
+ const NanDataPathIndicationResponse& msg) {
+ NanDataPathIndicationResponse msg_internal(msg);
+ return global_func_table_.wifi_nan_data_indication_response(id, getIfaceHandle(iface_name),
+ &msg_internal);
+}
+
+typedef struct {
+ u8 num_ndp_instances;
+ NanDataPathId ndp_instance_id;
+} NanDataPathEndSingleNdpIdRequest;
+
+wifi_error WifiLegacyHal::nanDataEnd(const std::string& iface_name, transaction_id id,
+ uint32_t ndpInstanceId) {
+ NanDataPathEndSingleNdpIdRequest msg;
+ msg.num_ndp_instances = 1;
+ msg.ndp_instance_id = ndpInstanceId;
+ wifi_error status = global_func_table_.wifi_nan_data_end(id, getIfaceHandle(iface_name),
+ (NanDataPathEndRequest*)&msg);
+ return status;
+}
+
+wifi_error WifiLegacyHal::setCountryCode(const std::string& iface_name,
+ std::array<int8_t, 2> code) {
+ std::string code_str(code.data(), code.data() + code.size());
+ return global_func_table_.wifi_set_country_code(getIfaceHandle(iface_name), code_str.c_str());
+}
+
+wifi_error WifiLegacyHal::retrieveIfaceHandles() {
+ wifi_interface_handle* iface_handles = nullptr;
+ int num_iface_handles = 0;
+ wifi_error status =
+ global_func_table_.wifi_get_ifaces(global_handle_, &num_iface_handles, &iface_handles);
+ if (status != WIFI_SUCCESS) {
+ LOG(ERROR) << "Failed to enumerate interface handles";
+ return status;
+ }
+ iface_name_to_handle_.clear();
+ for (int i = 0; i < num_iface_handles; ++i) {
+ std::array<char, IFNAMSIZ> iface_name_arr = {};
+ status = global_func_table_.wifi_get_iface_name(iface_handles[i], iface_name_arr.data(),
+ iface_name_arr.size());
+ if (status != WIFI_SUCCESS) {
+ LOG(WARNING) << "Failed to get interface handle name";
+ continue;
+ }
+ // Assuming the interface name is null terminated since the legacy HAL
+ // API does not return a size.
+ std::string iface_name(iface_name_arr.data());
+ LOG(INFO) << "Adding interface handle for " << iface_name;
+ iface_name_to_handle_[iface_name] = iface_handles[i];
+ }
+ return WIFI_SUCCESS;
+}
+
+wifi_interface_handle WifiLegacyHal::getIfaceHandle(const std::string& iface_name) {
+ const auto iface_handle_iter = iface_name_to_handle_.find(iface_name);
+ if (iface_handle_iter == iface_name_to_handle_.end()) {
+ LOG(ERROR) << "Unknown iface name: " << iface_name;
+ return nullptr;
+ }
+ return iface_handle_iter->second;
+}
+
+void WifiLegacyHal::runEventLoop() {
+ LOG(DEBUG) << "Starting legacy HAL event loop";
+ global_func_table_.wifi_event_loop(global_handle_);
+ const auto lock = hidl_sync_util::acquireGlobalLock();
+ if (!awaiting_event_loop_termination_) {
+ LOG(FATAL) << "Legacy HAL event loop terminated, but HAL was not stopping";
+ }
+ LOG(DEBUG) << "Legacy HAL event loop terminated";
+ awaiting_event_loop_termination_ = false;
+ stop_wait_cv_.notify_one();
+}
+
+std::pair<wifi_error, std::vector<wifi_cached_scan_results>> WifiLegacyHal::getGscanCachedResults(
+ const std::string& iface_name) {
+ std::vector<wifi_cached_scan_results> cached_scan_results;
+ cached_scan_results.resize(kMaxCachedGscanResults);
+ int32_t num_results = 0;
+ wifi_error status = global_func_table_.wifi_get_cached_gscan_results(
+ getIfaceHandle(iface_name), true /* always flush */, cached_scan_results.size(),
+ cached_scan_results.data(), &num_results);
+ CHECK(num_results >= 0 && static_cast<uint32_t>(num_results) <= kMaxCachedGscanResults);
+ cached_scan_results.resize(num_results);
+ // Check for invalid IE lengths in these cached scan results and correct it.
+ for (auto& cached_scan_result : cached_scan_results) {
+ int num_scan_results = cached_scan_result.num_results;
+ for (int i = 0; i < num_scan_results; i++) {
+ auto& scan_result = cached_scan_result.results[i];
+ if (scan_result.ie_length > 0) {
+ LOG(DEBUG) << "Cached scan result has non-zero IE length " << scan_result.ie_length;
+ scan_result.ie_length = 0;
+ }
+ }
+ }
+ return {status, std::move(cached_scan_results)};
+}
+
+wifi_error WifiLegacyHal::createVirtualInterface(const std::string& ifname,
+ wifi_interface_type iftype) {
+ // Create the interface if it doesn't exist. If interface already exist,
+ // Vendor Hal should return WIFI_SUCCESS.
+ wifi_error status = global_func_table_.wifi_virtual_interface_create(global_handle_,
+ ifname.c_str(), iftype);
+ return handleVirtualInterfaceCreateOrDeleteStatus(ifname, status);
+}
+
+wifi_error WifiLegacyHal::deleteVirtualInterface(const std::string& ifname) {
+ // Delete the interface if it was created dynamically.
+ wifi_error status =
+ global_func_table_.wifi_virtual_interface_delete(global_handle_, ifname.c_str());
+ return handleVirtualInterfaceCreateOrDeleteStatus(ifname, status);
+}
+
+wifi_error WifiLegacyHal::handleVirtualInterfaceCreateOrDeleteStatus(const std::string& ifname,
+ wifi_error status) {
+ if (status == WIFI_SUCCESS) {
+ // refresh list of handlers now.
+ status = retrieveIfaceHandles();
+ } else if (status == WIFI_ERROR_NOT_SUPPORTED) {
+ // Vendor hal does not implement this API. Such vendor implementations
+ // are expected to create / delete interface by other means.
+
+ // check if interface exists.
+ if (if_nametoindex(ifname.c_str())) {
+ status = retrieveIfaceHandles();
+ }
+ }
+ return status;
+}
+
+wifi_error WifiLegacyHal::getSupportedIfaceName(uint32_t iface_type, std::string& ifname) {
+ std::array<char, IFNAMSIZ> buffer;
+
+ wifi_error res = global_func_table_.wifi_get_supported_iface_name(
+ global_handle_, (uint32_t)iface_type, buffer.data(), buffer.size());
+ if (res == WIFI_SUCCESS) ifname = buffer.data();
+
+ return res;
+}
+
+wifi_error WifiLegacyHal::multiStaSetPrimaryConnection(const std::string& ifname) {
+ return global_func_table_.wifi_multi_sta_set_primary_connection(global_handle_,
+ getIfaceHandle(ifname));
+}
+
+wifi_error WifiLegacyHal::multiStaSetUseCase(wifi_multi_sta_use_case use_case) {
+ return global_func_table_.wifi_multi_sta_set_use_case(global_handle_, use_case);
+}
+
+wifi_error WifiLegacyHal::setCoexUnsafeChannels(
+ std::vector<wifi_coex_unsafe_channel> unsafe_channels, uint32_t restrictions) {
+ return global_func_table_.wifi_set_coex_unsafe_channels(global_handle_, unsafe_channels.size(),
+ unsafe_channels.data(), restrictions);
+}
+
+wifi_error WifiLegacyHal::setVoipMode(const std::string& iface_name, wifi_voip_mode mode) {
+ return global_func_table_.wifi_set_voip_mode(getIfaceHandle(iface_name), mode);
+}
+
+wifi_error WifiLegacyHal::twtRegisterHandler(const std::string& iface_name,
+ const TwtCallbackHandlers& user_callbacks) {
+ on_twt_event_setup_response_callback = user_callbacks.on_setup_response;
+ on_twt_event_teardown_completion_callback = user_callbacks.on_teardown_completion;
+ on_twt_event_info_frame_received_callback = user_callbacks.on_info_frame_received;
+ on_twt_event_device_notify_callback = user_callbacks.on_device_notify;
+
+ return global_func_table_.wifi_twt_register_handler(
+ getIfaceHandle(iface_name),
+ {onAsyncTwtEventSetupResponse, onAsyncTwtEventTeardownCompletion,
+ onAsyncTwtEventInfoFrameReceived, onAsyncTwtEventDeviceNotify});
+}
+
+std::pair<wifi_error, TwtCapabilitySet> WifiLegacyHal::twtGetCapability(
+ const std::string& iface_name) {
+ TwtCapabilitySet capSet;
+ wifi_error status =
+ global_func_table_.wifi_twt_get_capability(getIfaceHandle(iface_name), &capSet);
+ return {status, capSet};
+}
+
+wifi_error WifiLegacyHal::twtSetupRequest(const std::string& iface_name,
+ const TwtSetupRequest& msg) {
+ TwtSetupRequest msgInternal(msg);
+ return global_func_table_.wifi_twt_setup_request(getIfaceHandle(iface_name), &msgInternal);
+}
+
+wifi_error WifiLegacyHal::twtTearDownRequest(const std::string& iface_name,
+ const TwtTeardownRequest& msg) {
+ TwtTeardownRequest msgInternal(msg);
+ return global_func_table_.wifi_twt_teardown_request(getIfaceHandle(iface_name), &msgInternal);
+}
+
+wifi_error WifiLegacyHal::twtInfoFrameRequest(const std::string& iface_name,
+ const TwtInfoFrameRequest& msg) {
+ TwtInfoFrameRequest msgInternal(msg);
+ return global_func_table_.wifi_twt_info_frame_request(getIfaceHandle(iface_name), &msgInternal);
+}
+
+std::pair<wifi_error, TwtStats> WifiLegacyHal::twtGetStats(const std::string& iface_name,
+ uint8_t configId) {
+ TwtStats stats;
+ wifi_error status =
+ global_func_table_.wifi_twt_get_stats(getIfaceHandle(iface_name), configId, &stats);
+ return {status, stats};
+}
+
+wifi_error WifiLegacyHal::twtClearStats(const std::string& iface_name, uint8_t configId) {
+ return global_func_table_.wifi_twt_clear_stats(getIfaceHandle(iface_name), configId);
+}
+
+wifi_error WifiLegacyHal::setDtimConfig(const std::string& iface_name, uint32_t multiplier) {
+ return global_func_table_.wifi_set_dtim_config(getIfaceHandle(iface_name), multiplier);
+}
+
+std::pair<wifi_error, std::vector<wifi_usable_channel>> WifiLegacyHal::getUsableChannels(
+ uint32_t band_mask, uint32_t iface_mode_mask, uint32_t filter_mask) {
+ std::vector<wifi_usable_channel> channels;
+ channels.resize(kMaxWifiUsableChannels);
+ uint32_t size = 0;
+ wifi_error status = global_func_table_.wifi_get_usable_channels(
+ global_handle_, band_mask, iface_mode_mask, filter_mask, channels.size(), &size,
+ reinterpret_cast<wifi_usable_channel*>(channels.data()));
+ CHECK(size >= 0 && size <= kMaxWifiUsableChannels);
+ channels.resize(size);
+ return {status, std::move(channels)};
+}
+
+wifi_error WifiLegacyHal::triggerSubsystemRestart() {
+ return global_func_table_.wifi_trigger_subsystem_restart(global_handle_);
+}
+
+wifi_error WifiLegacyHal::setIndoorState(bool isIndoor) {
+ return global_func_table_.wifi_set_indoor_state(global_handle_, isIndoor);
+}
+
+std::pair<wifi_error, wifi_radio_combination_matrix*>
+WifiLegacyHal::getSupportedRadioCombinationsMatrix() {
+ char* buffer = new char[kMaxSupportedRadioCombinationsMatrixLength];
+ std::fill(buffer, buffer + kMaxSupportedRadioCombinationsMatrixLength, 0);
+ uint32_t size = 0;
+ wifi_radio_combination_matrix* radio_combination_matrix_ptr =
+ reinterpret_cast<wifi_radio_combination_matrix*>(buffer);
+ wifi_error status = global_func_table_.wifi_get_supported_radio_combinations_matrix(
+ global_handle_, kMaxSupportedRadioCombinationsMatrixLength, &size,
+ radio_combination_matrix_ptr);
+ CHECK(size >= 0 && size <= kMaxSupportedRadioCombinationsMatrixLength);
+ return {status, radio_combination_matrix_ptr};
+}
+
+wifi_error WifiLegacyHal::chreNanRttRequest(const std::string& iface_name, bool enable) {
+ if (enable)
+ return global_func_table_.wifi_nan_rtt_chre_enable_request(0, getIfaceHandle(iface_name),
+ NULL);
+ else
+ return global_func_table_.wifi_nan_rtt_chre_disable_request(0, getIfaceHandle(iface_name));
+}
+
+wifi_error WifiLegacyHal::chreRegisterHandler(const std::string& iface_name,
+ const ChreCallbackHandlers& handler) {
+ if (on_chre_nan_rtt_internal_callback) {
+ return WIFI_ERROR_NOT_AVAILABLE;
+ }
+
+ on_chre_nan_rtt_internal_callback = handler.on_wifi_chre_nan_rtt_state;
+
+ wifi_error status = global_func_table_.wifi_chre_register_handler(getIfaceHandle(iface_name),
+ {onAsyncChreNanRttState});
+ if (status != WIFI_SUCCESS) {
+ on_chre_nan_rtt_internal_callback = nullptr;
+ }
+ return status;
+}
+
+wifi_error WifiLegacyHal::enableWifiTxPowerLimits(const std::string& iface_name, bool enable) {
+ return global_func_table_.wifi_enable_tx_power_limits(getIfaceHandle(iface_name), enable);
+}
+
+wifi_error WifiLegacyHal::getWifiCachedScanResults(
+ const std::string& iface_name, const CachedScanResultsCallbackHandlers& handler) {
+ on_cached_scan_results_internal_callback = handler.on_cached_scan_results;
+
+ wifi_error status = global_func_table_.wifi_get_cached_scan_results(getIfaceHandle(iface_name),
+ {onSyncCachedScanResults});
+
+ on_cached_scan_results_internal_callback = nullptr;
+ return status;
+}
+
+void WifiLegacyHal::invalidate() {
+ global_handle_ = nullptr;
+ iface_name_to_handle_.clear();
+ on_driver_memory_dump_internal_callback = nullptr;
+ on_firmware_memory_dump_internal_callback = nullptr;
+ on_gscan_event_internal_callback = nullptr;
+ on_gscan_full_result_internal_callback = nullptr;
+ on_link_layer_stats_result_internal_callback = nullptr;
+ on_rssi_threshold_breached_internal_callback = nullptr;
+ on_ring_buffer_data_internal_callback = nullptr;
+ on_error_alert_internal_callback = nullptr;
+ on_radio_mode_change_internal_callback = nullptr;
+ on_subsystem_restart_internal_callback = nullptr;
+ on_rtt_results_internal_callback = nullptr;
+ on_nan_notify_response_user_callback = nullptr;
+ on_nan_event_publish_terminated_user_callback = nullptr;
+ on_nan_event_match_user_callback = nullptr;
+ on_nan_event_match_expired_user_callback = nullptr;
+ on_nan_event_subscribe_terminated_user_callback = nullptr;
+ on_nan_event_followup_user_callback = nullptr;
+ on_nan_event_disc_eng_event_user_callback = nullptr;
+ on_nan_event_disabled_user_callback = nullptr;
+ on_nan_event_tca_user_callback = nullptr;
+ on_nan_event_beacon_sdf_payload_user_callback = nullptr;
+ on_nan_event_data_path_request_user_callback = nullptr;
+ on_nan_event_data_path_confirm_user_callback = nullptr;
+ on_nan_event_data_path_end_user_callback = nullptr;
+ on_nan_event_transmit_follow_up_user_callback = nullptr;
+ on_nan_event_range_request_user_callback = nullptr;
+ on_nan_event_range_report_user_callback = nullptr;
+ on_nan_event_schedule_update_user_callback = nullptr;
+ on_twt_event_setup_response_callback = nullptr;
+ on_twt_event_teardown_completion_callback = nullptr;
+ on_twt_event_info_frame_received_callback = nullptr;
+ on_twt_event_device_notify_callback = nullptr;
+ on_chre_nan_rtt_internal_callback = nullptr;
+}
+
+} // namespace legacy_hal
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.6/default/wifi_legacy_hal.h b/wifi/1.6/default/wifi_legacy_hal.h
new file mode 100644
index 0000000..b6bd5ea
--- /dev/null
+++ b/wifi/1.6/default/wifi_legacy_hal.h
@@ -0,0 +1,739 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_LEGACY_HAL_H_
+#define WIFI_LEGACY_HAL_H_
+
+#include <condition_variable>
+#include <functional>
+#include <map>
+#include <thread>
+#include <vector>
+
+#include <hal_legacy/wifi_hal.h>
+#include <wifi_system/interface_tool.h>
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+// This is in a separate namespace to prevent typename conflicts between
+// the legacy HAL types and the HIDL interface types.
+namespace legacy_hal {
+// Import all the types defined inside the legacy HAL header files into this
+// namespace.
+using ::chre_nan_rtt_state;
+using ::frame_info;
+using ::frame_type;
+using ::FRAME_TYPE_80211_MGMT;
+using ::FRAME_TYPE_ETHERNET_II;
+using ::FRAME_TYPE_UNKNOWN;
+using ::fw_roaming_state_t;
+using ::mac_addr;
+using ::NAN_CHANNEL_24G_BAND;
+using ::NAN_CHANNEL_5G_BAND_HIGH;
+using ::NAN_CHANNEL_5G_BAND_LOW;
+using ::NAN_DISABLE_RANGE_REPORT;
+using ::NAN_DO_NOT_USE_SRF;
+using ::NAN_DP_CHANNEL_NOT_REQUESTED;
+using ::NAN_DP_CONFIG_NO_SECURITY;
+using ::NAN_DP_CONFIG_SECURITY;
+using ::NAN_DP_END;
+using ::NAN_DP_FORCE_CHANNEL_SETUP;
+using ::NAN_DP_INITIATOR_RESPONSE;
+using ::NAN_DP_INTERFACE_CREATE;
+using ::NAN_DP_INTERFACE_DELETE;
+using ::NAN_DP_REQUEST_ACCEPT;
+using ::NAN_DP_REQUEST_CHANNEL_SETUP;
+using ::NAN_DP_REQUEST_REJECT;
+using ::NAN_DP_RESPONDER_RESPONSE;
+using ::NAN_GET_CAPABILITIES;
+using ::NAN_MATCH_ALG_MATCH_CONTINUOUS;
+using ::NAN_MATCH_ALG_MATCH_NEVER;
+using ::NAN_MATCH_ALG_MATCH_ONCE;
+using ::NAN_PUBLISH_TYPE_SOLICITED;
+using ::NAN_PUBLISH_TYPE_UNSOLICITED;
+using ::NAN_PUBLISH_TYPE_UNSOLICITED_SOLICITED;
+using ::NAN_RANGING_AUTO_RESPONSE_DISABLE;
+using ::NAN_RANGING_AUTO_RESPONSE_ENABLE;
+using ::NAN_RANGING_DISABLE;
+using ::NAN_RANGING_ENABLE;
+using ::NAN_RESPONSE_BEACON_SDF_PAYLOAD;
+using ::NAN_RESPONSE_CONFIG;
+using ::NAN_RESPONSE_DISABLED;
+using ::NAN_RESPONSE_ENABLED;
+using ::NAN_RESPONSE_ERROR;
+using ::NAN_RESPONSE_PUBLISH;
+using ::NAN_RESPONSE_PUBLISH_CANCEL;
+using ::NAN_RESPONSE_STATS;
+using ::NAN_RESPONSE_SUBSCRIBE;
+using ::NAN_RESPONSE_SUBSCRIBE_CANCEL;
+using ::NAN_RESPONSE_TCA;
+using ::NAN_RESPONSE_TRANSMIT_FOLLOWUP;
+using ::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
+using ::NAN_SECURITY_KEY_INPUT_PMK;
+using ::NAN_SERVICE_ACCEPT_POLICY_ALL;
+using ::NAN_SERVICE_ACCEPT_POLICY_NONE;
+using ::NAN_SRF_ATTR_BLOOM_FILTER;
+using ::NAN_SRF_ATTR_PARTIAL_MAC_ADDR;
+using ::NAN_SRF_INCLUDE_DO_NOT_RESPOND;
+using ::NAN_SRF_INCLUDE_RESPOND;
+using ::NAN_SSI_NOT_REQUIRED_IN_MATCH_IND;
+using ::NAN_SSI_REQUIRED_IN_MATCH_IND;
+using ::NAN_STATUS_ALREADY_ENABLED;
+using ::NAN_STATUS_FOLLOWUP_QUEUE_FULL;
+using ::NAN_STATUS_INTERNAL_FAILURE;
+using ::NAN_STATUS_INVALID_NDP_ID;
+using ::NAN_STATUS_INVALID_PARAM;
+using ::NAN_STATUS_INVALID_PUBLISH_SUBSCRIBE_ID;
+using ::NAN_STATUS_INVALID_REQUESTOR_INSTANCE_ID;
+using ::NAN_STATUS_NAN_NOT_ALLOWED;
+using ::NAN_STATUS_NO_OTA_ACK;
+using ::NAN_STATUS_NO_RESOURCE_AVAILABLE;
+using ::NAN_STATUS_PROTOCOL_FAILURE;
+using ::NAN_STATUS_SUCCESS;
+using ::NAN_STATUS_UNSUPPORTED_CONCURRENCY_NAN_DISABLED;
+using ::NAN_SUBSCRIBE_TYPE_ACTIVE;
+using ::NAN_SUBSCRIBE_TYPE_PASSIVE;
+using ::NAN_TRANSMIT_IN_DW;
+using ::NAN_TRANSMIT_IN_FAW;
+using ::NAN_TX_PRIORITY_HIGH;
+using ::NAN_TX_PRIORITY_NORMAL;
+using ::NAN_TX_TYPE_BROADCAST;
+using ::NAN_TX_TYPE_UNICAST;
+using ::NAN_USE_SRF;
+using ::NanBeaconSdfPayloadInd;
+using ::NanCapabilities;
+using ::NanChannelInfo;
+using ::NanConfigRequest;
+using ::NanDataPathChannelCfg;
+using ::NanDataPathConfirmInd;
+using ::NanDataPathEndInd;
+using ::NanDataPathIndicationResponse;
+using ::NanDataPathInitiatorRequest;
+using ::NanDataPathRequestInd;
+using ::NanDataPathScheduleUpdateInd;
+using ::NanDisabledInd;
+using ::NanDiscEngEventInd;
+using ::NanEnableRequest;
+using ::NanFollowupInd;
+using ::NanMatchAlg;
+using ::NanMatchExpiredInd;
+using ::NanMatchInd;
+using ::NanPublishCancelRequest;
+using ::NanPublishRequest;
+using ::NanPublishTerminatedInd;
+using ::NanPublishType;
+using ::NanRangeReportInd;
+using ::NanRangeRequestInd;
+using ::NanResponseMsg;
+using ::NanSRFType;
+using ::NanStatusType;
+using ::NanSubscribeCancelRequest;
+using ::NanSubscribeRequest;
+using ::NanSubscribeTerminatedInd;
+using ::NanSubscribeType;
+using ::NanTransmitFollowupInd;
+using ::NanTransmitFollowupRequest;
+using ::NanTxType;
+using ::ROAMING_DISABLE;
+using ::ROAMING_ENABLE;
+using ::RTT_PEER_AP;
+using ::RTT_PEER_NAN;
+using ::RTT_PEER_P2P_CLIENT;
+using ::RTT_PEER_P2P_GO;
+using ::RTT_PEER_STA;
+using ::rtt_peer_type;
+using ::RTT_STATUS_ABORTED;
+using ::RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL;
+using ::RTT_STATUS_FAIL_BUSY_TRY_LATER;
+using ::RTT_STATUS_FAIL_FTM_PARAM_OVERRIDE;
+using ::RTT_STATUS_FAIL_INVALID_TS;
+using ::RTT_STATUS_FAIL_NO_CAPABILITY;
+using ::RTT_STATUS_FAIL_NO_RSP;
+using ::RTT_STATUS_FAIL_NOT_SCHEDULED_YET;
+using ::RTT_STATUS_FAIL_PROTOCOL;
+using ::RTT_STATUS_FAIL_REJECTED;
+using ::RTT_STATUS_FAIL_SCHEDULE;
+using ::RTT_STATUS_FAIL_TM_TIMEOUT;
+using ::RTT_STATUS_FAILURE;
+using ::RTT_STATUS_INVALID_REQ;
+using ::RTT_STATUS_NAN_RANGING_CONCURRENCY_NOT_SUPPORTED;
+using ::RTT_STATUS_NAN_RANGING_PROTOCOL_FAILURE;
+using ::RTT_STATUS_NO_WIFI;
+using ::RTT_STATUS_SUCCESS;
+using ::RTT_TYPE_1_SIDED;
+using ::RTT_TYPE_2_SIDED;
+using ::RX_PKT_FATE_DRV_DROP_FILTER;
+using ::RX_PKT_FATE_DRV_DROP_INVALID;
+using ::RX_PKT_FATE_DRV_DROP_NOBUFS;
+using ::RX_PKT_FATE_DRV_DROP_OTHER;
+using ::RX_PKT_FATE_DRV_QUEUED;
+using ::RX_PKT_FATE_FW_DROP_FILTER;
+using ::RX_PKT_FATE_FW_DROP_INVALID;
+using ::RX_PKT_FATE_FW_DROP_NOBUFS;
+using ::RX_PKT_FATE_FW_DROP_OTHER;
+using ::RX_PKT_FATE_FW_QUEUED;
+using ::RX_PKT_FATE_SUCCESS;
+using ::ssid_t;
+using ::transaction_id;
+using ::TX_PKT_FATE_ACKED;
+using ::TX_PKT_FATE_DRV_DROP_INVALID;
+using ::TX_PKT_FATE_DRV_DROP_NOBUFS;
+using ::TX_PKT_FATE_DRV_DROP_OTHER;
+using ::TX_PKT_FATE_DRV_QUEUED;
+using ::TX_PKT_FATE_FW_DROP_INVALID;
+using ::TX_PKT_FATE_FW_DROP_NOBUFS;
+using ::TX_PKT_FATE_FW_DROP_OTHER;
+using ::TX_PKT_FATE_FW_QUEUED;
+using ::TX_PKT_FATE_SENT;
+using ::WIFI_AC_BE;
+using ::WIFI_AC_BK;
+using ::WIFI_AC_VI;
+using ::WIFI_AC_VO;
+using ::WIFI_ANTENNA_1X1;
+using ::WIFI_ANTENNA_2X2;
+using ::WIFI_ANTENNA_3X3;
+using ::WIFI_ANTENNA_4X4;
+using ::WIFI_ANTENNA_UNSPECIFIED;
+using ::wifi_band;
+using ::WIFI_BAND_A;
+using ::WIFI_BAND_A_DFS;
+using ::WIFI_BAND_A_WITH_DFS;
+using ::WIFI_BAND_ABG;
+using ::WIFI_BAND_ABG_WITH_DFS;
+using ::WIFI_BAND_BG;
+using ::WIFI_BAND_UNSPECIFIED;
+using ::wifi_cached_scan_report;
+using ::wifi_cached_scan_results;
+using ::WIFI_CHAN_WIDTH_10;
+using ::WIFI_CHAN_WIDTH_160;
+using ::WIFI_CHAN_WIDTH_20;
+using ::WIFI_CHAN_WIDTH_320;
+using ::WIFI_CHAN_WIDTH_40;
+using ::WIFI_CHAN_WIDTH_5;
+using ::WIFI_CHAN_WIDTH_80;
+using ::WIFI_CHAN_WIDTH_80P80;
+using ::WIFI_CHAN_WIDTH_INVALID;
+using ::wifi_channel_info;
+using ::wifi_channel_stat;
+using ::wifi_channel_width;
+using ::wifi_coex_restriction;
+using ::wifi_coex_unsafe_channel;
+using ::WIFI_DUAL_STA_NON_TRANSIENT_UNBIASED;
+using ::WIFI_DUAL_STA_TRANSIENT_PREFER_PRIMARY;
+using ::wifi_error;
+using ::WIFI_ERROR_BUSY;
+using ::WIFI_ERROR_INVALID_ARGS;
+using ::WIFI_ERROR_INVALID_REQUEST_ID;
+using ::WIFI_ERROR_NONE;
+using ::WIFI_ERROR_NOT_AVAILABLE;
+using ::WIFI_ERROR_NOT_SUPPORTED;
+using ::WIFI_ERROR_OUT_OF_MEMORY;
+using ::WIFI_ERROR_TIMED_OUT;
+using ::WIFI_ERROR_TOO_MANY_REQUESTS;
+using ::WIFI_ERROR_UNINITIALIZED;
+using ::WIFI_ERROR_UNKNOWN;
+using ::wifi_gscan_capabilities;
+using ::wifi_hal_fn;
+using ::wifi_information_element;
+using ::WIFI_INTERFACE_IBSS;
+using ::WIFI_INTERFACE_MESH;
+using ::wifi_interface_mode;
+using ::WIFI_INTERFACE_NAN;
+using ::WIFI_INTERFACE_P2P_CLIENT;
+using ::WIFI_INTERFACE_P2P_GO;
+using ::WIFI_INTERFACE_SOFTAP;
+using ::WIFI_INTERFACE_STA;
+using ::WIFI_INTERFACE_TDLS;
+using ::wifi_interface_type;
+using ::WIFI_INTERFACE_TYPE_AP;
+using ::WIFI_INTERFACE_TYPE_NAN;
+using ::WIFI_INTERFACE_TYPE_P2P;
+using ::WIFI_INTERFACE_TYPE_STA;
+using ::WIFI_INTERFACE_UNKNOWN;
+using ::wifi_latency_mode;
+using ::WIFI_LATENCY_MODE_LOW;
+using ::WIFI_LATENCY_MODE_NORMAL;
+using ::wifi_lci_information;
+using ::wifi_lcr_information;
+using ::WIFI_LOGGER_CONNECT_EVENT_SUPPORTED;
+using ::WIFI_LOGGER_DRIVER_DUMP_SUPPORTED;
+using ::WIFI_LOGGER_MEMORY_DUMP_SUPPORTED;
+using ::WIFI_LOGGER_PACKET_FATE_SUPPORTED;
+using ::WIFI_LOGGER_POWER_EVENT_SUPPORTED;
+using ::WIFI_LOGGER_WAKE_LOCK_SUPPORTED;
+using ::WIFI_MOTION_EXPECTED;
+using ::WIFI_MOTION_NOT_EXPECTED;
+using ::wifi_motion_pattern;
+using ::WIFI_MOTION_UNKNOWN;
+using ::wifi_multi_sta_use_case;
+using ::wifi_power_scenario;
+using ::WIFI_POWER_SCENARIO_ON_BODY_CELL_OFF;
+using ::WIFI_POWER_SCENARIO_ON_BODY_CELL_ON;
+using ::WIFI_POWER_SCENARIO_ON_HEAD_CELL_OFF;
+using ::WIFI_POWER_SCENARIO_ON_HEAD_CELL_ON;
+using ::WIFI_POWER_SCENARIO_VOICE_CALL;
+using ::wifi_radio_combination;
+using ::wifi_radio_combination_matrix;
+using ::wifi_radio_configuration;
+using ::wifi_rate;
+using ::wifi_request_id;
+using ::wifi_ring_buffer_status;
+using ::wifi_roaming_capabilities;
+using ::wifi_roaming_config;
+using ::wifi_rtt_bw;
+using ::WIFI_RTT_BW_10;
+using ::WIFI_RTT_BW_160;
+using ::WIFI_RTT_BW_20;
+using ::WIFI_RTT_BW_320;
+using ::WIFI_RTT_BW_40;
+using ::WIFI_RTT_BW_5;
+using ::WIFI_RTT_BW_80;
+using ::wifi_rtt_capabilities;
+using ::wifi_rtt_config;
+using ::wifi_rtt_preamble;
+using ::WIFI_RTT_PREAMBLE_EHT;
+using ::WIFI_RTT_PREAMBLE_HE;
+using ::WIFI_RTT_PREAMBLE_HT;
+using ::WIFI_RTT_PREAMBLE_LEGACY;
+using ::WIFI_RTT_PREAMBLE_VHT;
+using ::wifi_rtt_responder;
+using ::wifi_rtt_result;
+using ::wifi_rtt_status;
+using ::wifi_rtt_type;
+using ::wifi_rx_packet_fate;
+using ::wifi_rx_report;
+using ::wifi_scan_bucket_spec;
+using ::wifi_scan_cmd_params;
+using ::WIFI_SCAN_FLAG_INTERRUPTED;
+using ::wifi_scan_result;
+using ::WIFI_SUCCESS;
+using ::wifi_tx_packet_fate;
+using ::wifi_tx_report;
+using ::wifi_usable_channel;
+using ::WIFI_USABLE_CHANNEL_FILTER_CELLULAR_COEXISTENCE;
+using ::WIFI_USABLE_CHANNEL_FILTER_CONCURRENCY;
+using ::WLAN_MAC_2_4_BAND;
+using ::WLAN_MAC_5_0_BAND;
+using ::WLAN_MAC_60_0_BAND;
+using ::WLAN_MAC_6_0_BAND;
+
+// APF capabilities supported by the iface.
+struct PacketFilterCapabilities {
+ uint32_t version;
+ uint32_t max_len;
+};
+
+// WARNING: We don't care about the variable sized members of either
+// |wifi_iface_stat|, |wifi_radio_stat| structures. So, using the pragma
+// to escape the compiler warnings regarding this.
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wgnu-variable-sized-type-not-at-end"
+// The |wifi_radio_stat.tx_time_per_levels| stats is provided as a pointer in
+// |wifi_radio_stat| structure in the legacy HAL API. Separate that out
+// into a separate return element to avoid passing pointers around.
+struct LinkLayerRadioStats {
+ wifi_radio_stat stats;
+ std::vector<uint32_t> tx_time_per_levels;
+ std::vector<wifi_channel_stat> channel_stats;
+};
+
+struct WifiPeerInfo {
+ wifi_peer_info peer_info;
+ std::vector<wifi_rate_stat> rate_stats;
+};
+
+struct LinkLayerStats {
+ wifi_iface_stat iface;
+ std::vector<LinkLayerRadioStats> radios;
+ std::vector<WifiPeerInfo> peers;
+};
+#pragma GCC diagnostic pop
+
+// The |WLAN_DRIVER_WAKE_REASON_CNT.cmd_event_wake_cnt| and
+// |WLAN_DRIVER_WAKE_REASON_CNT.driver_fw_local_wake_cnt| stats is provided
+// as a pointer in |WLAN_DRIVER_WAKE_REASON_CNT| structure in the legacy HAL
+// API. Separate that out into a separate return elements to avoid passing
+// pointers around.
+struct WakeReasonStats {
+ WLAN_DRIVER_WAKE_REASON_CNT wake_reason_cnt;
+ std::vector<uint32_t> cmd_event_wake_cnt;
+ std::vector<uint32_t> driver_fw_local_wake_cnt;
+};
+
+// NAN response and event callbacks struct.
+struct NanCallbackHandlers {
+ // NotifyResponse invoked to notify the status of the Request.
+ std::function<void(transaction_id, const NanResponseMsg&)> on_notify_response;
+ // Various event callbacks.
+ std::function<void(const NanPublishTerminatedInd&)> on_event_publish_terminated;
+ std::function<void(const NanMatchInd&)> on_event_match;
+ std::function<void(const NanMatchExpiredInd&)> on_event_match_expired;
+ std::function<void(const NanSubscribeTerminatedInd&)> on_event_subscribe_terminated;
+ std::function<void(const NanFollowupInd&)> on_event_followup;
+ std::function<void(const NanDiscEngEventInd&)> on_event_disc_eng_event;
+ std::function<void(const NanDisabledInd&)> on_event_disabled;
+ std::function<void(const NanTCAInd&)> on_event_tca;
+ std::function<void(const NanBeaconSdfPayloadInd&)> on_event_beacon_sdf_payload;
+ std::function<void(const NanDataPathRequestInd&)> on_event_data_path_request;
+ std::function<void(const NanDataPathConfirmInd&)> on_event_data_path_confirm;
+ std::function<void(const NanDataPathEndInd&)> on_event_data_path_end;
+ std::function<void(const NanTransmitFollowupInd&)> on_event_transmit_follow_up;
+ std::function<void(const NanRangeRequestInd&)> on_event_range_request;
+ std::function<void(const NanRangeReportInd&)> on_event_range_report;
+ std::function<void(const NanDataPathScheduleUpdateInd&)> on_event_schedule_update;
+};
+
+// Full scan results contain IE info and are hence passed by reference, to
+// preserve the variable length array member |ie_data|. Callee must not retain
+// the pointer.
+using on_gscan_full_result_callback =
+ std::function<void(wifi_request_id, const wifi_scan_result*, uint32_t)>;
+// These scan results don't contain any IE info, so no need to pass by
+// reference.
+using on_gscan_results_callback =
+ std::function<void(wifi_request_id, const std::vector<wifi_cached_scan_results>&)>;
+
+// Invoked when the rssi value breaches the thresholds set.
+using on_rssi_threshold_breached_callback =
+ std::function<void(wifi_request_id, std::array<uint8_t, 6>, int8_t)>;
+
+// Callback for RTT range request results.
+// Rtt results contain IE info and are hence passed by reference, to
+// preserve the |LCI| and |LCR| pointers. Callee must not retain
+// the pointer.
+using on_rtt_results_callback =
+ std::function<void(wifi_request_id, const std::vector<const wifi_rtt_result*>&)>;
+
+// Callback for ring buffer data.
+using on_ring_buffer_data_callback = std::function<void(
+ const std::string&, const std::vector<uint8_t>&, const wifi_ring_buffer_status&)>;
+
+// Callback for alerts.
+using on_error_alert_callback = std::function<void(int32_t, const std::vector<uint8_t>&)>;
+
+// Callback for subsystem restart
+using on_subsystem_restart_callback = std::function<void(const std::string&)>;
+
+// Struct for the mac info from the legacy HAL. This is a cleaner version
+// of the |wifi_mac_info| & |wifi_iface_info|.
+typedef struct {
+ std::string name;
+ wifi_channel channel;
+} WifiIfaceInfo;
+
+typedef struct {
+ uint32_t wlan_mac_id;
+ /* BIT MASK of BIT(WLAN_MAC*) as represented by wlan_mac_band */
+ uint32_t mac_band;
+ /* Represents the connected Wi-Fi interfaces associated with each MAC */
+ std::vector<WifiIfaceInfo> iface_infos;
+} WifiMacInfo;
+
+// Callback for radio mode change
+using on_radio_mode_change_callback = std::function<void(const std::vector<WifiMacInfo>&)>;
+
+// TWT response and event callbacks struct.
+struct TwtCallbackHandlers {
+ // Callback for TWT setup response
+ std::function<void(const TwtSetupResponse&)> on_setup_response;
+ // Callback for TWT teardown completion
+ std::function<void(const TwtTeardownCompletion&)> on_teardown_completion;
+ // Callback for TWT info frame received event
+ std::function<void(const TwtInfoFrameReceived&)> on_info_frame_received;
+ // Callback for TWT notification from the device
+ std::function<void(const TwtDeviceNotify&)> on_device_notify;
+};
+
+// CHRE response and event callbacks struct.
+struct ChreCallbackHandlers {
+ // Callback for CHRE NAN RTT
+ std::function<void(chre_nan_rtt_state)> on_wifi_chre_nan_rtt_state;
+};
+
+// Cached Scan Results response and event callbacks struct.
+struct CachedScanResultsCallbackHandlers {
+ // Callback for Cached Scan Results
+ std::function<void(wifi_cached_scan_report*)> on_cached_scan_results;
+};
+
+/**
+ * Class that encapsulates all legacy HAL interactions.
+ * This class manages the lifetime of the event loop thread used by legacy HAL.
+ *
+ * Note: There will only be a single instance of this class created in the Wifi
+ * object and will be valid for the lifetime of the process.
+ */
+class WifiLegacyHal {
+ public:
+ WifiLegacyHal(const std::weak_ptr<wifi_system::InterfaceTool> iface_tool, const wifi_hal_fn& fn,
+ bool is_primary);
+ virtual ~WifiLegacyHal() = default;
+
+ // Initialize the legacy HAL function table.
+ virtual wifi_error initialize();
+ // Start the legacy HAL and the event looper thread.
+ virtual wifi_error start();
+ // Deinitialize the legacy HAL and wait for the event loop thread to exit
+ // using a predefined timeout.
+ virtual wifi_error stop(std::unique_lock<std::recursive_mutex>* lock,
+ const std::function<void()>& on_complete_callback);
+ virtual wifi_error waitForDriverReady();
+ // Checks if legacy HAL has successfully started
+ bool isStarted();
+ // Wrappers for all the functions in the legacy HAL function table.
+ virtual std::pair<wifi_error, std::string> getDriverVersion(const std::string& iface_name);
+ virtual std::pair<wifi_error, std::string> getFirmwareVersion(const std::string& iface_name);
+ std::pair<wifi_error, std::vector<uint8_t>> requestDriverMemoryDump(
+ const std::string& iface_name);
+ std::pair<wifi_error, std::vector<uint8_t>> requestFirmwareMemoryDump(
+ const std::string& iface_name);
+ virtual std::pair<wifi_error, uint64_t> getSupportedFeatureSet(const std::string& iface_name);
+ // APF functions.
+ std::pair<wifi_error, PacketFilterCapabilities> getPacketFilterCapabilities(
+ const std::string& iface_name);
+ wifi_error setPacketFilter(const std::string& iface_name, const std::vector<uint8_t>& program);
+ std::pair<wifi_error, std::vector<uint8_t>> readApfPacketFilterData(
+ const std::string& iface_name);
+ // Gscan functions.
+ std::pair<wifi_error, wifi_gscan_capabilities> getGscanCapabilities(
+ const std::string& iface_name);
+ // These API's provides a simplified interface over the legacy Gscan API's:
+ // a) All scan events from the legacy HAL API other than the
+ // |WIFI_SCAN_FAILED| are treated as notification of results.
+ // This method then retrieves the cached scan results from the legacy
+ // HAL API and triggers the externally provided
+ // |on_results_user_callback| on success.
+ // b) |WIFI_SCAN_FAILED| scan event or failure to retrieve cached scan
+ // results
+ // triggers the externally provided |on_failure_user_callback|.
+ // c) Full scan result event triggers the externally provided
+ // |on_full_result_user_callback|.
+ wifi_error startGscan(const std::string& iface_name, wifi_request_id id,
+ const wifi_scan_cmd_params& params,
+ const std::function<void(wifi_request_id)>& on_failure_callback,
+ const on_gscan_results_callback& on_results_callback,
+ const on_gscan_full_result_callback& on_full_result_callback);
+ wifi_error stopGscan(const std::string& iface_name, wifi_request_id id);
+ std::pair<wifi_error, std::vector<uint32_t>> getValidFrequenciesForBand(
+ const std::string& iface_name, wifi_band band);
+ virtual wifi_error setDfsFlag(const std::string& iface_name, bool dfs_on);
+ // Link layer stats functions.
+ wifi_error enableLinkLayerStats(const std::string& iface_name, bool debug);
+ wifi_error disableLinkLayerStats(const std::string& iface_name);
+ std::pair<wifi_error, LinkLayerStats> getLinkLayerStats(const std::string& iface_name);
+ // RSSI monitor functions.
+ wifi_error startRssiMonitoring(
+ const std::string& iface_name, wifi_request_id id, int8_t max_rssi, int8_t min_rssi,
+ const on_rssi_threshold_breached_callback& on_threshold_breached_callback);
+ wifi_error stopRssiMonitoring(const std::string& iface_name, wifi_request_id id);
+ std::pair<wifi_error, wifi_roaming_capabilities> getRoamingCapabilities(
+ const std::string& iface_name);
+ wifi_error configureRoaming(const std::string& iface_name, const wifi_roaming_config& config);
+ wifi_error enableFirmwareRoaming(const std::string& iface_name, fw_roaming_state_t state);
+ wifi_error configureNdOffload(const std::string& iface_name, bool enable);
+ wifi_error startSendingOffloadedPacket(const std::string& iface_name, uint32_t cmd_id,
+ uint16_t ether_type,
+ const std::vector<uint8_t>& ip_packet_data,
+ const std::array<uint8_t, 6>& src_address,
+ const std::array<uint8_t, 6>& dst_address,
+ uint32_t period_in_ms);
+ wifi_error stopSendingOffloadedPacket(const std::string& iface_name, uint32_t cmd_id);
+ virtual wifi_error selectTxPowerScenario(const std::string& iface_name,
+ wifi_power_scenario scenario);
+ virtual wifi_error resetTxPowerScenario(const std::string& iface_name);
+ wifi_error setLatencyMode(const std::string& iface_name, wifi_latency_mode mode);
+ wifi_error setThermalMitigationMode(wifi_thermal_mode mode, uint32_t completion_window);
+ wifi_error setDscpToAccessCategoryMapping(uint32_t start, uint32_t end,
+ uint32_t access_category);
+ wifi_error resetDscpToAccessCategoryMapping();
+ // Logger/debug functions.
+ std::pair<wifi_error, uint32_t> getLoggerSupportedFeatureSet(const std::string& iface_name);
+ wifi_error startPktFateMonitoring(const std::string& iface_name);
+ std::pair<wifi_error, std::vector<wifi_tx_report>> getTxPktFates(const std::string& iface_name);
+ std::pair<wifi_error, std::vector<wifi_rx_report>> getRxPktFates(const std::string& iface_name);
+ std::pair<wifi_error, WakeReasonStats> getWakeReasonStats(const std::string& iface_name);
+ wifi_error registerRingBufferCallbackHandler(
+ const std::string& iface_name, const on_ring_buffer_data_callback& on_data_callback);
+ wifi_error deregisterRingBufferCallbackHandler(const std::string& iface_name);
+ virtual wifi_error registerSubsystemRestartCallbackHandler(
+ const on_subsystem_restart_callback& on_restart_callback);
+ std::pair<wifi_error, std::vector<wifi_ring_buffer_status>> getRingBuffersStatus(
+ const std::string& iface_name);
+ wifi_error startRingBufferLogging(const std::string& iface_name, const std::string& ring_name,
+ uint32_t verbose_level, uint32_t max_interval_sec,
+ uint32_t min_data_size);
+ wifi_error getRingBufferData(const std::string& iface_name, const std::string& ring_name);
+ wifi_error registerErrorAlertCallbackHandler(const std::string& iface_name,
+ const on_error_alert_callback& on_alert_callback);
+ wifi_error deregisterErrorAlertCallbackHandler(const std::string& iface_name);
+ // Radio mode functions.
+ virtual wifi_error registerRadioModeChangeCallbackHandler(
+ const std::string& iface_name,
+ const on_radio_mode_change_callback& on_user_change_callback);
+ // RTT functions.
+ wifi_error startRttRangeRequest(const std::string& iface_name, wifi_request_id id,
+ const std::vector<wifi_rtt_config>& rtt_configs,
+ const on_rtt_results_callback& on_results_callback);
+ wifi_error cancelRttRangeRequest(const std::string& iface_name, wifi_request_id id,
+ const std::vector<std::array<uint8_t, 6>>& mac_addrs);
+ std::pair<wifi_error, wifi_rtt_capabilities> getRttCapabilities(const std::string& iface_name);
+ std::pair<wifi_error, wifi_rtt_responder> getRttResponderInfo(const std::string& iface_name);
+ wifi_error enableRttResponder(const std::string& iface_name, wifi_request_id id,
+ const wifi_channel_info& channel_hint, uint32_t max_duration_secs,
+ const wifi_rtt_responder& info);
+ wifi_error disableRttResponder(const std::string& iface_name, wifi_request_id id);
+ wifi_error setRttLci(const std::string& iface_name, wifi_request_id id,
+ const wifi_lci_information& info);
+ wifi_error setRttLcr(const std::string& iface_name, wifi_request_id id,
+ const wifi_lcr_information& info);
+ // NAN functions.
+ virtual wifi_error nanRegisterCallbackHandlers(const std::string& iface_name,
+ const NanCallbackHandlers& callbacks);
+ wifi_error nanEnableRequest(const std::string& iface_name, transaction_id id,
+ const NanEnableRequest& msg);
+ virtual wifi_error nanDisableRequest(const std::string& iface_name, transaction_id id);
+ wifi_error nanPublishRequest(const std::string& iface_name, transaction_id id,
+ const NanPublishRequest& msg);
+ wifi_error nanPublishCancelRequest(const std::string& iface_name, transaction_id id,
+ const NanPublishCancelRequest& msg);
+ wifi_error nanSubscribeRequest(const std::string& iface_name, transaction_id id,
+ const NanSubscribeRequest& msg);
+ wifi_error nanSubscribeCancelRequest(const std::string& iface_name, transaction_id id,
+ const NanSubscribeCancelRequest& msg);
+ wifi_error nanTransmitFollowupRequest(const std::string& iface_name, transaction_id id,
+ const NanTransmitFollowupRequest& msg);
+ wifi_error nanStatsRequest(const std::string& iface_name, transaction_id id,
+ const NanStatsRequest& msg);
+ wifi_error nanConfigRequest(const std::string& iface_name, transaction_id id,
+ const NanConfigRequest& msg);
+ wifi_error nanTcaRequest(const std::string& iface_name, transaction_id id,
+ const NanTCARequest& msg);
+ wifi_error nanBeaconSdfPayloadRequest(const std::string& iface_name, transaction_id id,
+ const NanBeaconSdfPayloadRequest& msg);
+ std::pair<wifi_error, NanVersion> nanGetVersion();
+ wifi_error nanGetCapabilities(const std::string& iface_name, transaction_id id);
+ wifi_error nanDataInterfaceCreate(const std::string& iface_name, transaction_id id,
+ const std::string& data_iface_name);
+ virtual wifi_error nanDataInterfaceDelete(const std::string& iface_name, transaction_id id,
+ const std::string& data_iface_name);
+ wifi_error nanDataRequestInitiator(const std::string& iface_name, transaction_id id,
+ const NanDataPathInitiatorRequest& msg);
+ wifi_error nanDataIndicationResponse(const std::string& iface_name, transaction_id id,
+ const NanDataPathIndicationResponse& msg);
+ wifi_error nanDataEnd(const std::string& iface_name, transaction_id id, uint32_t ndpInstanceId);
+ // AP functions.
+ wifi_error setCountryCode(const std::string& iface_name, std::array<int8_t, 2> code);
+
+ // interface functions.
+ virtual wifi_error createVirtualInterface(const std::string& ifname,
+ wifi_interface_type iftype);
+ virtual wifi_error deleteVirtualInterface(const std::string& ifname);
+ virtual wifi_error getSupportedIfaceName(uint32_t iface_type, std::string& ifname);
+
+ // STA + STA functions
+ virtual wifi_error multiStaSetPrimaryConnection(const std::string& ifname);
+ virtual wifi_error multiStaSetUseCase(wifi_multi_sta_use_case use_case);
+
+ // Coex functions.
+ virtual wifi_error setCoexUnsafeChannels(std::vector<wifi_coex_unsafe_channel> unsafe_channels,
+ uint32_t restrictions);
+
+ wifi_error setVoipMode(const std::string& iface_name, wifi_voip_mode mode);
+
+ wifi_error twtRegisterHandler(const std::string& iface_name,
+ const TwtCallbackHandlers& handler);
+
+ std::pair<wifi_error, TwtCapabilitySet> twtGetCapability(const std::string& iface_name);
+
+ wifi_error twtSetupRequest(const std::string& iface_name, const TwtSetupRequest& msg);
+
+ wifi_error twtTearDownRequest(const std::string& iface_name, const TwtTeardownRequest& msg);
+
+ wifi_error twtInfoFrameRequest(const std::string& iface_name, const TwtInfoFrameRequest& msg);
+
+ std::pair<wifi_error, TwtStats> twtGetStats(const std::string& iface_name, uint8_t configId);
+
+ wifi_error twtClearStats(const std::string& iface_name, uint8_t configId);
+
+ wifi_error setDtimConfig(const std::string& iface_name, uint32_t multiplier);
+
+ // Retrieve the list of usable channels in the requested bands
+ // for the requested modes
+ std::pair<wifi_error, std::vector<wifi_usable_channel>> getUsableChannels(
+ uint32_t band_mask, uint32_t iface_mode_mask, uint32_t filter_mask);
+
+ wifi_error triggerSubsystemRestart();
+
+ wifi_error setIndoorState(bool isIndoor);
+
+ std::pair<wifi_error, wifi_radio_combination_matrix*> getSupportedRadioCombinationsMatrix();
+
+ // CHRE NAN RTT function
+ wifi_error chreNanRttRequest(const std::string& iface_name, bool enable);
+
+ wifi_error chreRegisterHandler(const std::string& iface_name,
+ const ChreCallbackHandlers& handler);
+
+ wifi_error enableWifiTxPowerLimits(const std::string& iface_name, bool enable);
+ wifi_error getWifiCachedScanResults(const std::string& iface_name,
+ const CachedScanResultsCallbackHandlers& handler);
+
+ private:
+ // Retrieve interface handles for all the available interfaces.
+ wifi_error retrieveIfaceHandles();
+ wifi_interface_handle getIfaceHandle(const std::string& iface_name);
+ // Run the legacy HAL event loop thread.
+ void runEventLoop();
+ // Retrieve the cached gscan results to pass the results back to the
+ // external callbacks.
+ std::pair<wifi_error, std::vector<wifi_cached_scan_results>> getGscanCachedResults(
+ const std::string& iface_name);
+ void invalidate();
+ // Handles wifi (error) status of Virtual interface create/delete
+ wifi_error handleVirtualInterfaceCreateOrDeleteStatus(const std::string& ifname,
+ wifi_error status);
+
+ // Global function table of legacy HAL.
+ wifi_hal_fn global_func_table_;
+ // Opaque handle to be used for all global operations.
+ wifi_handle global_handle_;
+ // Map of interface name to handle that is to be used for all interface
+ // specific operations.
+ std::map<std::string, wifi_interface_handle> iface_name_to_handle_;
+ // Flag to indicate if we have initiated the cleanup of legacy HAL.
+ std::atomic<bool> awaiting_event_loop_termination_;
+ std::condition_variable_any stop_wait_cv_;
+ // Flag to indicate if the legacy HAL has been started.
+ bool is_started_;
+ std::weak_ptr<wifi_system::InterfaceTool> iface_tool_;
+ // flag to indicate if this HAL is for the primary chip. This is used
+ // in order to avoid some hard-coded behavior used with older HALs,
+ // such as bring wlan0 interface up/down on start/stop HAL.
+ // it may be removed once vendor HALs are updated.
+ bool is_primary_;
+};
+
+} // namespace legacy_hal
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+
+#endif // WIFI_LEGACY_HAL_H_
diff --git a/wifi/1.6/default/wifi_legacy_hal_factory.cpp b/wifi/1.6/default/wifi_legacy_hal_factory.cpp
new file mode 100644
index 0000000..147bf4d
--- /dev/null
+++ b/wifi/1.6/default/wifi_legacy_hal_factory.cpp
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dirent.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <android-base/logging.h>
+#include <dlfcn.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/xmlmemory.h>
+
+#include "wifi_legacy_hal_factory.h"
+#include "wifi_legacy_hal_stubs.h"
+
+namespace {
+static constexpr char kVendorHalsDescPath[] = "/vendor/etc/wifi/vendor_hals";
+static constexpr char kVendorHalsDescExt[] = ".xml";
+static constexpr uint32_t kVendorHalsDescVersion = 1;
+
+bool isDirectory(struct dirent* entryPtr) {
+ bool isDir = false;
+ if (entryPtr->d_type != DT_UNKNOWN && entryPtr->d_type != DT_LNK) {
+ isDir = (entryPtr->d_type == DT_DIR);
+ } else {
+ struct stat entryStat;
+ stat(entryPtr->d_name, &entryStat);
+ isDir = S_ISDIR(entryStat.st_mode);
+ }
+ return isDir;
+}
+
+bool isFileExtension(const char* name, const char* ext) {
+ if (name == NULL) return false;
+ if (ext == NULL) return false;
+
+ size_t extLen = strlen(ext);
+ size_t nameLen = strlen(name);
+
+ if (extLen > nameLen) return false;
+
+ if (strncmp(name + nameLen - extLen, ext, extLen) != 0) return false;
+
+ return true;
+}
+}; // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace legacy_hal {
+
+WifiLegacyHalFactory::WifiLegacyHalFactory(
+ const std::weak_ptr<wifi_system::InterfaceTool> iface_tool)
+ : iface_tool_(iface_tool) {}
+
+std::vector<std::shared_ptr<WifiLegacyHal>> WifiLegacyHalFactory::getHals() {
+ if (legacy_hals_.empty()) {
+ if (!initVendorHalDescriptorFromLinked()) initVendorHalsDescriptorList();
+ for (auto& desc : descs_) {
+ std::shared_ptr<WifiLegacyHal> hal =
+ std::make_shared<WifiLegacyHal>(iface_tool_, desc.fn, desc.primary);
+ legacy_hals_.push_back(hal);
+ }
+ }
+
+ return legacy_hals_;
+}
+
+bool WifiLegacyHalFactory::initVendorHalDescriptorFromLinked() {
+ wifi_hal_lib_desc desc;
+
+ if (!initLinkedHalFunctionTable(&desc.fn)) return false;
+
+ desc.primary = true;
+ desc.handle = NULL;
+ descs_.push_back(desc);
+ return true;
+}
+
+bool WifiLegacyHalFactory::initLinkedHalFunctionTable(wifi_hal_fn* hal_fn) {
+ init_wifi_vendor_hal_func_table_t initfn;
+
+ initfn = (init_wifi_vendor_hal_func_table_t)dlsym(RTLD_DEFAULT,
+ "init_wifi_vendor_hal_func_table");
+ if (!initfn) {
+ LOG(INFO) << "no vendor HAL library linked, will try dynamic load";
+ return false;
+ }
+
+ if (!initHalFuncTableWithStubs(hal_fn)) {
+ LOG(ERROR) << "Can not initialize the basic function pointer table";
+ return false;
+ }
+
+ if (initfn(hal_fn) != WIFI_SUCCESS) {
+ LOG(ERROR) << "Can not initialize the vendor function pointer table";
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * Overall structure of the HAL descriptor XML schema
+ *
+ * <?xml version="1.0" encoding="UTF-8"?>
+ * <WifiVendorHal version="1">
+ * <path>/vendor/lib64/libwifi-hal-qcom.so</path>
+ * <primary>1</primary>
+ * </WifiVendorHal>
+ */
+void WifiLegacyHalFactory::initVendorHalsDescriptorList() {
+ xmlDocPtr xml;
+ xmlNodePtr node, cnode;
+ char* version;
+ std::string path;
+ xmlChar* value;
+ wifi_hal_lib_desc desc;
+
+ LOG(INFO) << "processing vendor HALs descriptions in " << kVendorHalsDescPath;
+ DIR* dirPtr = ::opendir(kVendorHalsDescPath);
+ if (dirPtr == NULL) {
+ LOG(ERROR) << "failed to open " << kVendorHalsDescPath;
+ return;
+ }
+ for (struct dirent* entryPtr = ::readdir(dirPtr); entryPtr != NULL;
+ entryPtr = ::readdir(dirPtr)) {
+ if (isDirectory(entryPtr)) continue;
+
+ if (!isFileExtension(entryPtr->d_name, kVendorHalsDescExt))
+ continue; // only process .xml files
+
+ LOG(INFO) << "processing config file: " << entryPtr->d_name;
+
+ std::string fullPath(kVendorHalsDescPath);
+ fullPath.append("/");
+ fullPath.append(entryPtr->d_name);
+ xml = xmlReadFile(fullPath.c_str(), "UTF-8", XML_PARSE_RECOVER);
+ if (!xml) {
+ LOG(ERROR) << "failed to parse: " << entryPtr->d_name << " skipping...";
+ continue;
+ }
+ node = xmlDocGetRootElement(xml);
+ if (!node) {
+ LOG(ERROR) << "empty config file: " << entryPtr->d_name << " skipping...";
+ goto skip;
+ }
+ if (xmlStrcmp(node->name, BAD_CAST "WifiVendorHal")) {
+ LOG(ERROR) << "bad config, root element not WifiVendorHal: " << entryPtr->d_name
+ << " skipping...";
+ goto skip;
+ }
+ version = (char*)xmlGetProp(node, BAD_CAST "version");
+ if (!version || strtoul(version, NULL, 0) != kVendorHalsDescVersion) {
+ LOG(ERROR) << "conf file: " << entryPtr->d_name
+ << "must have version: " << kVendorHalsDescVersion << ", skipping...";
+ goto skip;
+ }
+ cnode = node->children;
+ path.clear();
+ desc.primary = false;
+ while (cnode) {
+ if (!xmlStrcmp(cnode->name, BAD_CAST "path")) {
+ value = xmlNodeListGetString(xml, cnode->children, 1);
+ if (value) path = (char*)value;
+ xmlFree(value);
+ } else if (!xmlStrcmp(cnode->name, BAD_CAST "primary")) {
+ value = xmlNodeListGetString(xml, cnode->children, 1);
+ desc.primary = !xmlStrcmp(value, BAD_CAST "1");
+ xmlFree(value);
+ }
+ cnode = cnode->next;
+ }
+ if (path.empty()) {
+ LOG(ERROR) << "hal library path not provided in: " << entryPtr->d_name
+ << ", skipping...";
+ goto skip;
+ }
+ if (loadVendorHalLib(path, desc)) {
+ if (desc.primary)
+ descs_.insert(descs_.begin(), desc);
+ else
+ descs_.push_back(desc);
+ }
+ skip:
+ xmlFreeDoc(xml);
+ }
+ ::closedir(dirPtr);
+}
+
+bool WifiLegacyHalFactory::loadVendorHalLib(const std::string& path, wifi_hal_lib_desc& desc) {
+ void* h = dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL);
+ init_wifi_vendor_hal_func_table_t initfn;
+ wifi_error res;
+
+ if (!h) {
+ LOG(ERROR) << "failed to open vendor hal library: " << path;
+ return false;
+ }
+ initfn = (init_wifi_vendor_hal_func_table_t)dlsym(h, "init_wifi_vendor_hal_func_table");
+ if (!initfn) {
+ LOG(ERROR) << "init_wifi_vendor_hal_func_table not found in: " << path;
+ goto out_err;
+ }
+
+ if (!initHalFuncTableWithStubs(&desc.fn)) {
+ LOG(ERROR) << "Can not initialize the basic function pointer table";
+ goto out_err;
+ }
+ res = initfn(&desc.fn);
+ if (res != WIFI_SUCCESS) {
+ LOG(ERROR) << "failed to initialize the vendor func table in: " << path
+ << " error: " << res;
+ goto out_err;
+ }
+
+ res = desc.fn.wifi_early_initialize();
+ // vendor HALs which do not implement early_initialize will return
+ // WIFI_ERROR_NOT_SUPPORTED, treat this as success.
+ if (res != WIFI_SUCCESS && res != WIFI_ERROR_NOT_SUPPORTED) {
+ LOG(ERROR) << "early initialization failed in: " << path << " error: " << res;
+ goto out_err;
+ }
+
+ desc.handle = h;
+ return true;
+out_err:
+ dlclose(h);
+ return false;
+}
+
+} // namespace legacy_hal
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.6/default/wifi_legacy_hal_factory.h b/wifi/1.6/default/wifi_legacy_hal_factory.h
new file mode 100644
index 0000000..9f4423e
--- /dev/null
+++ b/wifi/1.6/default/wifi_legacy_hal_factory.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_LEGACY_HAL_FACTORY_H_
+#define WIFI_LEGACY_HAL_FACTORY_H_
+
+#include <wifi_system/interface_tool.h>
+
+#include "wifi_legacy_hal.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+// This is in a separate namespace to prevent typename conflicts between
+// the legacy HAL types and the HIDL interface types.
+namespace legacy_hal {
+/**
+ * Class that creates WifiLegacyHal objects for vendor HALs in the system.
+ */
+class WifiLegacyHalFactory {
+ public:
+ WifiLegacyHalFactory(const std::weak_ptr<wifi_system::InterfaceTool> iface_tool);
+ virtual ~WifiLegacyHalFactory() = default;
+
+ std::vector<std::shared_ptr<WifiLegacyHal>> getHals();
+
+ private:
+ typedef struct {
+ wifi_hal_fn fn;
+ bool primary;
+ void* handle;
+ } wifi_hal_lib_desc;
+
+ bool initVendorHalDescriptorFromLinked();
+ void initVendorHalsDescriptorList();
+ bool initLinkedHalFunctionTable(wifi_hal_fn* hal_fn);
+ bool loadVendorHalLib(const std::string& path, wifi_hal_lib_desc& desc);
+
+ std::weak_ptr<wifi_system::InterfaceTool> iface_tool_;
+ std::vector<wifi_hal_lib_desc> descs_;
+ std::vector<std::shared_ptr<WifiLegacyHal>> legacy_hals_;
+};
+
+} // namespace legacy_hal
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+
+#endif // WIFI_LEGACY_HAL_FACTORY_H_
diff --git a/wifi/1.6/default/wifi_legacy_hal_stubs.cpp b/wifi/1.6/default/wifi_legacy_hal_stubs.cpp
new file mode 100644
index 0000000..8f8527a
--- /dev/null
+++ b/wifi/1.6/default/wifi_legacy_hal_stubs.cpp
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "wifi_legacy_hal_stubs.h"
+
+// TODO: Remove these stubs from HalTool in libwifi-system.
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace legacy_hal {
+template <typename>
+struct stubFunction;
+
+template <typename R, typename... Args>
+struct stubFunction<R (*)(Args...)> {
+ static constexpr R invoke(Args...) { return WIFI_ERROR_NOT_SUPPORTED; }
+};
+template <typename... Args>
+struct stubFunction<void (*)(Args...)> {
+ static constexpr void invoke(Args...) {}
+};
+
+template <typename T>
+void populateStubFor(T* val) {
+ *val = &stubFunction<T>::invoke;
+}
+
+bool initHalFuncTableWithStubs(wifi_hal_fn* hal_fn) {
+ if (hal_fn == nullptr) {
+ return false;
+ }
+ populateStubFor(&hal_fn->wifi_initialize);
+ populateStubFor(&hal_fn->wifi_wait_for_driver_ready);
+ populateStubFor(&hal_fn->wifi_cleanup);
+ populateStubFor(&hal_fn->wifi_event_loop);
+ populateStubFor(&hal_fn->wifi_get_error_info);
+ populateStubFor(&hal_fn->wifi_get_supported_feature_set);
+ populateStubFor(&hal_fn->wifi_get_concurrency_matrix);
+ populateStubFor(&hal_fn->wifi_set_scanning_mac_oui);
+ populateStubFor(&hal_fn->wifi_get_supported_channels);
+ populateStubFor(&hal_fn->wifi_is_epr_supported);
+ populateStubFor(&hal_fn->wifi_get_ifaces);
+ populateStubFor(&hal_fn->wifi_get_iface_name);
+ populateStubFor(&hal_fn->wifi_set_iface_event_handler);
+ populateStubFor(&hal_fn->wifi_reset_iface_event_handler);
+ populateStubFor(&hal_fn->wifi_start_gscan);
+ populateStubFor(&hal_fn->wifi_stop_gscan);
+ populateStubFor(&hal_fn->wifi_get_cached_gscan_results);
+ populateStubFor(&hal_fn->wifi_set_bssid_hotlist);
+ populateStubFor(&hal_fn->wifi_reset_bssid_hotlist);
+ populateStubFor(&hal_fn->wifi_set_significant_change_handler);
+ populateStubFor(&hal_fn->wifi_reset_significant_change_handler);
+ populateStubFor(&hal_fn->wifi_get_gscan_capabilities);
+ populateStubFor(&hal_fn->wifi_set_link_stats);
+ populateStubFor(&hal_fn->wifi_get_link_stats);
+ populateStubFor(&hal_fn->wifi_clear_link_stats);
+ populateStubFor(&hal_fn->wifi_get_valid_channels);
+ populateStubFor(&hal_fn->wifi_rtt_range_request);
+ populateStubFor(&hal_fn->wifi_rtt_range_cancel);
+ populateStubFor(&hal_fn->wifi_get_rtt_capabilities);
+ populateStubFor(&hal_fn->wifi_rtt_get_responder_info);
+ populateStubFor(&hal_fn->wifi_enable_responder);
+ populateStubFor(&hal_fn->wifi_disable_responder);
+ populateStubFor(&hal_fn->wifi_set_nodfs_flag);
+ populateStubFor(&hal_fn->wifi_start_logging);
+ populateStubFor(&hal_fn->wifi_set_epno_list);
+ populateStubFor(&hal_fn->wifi_reset_epno_list);
+ populateStubFor(&hal_fn->wifi_set_country_code);
+ populateStubFor(&hal_fn->wifi_get_firmware_memory_dump);
+ populateStubFor(&hal_fn->wifi_set_log_handler);
+ populateStubFor(&hal_fn->wifi_reset_log_handler);
+ populateStubFor(&hal_fn->wifi_set_alert_handler);
+ populateStubFor(&hal_fn->wifi_reset_alert_handler);
+ populateStubFor(&hal_fn->wifi_get_firmware_version);
+ populateStubFor(&hal_fn->wifi_get_ring_buffers_status);
+ populateStubFor(&hal_fn->wifi_get_logger_supported_feature_set);
+ populateStubFor(&hal_fn->wifi_get_ring_data);
+ populateStubFor(&hal_fn->wifi_enable_tdls);
+ populateStubFor(&hal_fn->wifi_disable_tdls);
+ populateStubFor(&hal_fn->wifi_get_tdls_status);
+ populateStubFor(&hal_fn->wifi_get_tdls_capabilities);
+ populateStubFor(&hal_fn->wifi_get_driver_version);
+ populateStubFor(&hal_fn->wifi_set_passpoint_list);
+ populateStubFor(&hal_fn->wifi_reset_passpoint_list);
+ populateStubFor(&hal_fn->wifi_set_lci);
+ populateStubFor(&hal_fn->wifi_set_lcr);
+ populateStubFor(&hal_fn->wifi_start_sending_offloaded_packet);
+ populateStubFor(&hal_fn->wifi_stop_sending_offloaded_packet);
+ populateStubFor(&hal_fn->wifi_start_rssi_monitoring);
+ populateStubFor(&hal_fn->wifi_stop_rssi_monitoring);
+ populateStubFor(&hal_fn->wifi_get_wake_reason_stats);
+ populateStubFor(&hal_fn->wifi_configure_nd_offload);
+ populateStubFor(&hal_fn->wifi_get_driver_memory_dump);
+ populateStubFor(&hal_fn->wifi_start_pkt_fate_monitoring);
+ populateStubFor(&hal_fn->wifi_get_tx_pkt_fates);
+ populateStubFor(&hal_fn->wifi_get_rx_pkt_fates);
+ populateStubFor(&hal_fn->wifi_nan_enable_request);
+ populateStubFor(&hal_fn->wifi_nan_disable_request);
+ populateStubFor(&hal_fn->wifi_nan_publish_request);
+ populateStubFor(&hal_fn->wifi_nan_publish_cancel_request);
+ populateStubFor(&hal_fn->wifi_nan_subscribe_request);
+ populateStubFor(&hal_fn->wifi_nan_subscribe_cancel_request);
+ populateStubFor(&hal_fn->wifi_nan_transmit_followup_request);
+ populateStubFor(&hal_fn->wifi_nan_stats_request);
+ populateStubFor(&hal_fn->wifi_nan_config_request);
+ populateStubFor(&hal_fn->wifi_nan_tca_request);
+ populateStubFor(&hal_fn->wifi_nan_beacon_sdf_payload_request);
+ populateStubFor(&hal_fn->wifi_nan_register_handler);
+ populateStubFor(&hal_fn->wifi_nan_get_version);
+ populateStubFor(&hal_fn->wifi_nan_get_capabilities);
+ populateStubFor(&hal_fn->wifi_nan_data_interface_create);
+ populateStubFor(&hal_fn->wifi_nan_data_interface_delete);
+ populateStubFor(&hal_fn->wifi_nan_data_request_initiator);
+ populateStubFor(&hal_fn->wifi_nan_data_indication_response);
+ populateStubFor(&hal_fn->wifi_nan_data_end);
+ populateStubFor(&hal_fn->wifi_get_packet_filter_capabilities);
+ populateStubFor(&hal_fn->wifi_set_packet_filter);
+ populateStubFor(&hal_fn->wifi_read_packet_filter);
+ populateStubFor(&hal_fn->wifi_get_roaming_capabilities);
+ populateStubFor(&hal_fn->wifi_enable_firmware_roaming);
+ populateStubFor(&hal_fn->wifi_configure_roaming);
+ populateStubFor(&hal_fn->wifi_select_tx_power_scenario);
+ populateStubFor(&hal_fn->wifi_reset_tx_power_scenario);
+ populateStubFor(&hal_fn->wifi_set_radio_mode_change_handler);
+ populateStubFor(&hal_fn->wifi_set_latency_mode);
+ populateStubFor(&hal_fn->wifi_set_thermal_mitigation_mode);
+ populateStubFor(&hal_fn->wifi_virtual_interface_create);
+ populateStubFor(&hal_fn->wifi_virtual_interface_delete);
+ populateStubFor(&hal_fn->wifi_map_dscp_access_category);
+ populateStubFor(&hal_fn->wifi_reset_dscp_mapping);
+ populateStubFor(&hal_fn->wifi_set_subsystem_restart_handler);
+ populateStubFor(&hal_fn->wifi_get_supported_iface_name);
+ populateStubFor(&hal_fn->wifi_early_initialize);
+ populateStubFor(&hal_fn->wifi_get_chip_feature_set);
+ populateStubFor(&hal_fn->wifi_multi_sta_set_primary_connection);
+ populateStubFor(&hal_fn->wifi_multi_sta_set_use_case);
+ populateStubFor(&hal_fn->wifi_set_coex_unsafe_channels);
+ populateStubFor(&hal_fn->wifi_set_voip_mode);
+ populateStubFor(&hal_fn->wifi_twt_register_handler);
+ populateStubFor(&hal_fn->wifi_twt_get_capability);
+ populateStubFor(&hal_fn->wifi_twt_setup_request);
+ populateStubFor(&hal_fn->wifi_twt_teardown_request);
+ populateStubFor(&hal_fn->wifi_twt_info_frame_request);
+ populateStubFor(&hal_fn->wifi_twt_get_stats);
+ populateStubFor(&hal_fn->wifi_twt_clear_stats);
+ populateStubFor(&hal_fn->wifi_set_dtim_config);
+ populateStubFor(&hal_fn->wifi_get_usable_channels);
+ populateStubFor(&hal_fn->wifi_trigger_subsystem_restart);
+ populateStubFor(&hal_fn->wifi_set_indoor_state);
+ populateStubFor(&hal_fn->wifi_get_supported_radio_combinations_matrix);
+ populateStubFor(&hal_fn->wifi_nan_rtt_chre_enable_request);
+ populateStubFor(&hal_fn->wifi_nan_rtt_chre_disable_request);
+ populateStubFor(&hal_fn->wifi_chre_register_handler);
+ populateStubFor(&hal_fn->wifi_enable_tx_power_limits);
+ populateStubFor(&hal_fn->wifi_get_cached_scan_results);
+ return true;
+}
+} // namespace legacy_hal
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.6/default/wifi_legacy_hal_stubs.h b/wifi/1.6/default/wifi_legacy_hal_stubs.h
new file mode 100644
index 0000000..ebc0347
--- /dev/null
+++ b/wifi/1.6/default/wifi_legacy_hal_stubs.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_LEGACY_HAL_STUBS_H_
+#define WIFI_LEGACY_HAL_STUBS_H_
+
+#include <hal_legacy/wifi_hal.h>
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace legacy_hal {
+
+bool initHalFuncTableWithStubs(wifi_hal_fn* hal_fn);
+} // namespace legacy_hal
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+
+#endif // WIFI_LEGACY_HAL_STUBS_H_
diff --git a/wifi/1.6/default/wifi_mode_controller.cpp b/wifi/1.6/default/wifi_mode_controller.cpp
new file mode 100644
index 0000000..4b8ac7d
--- /dev/null
+++ b/wifi/1.6/default/wifi_mode_controller.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <private/android_filesystem_config.h>
+
+#include "wifi_mode_controller.h"
+
+using android::hardware::wifi::V1_0::IfaceType;
+using android::wifi_hal::DriverTool;
+
+namespace {
+int convertIfaceTypeToFirmwareMode(IfaceType type) {
+ int mode;
+ switch (type) {
+ case IfaceType::AP:
+ mode = DriverTool::kFirmwareModeAp;
+ break;
+ case IfaceType::P2P:
+ mode = DriverTool::kFirmwareModeP2p;
+ break;
+ case IfaceType::NAN:
+ // NAN is exposed in STA mode currently.
+ mode = DriverTool::kFirmwareModeSta;
+ break;
+ case IfaceType::STA:
+ mode = DriverTool::kFirmwareModeSta;
+ break;
+ }
+ return mode;
+}
+} // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace mode_controller {
+
+WifiModeController::WifiModeController() : driver_tool_(new DriverTool) {}
+
+bool WifiModeController::isFirmwareModeChangeNeeded(IfaceType type) {
+ return driver_tool_->IsFirmwareModeChangeNeeded(convertIfaceTypeToFirmwareMode(type));
+}
+
+bool WifiModeController::initialize() {
+ if (!driver_tool_->LoadDriver()) {
+ LOG(ERROR) << "Failed to load WiFi driver";
+ return false;
+ }
+ return true;
+}
+
+bool WifiModeController::changeFirmwareMode(IfaceType type) {
+ if (!driver_tool_->ChangeFirmwareMode(convertIfaceTypeToFirmwareMode(type))) {
+ LOG(ERROR) << "Failed to change firmware mode";
+ return false;
+ }
+ return true;
+}
+
+bool WifiModeController::deinitialize() {
+ if (!driver_tool_->UnloadDriver()) {
+ LOG(ERROR) << "Failed to unload WiFi driver";
+ return false;
+ }
+ return true;
+}
+} // namespace mode_controller
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.6/default/wifi_mode_controller.h b/wifi/1.6/default/wifi_mode_controller.h
new file mode 100644
index 0000000..fee2b66
--- /dev/null
+++ b/wifi/1.6/default/wifi_mode_controller.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_MODE_CONTROLLER_H_
+#define WIFI_MODE_CONTROLLER_H_
+
+#include <wifi_hal/driver_tool.h>
+
+#include <android/hardware/wifi/1.0/IWifi.h>
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+namespace mode_controller {
+using namespace android::hardware::wifi::V1_0;
+
+/**
+ * Class that encapsulates all firmware mode configuration.
+ * This class will perform the necessary firmware reloads to put the chip in the
+ * required state (essentially a wrapper over DriverTool).
+ */
+class WifiModeController {
+ public:
+ WifiModeController();
+ virtual ~WifiModeController() = default;
+
+ // Checks if a firmware mode change is necessary to support the specified
+ // iface type operations.
+ virtual bool isFirmwareModeChangeNeeded(IfaceType type);
+ virtual bool initialize();
+ // Change the firmware mode to support the specified iface type operations.
+ virtual bool changeFirmwareMode(IfaceType type);
+ // Unload the driver. This should be invoked whenever |IWifi.stop()| is
+ // invoked.
+ virtual bool deinitialize();
+
+ private:
+ std::unique_ptr<wifi_hal::DriverTool> driver_tool_;
+};
+
+} // namespace mode_controller
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+
+#endif // WIFI_MODE_CONTROLLER_H_
diff --git a/wifi/1.6/default/wifi_nan_iface.cpp b/wifi/1.6/default/wifi_nan_iface.cpp
new file mode 100644
index 0000000..ac2ebc9
--- /dev/null
+++ b/wifi/1.6/default/wifi_nan_iface.cpp
@@ -0,0 +1,1016 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+
+#include "hidl_return_util.h"
+#include "hidl_struct_util.h"
+#include "wifi_nan_iface.h"
+#include "wifi_status_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+using hidl_return_util::validateAndCall;
+
+WifiNanIface::WifiNanIface(const std::string& ifname, bool is_dedicated_iface,
+ const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+ const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util)
+ : ifname_(ifname),
+ is_dedicated_iface_(is_dedicated_iface),
+ legacy_hal_(legacy_hal),
+ iface_util_(iface_util),
+ is_valid_(true) {
+ if (is_dedicated_iface_) {
+ // If using a dedicated iface, set the iface up first.
+ if (!iface_util_.lock()->setUpState(ifname_, true)) {
+ // Fatal failure, invalidate the iface object.
+ invalidate();
+ return;
+ }
+ }
+ // Register all the callbacks here. these should be valid for the lifetime
+ // of the object. Whenever the mode changes legacy HAL will remove
+ // all of these callbacks.
+ legacy_hal::NanCallbackHandlers callback_handlers;
+ android::wp<WifiNanIface> weak_ptr_this(this);
+
+ // Callback for response.
+ callback_handlers.on_notify_response = [weak_ptr_this](legacy_hal::transaction_id id,
+ const legacy_hal::NanResponseMsg& msg) {
+ const auto shared_ptr_this = weak_ptr_this.promote();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ WifiNanStatus wifiNanStatus;
+ if (!hidl_struct_util::convertLegacyNanResponseHeaderToHidl(msg, &wifiNanStatus)) {
+ LOG(ERROR) << "Failed to convert nan response header";
+ return;
+ }
+
+ switch (msg.response_type) {
+ case legacy_hal::NAN_RESPONSE_ENABLED: {
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->notifyEnableResponse(id, wifiNanStatus).isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ break;
+ }
+ case legacy_hal::NAN_RESPONSE_DISABLED: {
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->notifyDisableResponse(id, wifiNanStatus).isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ break;
+ }
+ case legacy_hal::NAN_RESPONSE_PUBLISH: {
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->notifyStartPublishResponse(id, wifiNanStatus,
+ msg.body.publish_response.publish_id)
+ .isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ break;
+ }
+ case legacy_hal::NAN_RESPONSE_PUBLISH_CANCEL: {
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->notifyStopPublishResponse(id, wifiNanStatus).isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ break;
+ }
+ case legacy_hal::NAN_RESPONSE_TRANSMIT_FOLLOWUP: {
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->notifyTransmitFollowupResponse(id, wifiNanStatus).isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ break;
+ }
+ case legacy_hal::NAN_RESPONSE_SUBSCRIBE: {
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->notifyStartSubscribeResponse(
+ id, wifiNanStatus,
+ msg.body.subscribe_response.subscribe_id)
+ .isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ break;
+ }
+ case legacy_hal::NAN_RESPONSE_SUBSCRIBE_CANCEL: {
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->notifyStopSubscribeResponse(id, wifiNanStatus).isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ break;
+ }
+ case legacy_hal::NAN_RESPONSE_CONFIG: {
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->notifyConfigResponse(id, wifiNanStatus).isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ break;
+ }
+ case legacy_hal::NAN_GET_CAPABILITIES: {
+ V1_6::NanCapabilities hidl_struct;
+ if (!hidl_struct_util::convertLegacyNanCapabilitiesResponseToHidl(
+ msg.body.nan_capabilities, &hidl_struct)) {
+ LOG(ERROR) << "Failed to convert nan capabilities response";
+ return;
+ }
+ for (const auto& callback : shared_ptr_this->getEventCallbacks_1_6()) {
+ if (!callback->notifyCapabilitiesResponse_1_6(id, wifiNanStatus, hidl_struct)
+ .isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ break;
+ }
+ case legacy_hal::NAN_DP_INTERFACE_CREATE: {
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->notifyCreateDataInterfaceResponse(id, wifiNanStatus).isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ break;
+ }
+ case legacy_hal::NAN_DP_INTERFACE_DELETE: {
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->notifyDeleteDataInterfaceResponse(id, wifiNanStatus).isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ break;
+ }
+ case legacy_hal::NAN_DP_INITIATOR_RESPONSE: {
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->notifyInitiateDataPathResponse(
+ id, wifiNanStatus,
+ msg.body.data_request_response.ndp_instance_id)
+ .isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ break;
+ }
+ case legacy_hal::NAN_DP_RESPONDER_RESPONSE: {
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->notifyRespondToDataPathIndicationResponse(id, wifiNanStatus)
+ .isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ break;
+ }
+ case legacy_hal::NAN_DP_END: {
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->notifyTerminateDataPathResponse(id, wifiNanStatus).isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ break;
+ }
+ case legacy_hal::NAN_RESPONSE_BEACON_SDF_PAYLOAD:
+ /* fall through */
+ case legacy_hal::NAN_RESPONSE_TCA:
+ /* fall through */
+ case legacy_hal::NAN_RESPONSE_STATS:
+ /* fall through */
+ case legacy_hal::NAN_RESPONSE_ERROR:
+ /* fall through */
+ default:
+ LOG(ERROR) << "Unknown or unhandled response type: " << msg.response_type;
+ return;
+ }
+ };
+
+ callback_handlers.on_event_disc_eng_event =
+ [weak_ptr_this](const legacy_hal::NanDiscEngEventInd& msg) {
+ const auto shared_ptr_this = weak_ptr_this.promote();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ NanClusterEventInd hidl_struct;
+ // event types defined identically - hence can be cast
+ hidl_struct.eventType = (NanClusterEventType)msg.event_type;
+ hidl_struct.addr = msg.data.mac_addr.addr;
+
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->eventClusterEvent(hidl_struct).isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ };
+
+ callback_handlers.on_event_disabled = [weak_ptr_this](const legacy_hal::NanDisabledInd& msg) {
+ const auto shared_ptr_this = weak_ptr_this.promote();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ WifiNanStatus status;
+ hidl_struct_util::convertToWifiNanStatus(msg.reason, msg.nan_reason, sizeof(msg.nan_reason),
+ &status);
+
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->eventDisabled(status).isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ };
+
+ callback_handlers.on_event_publish_terminated =
+ [weak_ptr_this](const legacy_hal::NanPublishTerminatedInd& msg) {
+ const auto shared_ptr_this = weak_ptr_this.promote();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ WifiNanStatus status;
+ hidl_struct_util::convertToWifiNanStatus(msg.reason, msg.nan_reason,
+ sizeof(msg.nan_reason), &status);
+
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->eventPublishTerminated(msg.publish_id, status).isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ };
+
+ callback_handlers.on_event_subscribe_terminated =
+ [weak_ptr_this](const legacy_hal::NanSubscribeTerminatedInd& msg) {
+ const auto shared_ptr_this = weak_ptr_this.promote();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ WifiNanStatus status;
+ hidl_struct_util::convertToWifiNanStatus(msg.reason, msg.nan_reason,
+ sizeof(msg.nan_reason), &status);
+
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->eventSubscribeTerminated(msg.subscribe_id, status).isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ };
+
+ callback_handlers.on_event_match = [weak_ptr_this](const legacy_hal::NanMatchInd& msg) {
+ const auto shared_ptr_this = weak_ptr_this.promote();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ V1_6::NanMatchInd hidl_struct;
+ if (!hidl_struct_util::convertLegacyNanMatchIndToHidl(msg, &hidl_struct)) {
+ LOG(ERROR) << "Failed to convert nan capabilities response";
+ return;
+ }
+
+ for (const auto& callback : shared_ptr_this->getEventCallbacks_1_6()) {
+ if (!callback->eventMatch_1_6(hidl_struct).isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ };
+
+ callback_handlers.on_event_match_expired = [weak_ptr_this](
+ const legacy_hal::NanMatchExpiredInd& msg) {
+ const auto shared_ptr_this = weak_ptr_this.promote();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->eventMatchExpired(msg.publish_subscribe_id, msg.requestor_instance_id)
+ .isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ };
+
+ callback_handlers.on_event_followup = [weak_ptr_this](const legacy_hal::NanFollowupInd& msg) {
+ const auto shared_ptr_this = weak_ptr_this.promote();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ NanFollowupReceivedInd hidl_struct;
+ if (!hidl_struct_util::convertLegacyNanFollowupIndToHidl(msg, &hidl_struct)) {
+ LOG(ERROR) << "Failed to convert nan capabilities response";
+ return;
+ }
+
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->eventFollowupReceived(hidl_struct).isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ };
+
+ callback_handlers.on_event_transmit_follow_up =
+ [weak_ptr_this](const legacy_hal::NanTransmitFollowupInd& msg) {
+ const auto shared_ptr_this = weak_ptr_this.promote();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ WifiNanStatus status;
+ hidl_struct_util::convertToWifiNanStatus(msg.reason, msg.nan_reason,
+ sizeof(msg.nan_reason), &status);
+
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->eventTransmitFollowup(msg.id, status).isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ };
+
+ callback_handlers.on_event_data_path_request =
+ [weak_ptr_this](const legacy_hal::NanDataPathRequestInd& msg) {
+ const auto shared_ptr_this = weak_ptr_this.promote();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ NanDataPathRequestInd hidl_struct;
+ if (!hidl_struct_util::convertLegacyNanDataPathRequestIndToHidl(msg,
+ &hidl_struct)) {
+ LOG(ERROR) << "Failed to convert nan capabilities response";
+ return;
+ }
+
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->eventDataPathRequest(hidl_struct).isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ };
+
+ callback_handlers.on_event_data_path_confirm =
+ [weak_ptr_this](const legacy_hal::NanDataPathConfirmInd& msg) {
+ const auto shared_ptr_this = weak_ptr_this.promote();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ V1_6::NanDataPathConfirmInd hidl_struct;
+ if (!hidl_struct_util::convertLegacyNanDataPathConfirmIndToHidl(msg,
+ &hidl_struct)) {
+ LOG(ERROR) << "Failed to convert nan capabilities response";
+ return;
+ }
+
+ for (const auto& callback : shared_ptr_this->getEventCallbacks_1_6()) {
+ if (!callback->eventDataPathConfirm_1_6(hidl_struct).isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ };
+
+ callback_handlers.on_event_data_path_end =
+ [weak_ptr_this](const legacy_hal::NanDataPathEndInd& msg) {
+ const auto shared_ptr_this = weak_ptr_this.promote();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ for (int i = 0; i < msg.num_ndp_instances; ++i) {
+ if (!callback->eventDataPathTerminated(msg.ndp_instance_id[i]).isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ }
+ };
+
+ callback_handlers.on_event_beacon_sdf_payload =
+ [weak_ptr_this](const legacy_hal::NanBeaconSdfPayloadInd& /* msg */) {
+ LOG(ERROR) << "on_event_beacon_sdf_payload - should not be called";
+ };
+
+ callback_handlers.on_event_range_request =
+ [weak_ptr_this](const legacy_hal::NanRangeRequestInd& /* msg */) {
+ LOG(ERROR) << "on_event_range_request - should not be called";
+ };
+
+ callback_handlers.on_event_range_report =
+ [weak_ptr_this](const legacy_hal::NanRangeReportInd& /* msg */) {
+ LOG(ERROR) << "on_event_range_report - should not be called";
+ };
+
+ callback_handlers.on_event_schedule_update =
+ [weak_ptr_this](const legacy_hal::NanDataPathScheduleUpdateInd& msg) {
+ const auto shared_ptr_this = weak_ptr_this.promote();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ V1_6::NanDataPathScheduleUpdateInd hidl_struct;
+ if (!hidl_struct_util::convertLegacyNanDataPathScheduleUpdateIndToHidl(
+ msg, &hidl_struct)) {
+ LOG(ERROR) << "Failed to convert nan capabilities response";
+ return;
+ }
+
+ for (const auto& callback : shared_ptr_this->getEventCallbacks_1_6()) {
+ if (!callback->eventDataPathScheduleUpdate_1_6(hidl_struct).isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ };
+
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->nanRegisterCallbackHandlers(ifname_, callback_handlers);
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ LOG(ERROR) << "Failed to register nan callbacks. Invalidating object";
+ invalidate();
+ }
+
+ // Register for iface state toggle events.
+ iface_util::IfaceEventHandlers event_handlers = {};
+ event_handlers.on_state_toggle_off_on = [weak_ptr_this](const std::string& /* iface_name */) {
+ const auto shared_ptr_this = weak_ptr_this.promote();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ // Tell framework that NAN has been disabled.
+ WifiNanStatus status = {NanStatusType::UNSUPPORTED_CONCURRENCY_NAN_DISABLED, ""};
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->eventDisabled(status).isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ };
+ iface_util_.lock()->registerIfaceEventHandlers(ifname_, event_handlers);
+}
+
+void WifiNanIface::invalidate() {
+ if (!isValid()) {
+ return;
+ }
+ // send commands to HAL to actually disable and destroy interfaces
+ legacy_hal_.lock()->nanDisableRequest(ifname_, 0xFFFF);
+ legacy_hal_.lock()->nanDataInterfaceDelete(ifname_, 0xFFFE, "aware_data0");
+ legacy_hal_.lock()->nanDataInterfaceDelete(ifname_, 0xFFFD, "aware_data1");
+ iface_util_.lock()->unregisterIfaceEventHandlers(ifname_);
+ legacy_hal_.reset();
+ event_cb_handler_.invalidate();
+ event_cb_handler_1_2_.invalidate();
+ event_cb_handler_1_5_.invalidate();
+ is_valid_ = false;
+ if (is_dedicated_iface_) {
+ // If using a dedicated iface, set the iface down.
+ iface_util_.lock()->setUpState(ifname_, false);
+ }
+}
+
+bool WifiNanIface::isValid() {
+ return is_valid_;
+}
+
+std::string WifiNanIface::getName() {
+ return ifname_;
+}
+
+std::set<sp<V1_0::IWifiNanIfaceEventCallback>> WifiNanIface::getEventCallbacks() {
+ return event_cb_handler_.getCallbacks();
+}
+
+std::set<sp<V1_2::IWifiNanIfaceEventCallback>> WifiNanIface::getEventCallbacks_1_2() {
+ return event_cb_handler_1_2_.getCallbacks();
+}
+
+std::set<sp<V1_5::IWifiNanIfaceEventCallback>> WifiNanIface::getEventCallbacks_1_5() {
+ return event_cb_handler_1_5_.getCallbacks();
+}
+
+std::set<sp<V1_6::IWifiNanIfaceEventCallback>> WifiNanIface::getEventCallbacks_1_6() {
+ return event_cb_handler_1_6_.getCallbacks();
+}
+
+Return<void> WifiNanIface::getName(getName_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::getNameInternal, hidl_status_cb);
+}
+
+Return<void> WifiNanIface::getType(getType_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::getTypeInternal, hidl_status_cb);
+}
+
+Return<void> WifiNanIface::registerEventCallback(
+ const sp<V1_0::IWifiNanIfaceEventCallback>& callback,
+ registerEventCallback_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::registerEventCallbackInternal, hidl_status_cb, callback);
+}
+
+Return<void> WifiNanIface::getCapabilitiesRequest(uint16_t cmd_id,
+ getCapabilitiesRequest_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::getCapabilitiesRequestInternal, hidl_status_cb, cmd_id);
+}
+
+Return<void> WifiNanIface::enableRequest(uint16_t cmd_id, const V1_0::NanEnableRequest& msg,
+ enableRequest_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::enableRequestInternal, hidl_status_cb, cmd_id, msg);
+}
+
+Return<void> WifiNanIface::configRequest(uint16_t cmd_id, const V1_0::NanConfigRequest& msg,
+ configRequest_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::configRequestInternal, hidl_status_cb, cmd_id, msg);
+}
+
+Return<void> WifiNanIface::disableRequest(uint16_t cmd_id, disableRequest_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::disableRequestInternal, hidl_status_cb, cmd_id);
+}
+
+Return<void> WifiNanIface::startPublishRequest(uint16_t cmd_id, const V1_0::NanPublishRequest& msg,
+ startPublishRequest_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::startPublishRequestInternal, hidl_status_cb, cmd_id, msg);
+}
+
+Return<void> WifiNanIface::stopPublishRequest(uint16_t cmd_id, uint8_t sessionId,
+ stopPublishRequest_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::stopPublishRequestInternal, hidl_status_cb, cmd_id,
+ sessionId);
+}
+
+Return<void> WifiNanIface::startSubscribeRequest(uint16_t cmd_id,
+ const V1_0::NanSubscribeRequest& msg,
+ startSubscribeRequest_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::startSubscribeRequestInternal, hidl_status_cb, cmd_id,
+ msg);
+}
+
+Return<void> WifiNanIface::stopSubscribeRequest(uint16_t cmd_id, uint8_t sessionId,
+ stopSubscribeRequest_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::stopSubscribeRequestInternal, hidl_status_cb, cmd_id,
+ sessionId);
+}
+
+Return<void> WifiNanIface::transmitFollowupRequest(uint16_t cmd_id,
+ const NanTransmitFollowupRequest& msg,
+ transmitFollowupRequest_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::transmitFollowupRequestInternal, hidl_status_cb, cmd_id,
+ msg);
+}
+
+Return<void> WifiNanIface::createDataInterfaceRequest(
+ uint16_t cmd_id, const hidl_string& iface_name,
+ createDataInterfaceRequest_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::createDataInterfaceRequestInternal, hidl_status_cb,
+ cmd_id, iface_name);
+}
+
+Return<void> WifiNanIface::deleteDataInterfaceRequest(
+ uint16_t cmd_id, const hidl_string& iface_name,
+ deleteDataInterfaceRequest_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::deleteDataInterfaceRequestInternal, hidl_status_cb,
+ cmd_id, iface_name);
+}
+
+Return<void> WifiNanIface::initiateDataPathRequest(uint16_t cmd_id,
+ const V1_0::NanInitiateDataPathRequest& msg,
+ initiateDataPathRequest_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::initiateDataPathRequestInternal, hidl_status_cb, cmd_id,
+ msg);
+}
+
+Return<void> WifiNanIface::respondToDataPathIndicationRequest(
+ uint16_t cmd_id, const V1_0::NanRespondToDataPathIndicationRequest& msg,
+ respondToDataPathIndicationRequest_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::respondToDataPathIndicationRequestInternal,
+ hidl_status_cb, cmd_id, msg);
+}
+
+Return<void> WifiNanIface::terminateDataPathRequest(uint16_t cmd_id, uint32_t ndpInstanceId,
+ terminateDataPathRequest_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::terminateDataPathRequestInternal, hidl_status_cb, cmd_id,
+ ndpInstanceId);
+}
+
+Return<void> WifiNanIface::registerEventCallback_1_2(
+ const sp<V1_2::IWifiNanIfaceEventCallback>& callback,
+ registerEventCallback_1_2_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::registerEventCallback_1_2Internal, hidl_status_cb,
+ callback);
+}
+
+Return<void> WifiNanIface::enableRequest_1_2(uint16_t cmd_id, const V1_0::NanEnableRequest& msg1,
+ const V1_2::NanConfigRequestSupplemental& msg2,
+ enableRequest_1_2_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::enableRequest_1_2Internal, hidl_status_cb, cmd_id, msg1,
+ msg2);
+}
+
+Return<void> WifiNanIface::configRequest_1_2(uint16_t cmd_id, const V1_0::NanConfigRequest& msg1,
+ const V1_2::NanConfigRequestSupplemental& msg2,
+ configRequest_1_2_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::configRequest_1_2Internal, hidl_status_cb, cmd_id, msg1,
+ msg2);
+}
+
+Return<void> WifiNanIface::enableRequest_1_4(uint16_t cmd_id, const V1_4::NanEnableRequest& msg1,
+ const V1_2::NanConfigRequestSupplemental& msg2,
+ enableRequest_1_4_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::enableRequest_1_4Internal, hidl_status_cb, cmd_id, msg1,
+ msg2);
+}
+
+Return<void> WifiNanIface::configRequest_1_4(uint16_t cmd_id, const V1_4::NanConfigRequest& msg1,
+ const V1_2::NanConfigRequestSupplemental& msg2,
+ configRequest_1_4_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::configRequest_1_4Internal, hidl_status_cb, cmd_id, msg1,
+ msg2);
+}
+
+Return<void> WifiNanIface::registerEventCallback_1_5(
+ const sp<V1_5::IWifiNanIfaceEventCallback>& callback,
+ registerEventCallback_1_5_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::registerEventCallback_1_5Internal, hidl_status_cb,
+ callback);
+}
+
+Return<void> WifiNanIface::enableRequest_1_5(uint16_t cmd_id, const V1_4::NanEnableRequest& msg1,
+ const V1_5::NanConfigRequestSupplemental& msg2,
+ enableRequest_1_5_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::enableRequest_1_5Internal, hidl_status_cb, cmd_id, msg1,
+ msg2);
+}
+
+Return<void> WifiNanIface::configRequest_1_5(uint16_t cmd_id, const V1_4::NanConfigRequest& msg1,
+ const V1_5::NanConfigRequestSupplemental& msg2,
+ configRequest_1_5_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::configRequest_1_5Internal, hidl_status_cb, cmd_id, msg1,
+ msg2);
+}
+
+Return<void> WifiNanIface::getCapabilitiesRequest_1_5(
+ uint16_t cmd_id, getCapabilitiesRequest_1_5_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::getCapabilitiesRequest_1_5Internal, hidl_status_cb,
+ cmd_id);
+}
+
+Return<void> WifiNanIface::enableRequest_1_6(uint16_t cmd_id, const V1_4::NanEnableRequest& msg1,
+ const V1_6::NanConfigRequestSupplemental& msg2,
+ enableRequest_1_5_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::enableRequest_1_6Internal, hidl_status_cb, cmd_id, msg1,
+ msg2);
+}
+
+Return<void> WifiNanIface::configRequest_1_6(uint16_t cmd_id, const V1_4::NanConfigRequest& msg1,
+ const V1_6::NanConfigRequestSupplemental& msg2,
+ configRequest_1_5_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::configRequest_1_6Internal, hidl_status_cb, cmd_id, msg1,
+ msg2);
+}
+
+Return<void> WifiNanIface::initiateDataPathRequest_1_6(uint16_t cmd_id,
+ const V1_6::NanInitiateDataPathRequest& msg,
+ initiateDataPathRequest_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::initiateDataPathRequest_1_6Internal, hidl_status_cb,
+ cmd_id, msg);
+}
+
+Return<void> WifiNanIface::respondToDataPathIndicationRequest_1_6(
+ uint16_t cmd_id, const V1_6::NanRespondToDataPathIndicationRequest& msg,
+ respondToDataPathIndicationRequest_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::respondToDataPathIndicationRequest_1_6Internal,
+ hidl_status_cb, cmd_id, msg);
+}
+
+Return<void> WifiNanIface::startPublishRequest_1_6(uint16_t cmd_id,
+ const V1_6::NanPublishRequest& msg,
+ startPublishRequest_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::startPublishRequest_1_6Internal, hidl_status_cb, cmd_id,
+ msg);
+}
+
+std::pair<WifiStatus, std::string> WifiNanIface::getNameInternal() {
+ return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_};
+}
+
+std::pair<WifiStatus, IfaceType> WifiNanIface::getTypeInternal() {
+ return {createWifiStatus(WifiStatusCode::SUCCESS), IfaceType::NAN};
+}
+
+Return<void> WifiNanIface::registerEventCallback_1_6(
+ const sp<V1_6::IWifiNanIfaceEventCallback>& callback,
+ registerEventCallback_1_6_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::registerEventCallback_1_6Internal, hidl_status_cb,
+ callback);
+}
+
+WifiStatus WifiNanIface::registerEventCallbackInternal(
+ const sp<V1_0::IWifiNanIfaceEventCallback>& callback) {
+ if (!event_cb_handler_.addCallback(callback)) {
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+ }
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+WifiStatus WifiNanIface::getCapabilitiesRequestInternal(uint16_t /* cmd_id */) {
+ return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiNanIface::enableRequestInternal(uint16_t /* cmd_id */,
+ const V1_0::NanEnableRequest& /* msg */) {
+ return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiNanIface::configRequestInternal(uint16_t /* cmd_id */,
+ const V1_0::NanConfigRequest& /* msg */) {
+ return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiNanIface::disableRequestInternal(uint16_t cmd_id) {
+ legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->nanDisableRequest(ifname_, cmd_id);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::startPublishRequestInternal(uint16_t /* cmd_id */,
+ const V1_0::NanPublishRequest& /* msg */) {
+ return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiNanIface::stopPublishRequestInternal(uint16_t cmd_id, uint8_t sessionId) {
+ legacy_hal::NanPublishCancelRequest legacy_msg;
+ legacy_msg.publish_id = sessionId;
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->nanPublishCancelRequest(ifname_, cmd_id, legacy_msg);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::startSubscribeRequestInternal(uint16_t cmd_id,
+ const V1_0::NanSubscribeRequest& msg) {
+ legacy_hal::NanSubscribeRequest legacy_msg;
+ if (!hidl_struct_util::convertHidlNanSubscribeRequestToLegacy(msg, &legacy_msg)) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->nanSubscribeRequest(ifname_, cmd_id, legacy_msg);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::stopSubscribeRequestInternal(uint16_t cmd_id, uint8_t sessionId) {
+ legacy_hal::NanSubscribeCancelRequest legacy_msg;
+ legacy_msg.subscribe_id = sessionId;
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->nanSubscribeCancelRequest(ifname_, cmd_id, legacy_msg);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::transmitFollowupRequestInternal(uint16_t cmd_id,
+ const NanTransmitFollowupRequest& msg) {
+ legacy_hal::NanTransmitFollowupRequest legacy_msg;
+ if (!hidl_struct_util::convertHidlNanTransmitFollowupRequestToLegacy(msg, &legacy_msg)) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->nanTransmitFollowupRequest(ifname_, cmd_id, legacy_msg);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::createDataInterfaceRequestInternal(uint16_t cmd_id,
+ const std::string& iface_name) {
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->nanDataInterfaceCreate(ifname_, cmd_id, iface_name);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+WifiStatus WifiNanIface::deleteDataInterfaceRequestInternal(uint16_t cmd_id,
+ const std::string& iface_name) {
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->nanDataInterfaceDelete(ifname_, cmd_id, iface_name);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+WifiStatus WifiNanIface::initiateDataPathRequestInternal(
+ uint16_t cmd_id, const V1_0::NanInitiateDataPathRequest& msg) {
+ legacy_hal::NanDataPathInitiatorRequest legacy_msg;
+ if (!hidl_struct_util::convertHidlNanDataPathInitiatorRequestToLegacy(msg, &legacy_msg)) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->nanDataRequestInitiator(ifname_, cmd_id, legacy_msg);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+WifiStatus WifiNanIface::respondToDataPathIndicationRequestInternal(
+ uint16_t cmd_id, const V1_0::NanRespondToDataPathIndicationRequest& msg) {
+ legacy_hal::NanDataPathIndicationResponse legacy_msg;
+ if (!hidl_struct_util::convertHidlNanDataPathIndicationResponseToLegacy(msg, &legacy_msg)) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->nanDataIndicationResponse(ifname_, cmd_id, legacy_msg);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+WifiStatus WifiNanIface::terminateDataPathRequestInternal(uint16_t cmd_id, uint32_t ndpInstanceId) {
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->nanDataEnd(ifname_, cmd_id, ndpInstanceId);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::registerEventCallback_1_2Internal(
+ const sp<V1_2::IWifiNanIfaceEventCallback>& callback) {
+ sp<V1_0::IWifiNanIfaceEventCallback> callback_1_0 = callback;
+ if (!event_cb_handler_.addCallback(callback_1_0)) {
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+ }
+ if (!event_cb_handler_1_2_.addCallback(callback)) {
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+ }
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+WifiStatus WifiNanIface::enableRequest_1_2Internal(
+ uint16_t /* cmd_id */, const V1_0::NanEnableRequest& /* msg1 */,
+ const V1_2::NanConfigRequestSupplemental& /* msg2 */) {
+ return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiNanIface::configRequest_1_2Internal(
+ uint16_t /* cmd_id */, const V1_0::NanConfigRequest& /* msg1 */,
+ const V1_2::NanConfigRequestSupplemental& /* msg2 */) {
+ return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiNanIface::enableRequest_1_4Internal(
+ uint16_t /* cmd_id */, const V1_4::NanEnableRequest& /* msg1 */,
+ const V1_2::NanConfigRequestSupplemental& /* msg2 */) {
+ return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiNanIface::configRequest_1_4Internal(
+ uint16_t /* cmd_id */, const V1_4::NanConfigRequest& /* msg1 */,
+ const V1_2::NanConfigRequestSupplemental& /* msg2 */) {
+ return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiNanIface::registerEventCallback_1_5Internal(
+ const sp<V1_5::IWifiNanIfaceEventCallback>& callback) {
+ sp<V1_0::IWifiNanIfaceEventCallback> callback_1_0 = callback;
+ if (!event_cb_handler_.addCallback(callback_1_0)) {
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+ }
+ sp<V1_2::IWifiNanIfaceEventCallback> callback_1_2 = callback;
+ if (!event_cb_handler_1_2_.addCallback(callback_1_2)) {
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+ }
+ if (!event_cb_handler_1_5_.addCallback(callback)) {
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+ }
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+WifiStatus WifiNanIface::getCapabilitiesRequest_1_5Internal(uint16_t cmd_id) {
+ legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->nanGetCapabilities(ifname_, cmd_id);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::enableRequest_1_5Internal(
+ uint16_t /* cmd_id */, const V1_4::NanEnableRequest& /* msg1 */,
+ const V1_5::NanConfigRequestSupplemental& /* msg2 */) {
+ return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiNanIface::configRequest_1_5Internal(
+ uint16_t /* cmd_id */, const V1_4::NanConfigRequest& /* msg1 */,
+ const V1_5::NanConfigRequestSupplemental& /* msg2 */) {
+ return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiNanIface::enableRequest_1_6Internal(uint16_t cmd_id,
+ const V1_4::NanEnableRequest& msg1,
+ const V1_6::NanConfigRequestSupplemental& msg2) {
+ legacy_hal::NanEnableRequest legacy_msg;
+ if (!hidl_struct_util::convertHidlNanEnableRequest_1_6ToLegacy(msg1, msg2, &legacy_msg)) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->nanEnableRequest(ifname_, cmd_id, legacy_msg);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::configRequest_1_6Internal(uint16_t cmd_id,
+ const V1_4::NanConfigRequest& msg1,
+ const V1_6::NanConfigRequestSupplemental& msg2) {
+ legacy_hal::NanConfigRequest legacy_msg;
+ if (!hidl_struct_util::convertHidlNanConfigRequest_1_6ToLegacy(msg1, msg2, &legacy_msg)) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->nanConfigRequest(ifname_, cmd_id, legacy_msg);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::initiateDataPathRequest_1_6Internal(
+ uint16_t cmd_id, const V1_6::NanInitiateDataPathRequest& msg) {
+ legacy_hal::NanDataPathInitiatorRequest legacy_msg;
+ if (!hidl_struct_util::convertHidlNanDataPathInitiatorRequest_1_6ToLegacy(msg, &legacy_msg)) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->nanDataRequestInitiator(ifname_, cmd_id, legacy_msg);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::respondToDataPathIndicationRequest_1_6Internal(
+ uint16_t cmd_id, const V1_6::NanRespondToDataPathIndicationRequest& msg) {
+ legacy_hal::NanDataPathIndicationResponse legacy_msg;
+ if (!hidl_struct_util::convertHidlNanDataPathIndicationResponse_1_6ToLegacy(msg, &legacy_msg)) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->nanDataIndicationResponse(ifname_, cmd_id, legacy_msg);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::startPublishRequest_1_6Internal(uint16_t cmd_id,
+ const V1_6::NanPublishRequest& msg) {
+ legacy_hal::NanPublishRequest legacy_msg;
+ if (!hidl_struct_util::convertHidlNanPublishRequestToLegacy(msg, &legacy_msg)) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->nanPublishRequest(ifname_, cmd_id, legacy_msg);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::registerEventCallback_1_6Internal(
+ const sp<V1_6::IWifiNanIfaceEventCallback>& callback) {
+ sp<V1_0::IWifiNanIfaceEventCallback> callback_1_0 = callback;
+ if (!event_cb_handler_.addCallback(callback_1_0)) {
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+ }
+ sp<V1_2::IWifiNanIfaceEventCallback> callback_1_2 = callback;
+ if (!event_cb_handler_1_2_.addCallback(callback_1_2)) {
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+ }
+ sp<V1_5::IWifiNanIfaceEventCallback> callback_1_5 = callback;
+ if (!event_cb_handler_1_5_.addCallback(callback_1_5)) {
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+ }
+ if (!event_cb_handler_1_6_.addCallback(callback)) {
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+ }
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.6/default/wifi_nan_iface.h b/wifi/1.6/default/wifi_nan_iface.h
new file mode 100644
index 0000000..15bf572
--- /dev/null
+++ b/wifi/1.6/default/wifi_nan_iface.h
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_NAN_IFACE_H_
+#define WIFI_NAN_IFACE_H_
+
+#include <android-base/macros.h>
+#include <android/hardware/wifi/1.6/IWifiNanIface.h>
+#include <android/hardware/wifi/1.6/IWifiNanIfaceEventCallback.h>
+
+#include "hidl_callback_util.h"
+#include "wifi_iface_util.h"
+#include "wifi_legacy_hal.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+using namespace android::hardware::wifi::V1_0;
+using namespace android::hardware::wifi::V1_2;
+using namespace android::hardware::wifi::V1_4;
+using namespace android::hardware::wifi::V1_6;
+
+/**
+ * HIDL interface object used to control a NAN Iface instance.
+ */
+class WifiNanIface : public V1_6::IWifiNanIface {
+ public:
+ WifiNanIface(const std::string& ifname, bool is_dedicated_iface,
+ const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+ const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util);
+ // Refer to |WifiChip::invalidate()|.
+ void invalidate();
+ bool isValid();
+ std::string getName();
+
+ // HIDL methods exposed.
+ Return<void> getName(getName_cb hidl_status_cb) override;
+ Return<void> getType(getType_cb hidl_status_cb) override;
+ Return<void> registerEventCallback(const sp<V1_0::IWifiNanIfaceEventCallback>& callback,
+ registerEventCallback_cb hidl_status_cb) override;
+ Return<void> getCapabilitiesRequest(uint16_t cmd_id,
+ getCapabilitiesRequest_cb hidl_status_cb) override;
+ Return<void> enableRequest(uint16_t cmd_id, const V1_0::NanEnableRequest& msg,
+ enableRequest_cb hidl_status_cb) override;
+ Return<void> configRequest(uint16_t cmd_id, const V1_0::NanConfigRequest& msg,
+ configRequest_cb hidl_status_cb) override;
+ Return<void> disableRequest(uint16_t cmd_id, disableRequest_cb hidl_status_cb) override;
+ Return<void> startPublishRequest(uint16_t cmd_id, const V1_0::NanPublishRequest& msg,
+ startPublishRequest_cb hidl_status_cb) override;
+ Return<void> stopPublishRequest(uint16_t cmd_id, uint8_t sessionId,
+ stopPublishRequest_cb hidl_status_cb) override;
+ Return<void> startSubscribeRequest(uint16_t cmd_id, const V1_0::NanSubscribeRequest& msg,
+ startSubscribeRequest_cb hidl_status_cb) override;
+ Return<void> stopSubscribeRequest(uint16_t cmd_id, uint8_t sessionId,
+ stopSubscribeRequest_cb hidl_status_cb) override;
+ Return<void> transmitFollowupRequest(uint16_t cmd_id, const NanTransmitFollowupRequest& msg,
+ transmitFollowupRequest_cb hidl_status_cb) override;
+ Return<void> createDataInterfaceRequest(uint16_t cmd_id, const hidl_string& iface_name,
+ createDataInterfaceRequest_cb hidl_status_cb) override;
+ Return<void> deleteDataInterfaceRequest(uint16_t cmd_id, const hidl_string& iface_name,
+ deleteDataInterfaceRequest_cb hidl_status_cb) override;
+ Return<void> initiateDataPathRequest(uint16_t cmd_id,
+ const V1_0::NanInitiateDataPathRequest& msg,
+ initiateDataPathRequest_cb hidl_status_cb) override;
+ Return<void> respondToDataPathIndicationRequest(
+ uint16_t cmd_id, const V1_0::NanRespondToDataPathIndicationRequest& msg,
+ respondToDataPathIndicationRequest_cb hidl_status_cb) override;
+ Return<void> terminateDataPathRequest(uint16_t cmd_id, uint32_t ndpInstanceId,
+ terminateDataPathRequest_cb hidl_status_cb) override;
+
+ Return<void> registerEventCallback_1_2(const sp<V1_2::IWifiNanIfaceEventCallback>& callback,
+ registerEventCallback_1_2_cb hidl_status_cb) override;
+ Return<void> enableRequest_1_2(uint16_t cmd_id, const V1_0::NanEnableRequest& msg1,
+ const V1_2::NanConfigRequestSupplemental& msg2,
+ enableRequest_1_2_cb hidl_status_cb) override;
+ Return<void> configRequest_1_2(uint16_t cmd_id, const V1_0::NanConfigRequest& msg1,
+ const V1_2::NanConfigRequestSupplemental& msg2,
+ configRequest_1_2_cb hidl_status_cb) override;
+ Return<void> enableRequest_1_4(uint16_t cmd_id, const V1_4::NanEnableRequest& msg1,
+ const V1_2::NanConfigRequestSupplemental& msg2,
+ enableRequest_1_4_cb hidl_status_cb) override;
+ Return<void> configRequest_1_4(uint16_t cmd_id, const V1_4::NanConfigRequest& msg1,
+ const V1_2::NanConfigRequestSupplemental& msg2,
+ configRequest_1_4_cb hidl_status_cb) override;
+ Return<void> registerEventCallback_1_5(const sp<V1_5::IWifiNanIfaceEventCallback>& callback,
+ registerEventCallback_1_5_cb hidl_status_cb) override;
+ Return<void> enableRequest_1_5(uint16_t cmd_id, const V1_4::NanEnableRequest& msg1,
+ const V1_5::NanConfigRequestSupplemental& msg2,
+ enableRequest_1_5_cb hidl_status_cb) override;
+ Return<void> configRequest_1_5(uint16_t cmd_id, const V1_4::NanConfigRequest& msg1,
+ const V1_5::NanConfigRequestSupplemental& msg2,
+ configRequest_1_5_cb hidl_status_cb) override;
+ Return<void> getCapabilitiesRequest_1_5(uint16_t cmd_id,
+ getCapabilitiesRequest_cb hidl_status_cb) override;
+ Return<void> registerEventCallback_1_6(const sp<V1_6::IWifiNanIfaceEventCallback>& callback,
+ registerEventCallback_1_6_cb hidl_status_cb) override;
+ Return<void> initiateDataPathRequest_1_6(
+ uint16_t cmd_id, const V1_6::NanInitiateDataPathRequest& msg,
+ initiateDataPathRequest_1_6_cb hidl_status_cb) override;
+ Return<void> respondToDataPathIndicationRequest_1_6(
+ uint16_t cmd_id, const V1_6::NanRespondToDataPathIndicationRequest& msg,
+ respondToDataPathIndicationRequest_1_6_cb hidl_status_cb) override;
+ Return<void> enableRequest_1_6(uint16_t cmd_id, const V1_4::NanEnableRequest& msg1,
+ const V1_6::NanConfigRequestSupplemental& msg2,
+ enableRequest_1_6_cb hidl_status_cb) override;
+ Return<void> configRequest_1_6(uint16_t cmd_id, const V1_4::NanConfigRequest& msg1,
+ const V1_6::NanConfigRequestSupplemental& msg2,
+ configRequest_1_6_cb hidl_status_cb) override;
+ Return<void> startPublishRequest_1_6(uint16_t cmd_id, const V1_6::NanPublishRequest& msg,
+ startPublishRequest_cb hidl_status_cb) override;
+
+ private:
+ // Corresponding worker functions for the HIDL methods.
+ std::pair<WifiStatus, std::string> getNameInternal();
+ std::pair<WifiStatus, IfaceType> getTypeInternal();
+ WifiStatus registerEventCallbackInternal(const sp<V1_0::IWifiNanIfaceEventCallback>& callback);
+ WifiStatus getCapabilitiesRequestInternal(uint16_t cmd_id);
+ WifiStatus enableRequestInternal(uint16_t cmd_id, const V1_0::NanEnableRequest& msg);
+ WifiStatus configRequestInternal(uint16_t cmd_id, const V1_0::NanConfigRequest& msg);
+ WifiStatus disableRequestInternal(uint16_t cmd_id);
+ WifiStatus startPublishRequestInternal(uint16_t cmd_id, const V1_0::NanPublishRequest& msg);
+ WifiStatus stopPublishRequestInternal(uint16_t cmd_id, uint8_t sessionId);
+ WifiStatus startSubscribeRequestInternal(uint16_t cmd_id, const V1_0::NanSubscribeRequest& msg);
+ WifiStatus stopSubscribeRequestInternal(uint16_t cmd_id, uint8_t sessionId);
+ WifiStatus transmitFollowupRequestInternal(uint16_t cmd_id,
+ const NanTransmitFollowupRequest& msg);
+ WifiStatus createDataInterfaceRequestInternal(uint16_t cmd_id, const std::string& iface_name);
+ WifiStatus deleteDataInterfaceRequestInternal(uint16_t cmd_id, const std::string& iface_name);
+ WifiStatus initiateDataPathRequestInternal(uint16_t cmd_id,
+ const V1_0::NanInitiateDataPathRequest& msg);
+ WifiStatus respondToDataPathIndicationRequestInternal(
+ uint16_t cmd_id, const V1_0::NanRespondToDataPathIndicationRequest& msg);
+ WifiStatus terminateDataPathRequestInternal(uint16_t cmd_id, uint32_t ndpInstanceId);
+
+ WifiStatus registerEventCallback_1_2Internal(
+ const sp<V1_2::IWifiNanIfaceEventCallback>& callback);
+ WifiStatus enableRequest_1_2Internal(uint16_t cmd_id, const V1_0::NanEnableRequest& msg1,
+ const V1_2::NanConfigRequestSupplemental& msg2);
+ WifiStatus configRequest_1_2Internal(uint16_t cmd_id, const V1_0::NanConfigRequest& msg,
+ const V1_2::NanConfigRequestSupplemental& msg2);
+ WifiStatus enableRequest_1_4Internal(uint16_t cmd_id, const V1_4::NanEnableRequest& msg1,
+ const V1_2::NanConfigRequestSupplemental& msg2);
+ WifiStatus configRequest_1_4Internal(uint16_t cmd_id, const V1_4::NanConfigRequest& msg,
+ const V1_2::NanConfigRequestSupplemental& msg2);
+ WifiStatus registerEventCallback_1_5Internal(
+ const sp<V1_5::IWifiNanIfaceEventCallback>& callback);
+ WifiStatus enableRequest_1_5Internal(uint16_t cmd_id, const V1_4::NanEnableRequest& msg1,
+ const V1_5::NanConfigRequestSupplemental& msg2);
+ WifiStatus configRequest_1_5Internal(uint16_t cmd_id, const V1_4::NanConfigRequest& msg,
+ const V1_5::NanConfigRequestSupplemental& msg2);
+ WifiStatus getCapabilitiesRequest_1_5Internal(uint16_t cmd_id);
+ WifiStatus registerEventCallback_1_6Internal(
+ const sp<V1_6::IWifiNanIfaceEventCallback>& callback);
+
+ WifiStatus enableRequest_1_6Internal(uint16_t cmd_id, const V1_4::NanEnableRequest& msg1,
+ const V1_6::NanConfigRequestSupplemental& msg2);
+ WifiStatus configRequest_1_6Internal(uint16_t cmd_id, const V1_4::NanConfigRequest& msg,
+ const V1_6::NanConfigRequestSupplemental& msg2);
+ WifiStatus startPublishRequest_1_6Internal(uint16_t cmd_id, const V1_6::NanPublishRequest& msg);
+ WifiStatus initiateDataPathRequest_1_6Internal(uint16_t cmd_id,
+ const V1_6::NanInitiateDataPathRequest& msg);
+ WifiStatus respondToDataPathIndicationRequest_1_6Internal(
+ uint16_t cmd_id, const V1_6::NanRespondToDataPathIndicationRequest& msg);
+
+ // all 1_0 and descendant callbacks
+ std::set<sp<V1_0::IWifiNanIfaceEventCallback>> getEventCallbacks();
+ // all 1_2 and descendant callbacks
+ std::set<sp<V1_2::IWifiNanIfaceEventCallback>> getEventCallbacks_1_2();
+ // all 1_5 and descendant callbacks
+ std::set<sp<V1_5::IWifiNanIfaceEventCallback>> getEventCallbacks_1_5();
+ // all 1_6 and descendant callbacks
+ std::set<sp<V1_6::IWifiNanIfaceEventCallback>> getEventCallbacks_1_6();
+
+ std::string ifname_;
+ bool is_dedicated_iface_;
+ std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+ std::weak_ptr<iface_util::WifiIfaceUtil> iface_util_;
+ bool is_valid_;
+ hidl_callback_util::HidlCallbackHandler<V1_0::IWifiNanIfaceEventCallback> event_cb_handler_;
+ hidl_callback_util::HidlCallbackHandler<V1_2::IWifiNanIfaceEventCallback> event_cb_handler_1_2_;
+ hidl_callback_util::HidlCallbackHandler<V1_5::IWifiNanIfaceEventCallback> event_cb_handler_1_5_;
+ hidl_callback_util::HidlCallbackHandler<V1_6::IWifiNanIfaceEventCallback> event_cb_handler_1_6_;
+
+ DISALLOW_COPY_AND_ASSIGN(WifiNanIface);
+};
+
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+
+#endif // WIFI_NAN_IFACE_H_
diff --git a/wifi/1.6/default/wifi_p2p_iface.cpp b/wifi/1.6/default/wifi_p2p_iface.cpp
new file mode 100644
index 0000000..d4b1fca
--- /dev/null
+++ b/wifi/1.6/default/wifi_p2p_iface.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+
+#include "hidl_return_util.h"
+#include "wifi_p2p_iface.h"
+#include "wifi_status_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+using hidl_return_util::validateAndCall;
+
+WifiP2pIface::WifiP2pIface(const std::string& ifname,
+ const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal)
+ : ifname_(ifname), legacy_hal_(legacy_hal), is_valid_(true) {}
+
+void WifiP2pIface::invalidate() {
+ legacy_hal_.reset();
+ is_valid_ = false;
+}
+
+bool WifiP2pIface::isValid() {
+ return is_valid_;
+}
+
+std::string WifiP2pIface::getName() {
+ return ifname_;
+}
+
+Return<void> WifiP2pIface::getName(getName_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiP2pIface::getNameInternal, hidl_status_cb);
+}
+
+Return<void> WifiP2pIface::getType(getType_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiP2pIface::getTypeInternal, hidl_status_cb);
+}
+
+std::pair<WifiStatus, std::string> WifiP2pIface::getNameInternal() {
+ return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_};
+}
+
+std::pair<WifiStatus, IfaceType> WifiP2pIface::getTypeInternal() {
+ return {createWifiStatus(WifiStatusCode::SUCCESS), IfaceType::P2P};
+}
+
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.6/default/wifi_p2p_iface.h b/wifi/1.6/default/wifi_p2p_iface.h
new file mode 100644
index 0000000..0089443
--- /dev/null
+++ b/wifi/1.6/default/wifi_p2p_iface.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_P2P_IFACE_H_
+#define WIFI_P2P_IFACE_H_
+
+#include <android-base/macros.h>
+#include <android/hardware/wifi/1.0/IWifiP2pIface.h>
+
+#include "wifi_legacy_hal.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+using namespace android::hardware::wifi::V1_0;
+
+/**
+ * HIDL interface object used to control a P2P Iface instance.
+ */
+class WifiP2pIface : public V1_0::IWifiP2pIface {
+ public:
+ WifiP2pIface(const std::string& ifname,
+ const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
+ // Refer to |WifiChip::invalidate()|.
+ void invalidate();
+ bool isValid();
+ std::string getName();
+
+ // HIDL methods exposed.
+ Return<void> getName(getName_cb hidl_status_cb) override;
+ Return<void> getType(getType_cb hidl_status_cb) override;
+
+ private:
+ // Corresponding worker functions for the HIDL methods.
+ std::pair<WifiStatus, std::string> getNameInternal();
+ std::pair<WifiStatus, IfaceType> getTypeInternal();
+
+ std::string ifname_;
+ std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+ bool is_valid_;
+
+ DISALLOW_COPY_AND_ASSIGN(WifiP2pIface);
+};
+
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+
+#endif // WIFI_P2P_IFACE_H_
diff --git a/wifi/1.6/default/wifi_rtt_controller.cpp b/wifi/1.6/default/wifi_rtt_controller.cpp
new file mode 100644
index 0000000..aa9ee2f
--- /dev/null
+++ b/wifi/1.6/default/wifi_rtt_controller.cpp
@@ -0,0 +1,377 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+
+#include "hidl_return_util.h"
+#include "hidl_struct_util.h"
+#include "wifi_rtt_controller.h"
+#include "wifi_status_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+using hidl_return_util::validateAndCall;
+
+WifiRttController::WifiRttController(const std::string& iface_name,
+ const sp<IWifiIface>& bound_iface,
+ const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal)
+ : ifname_(iface_name), bound_iface_(bound_iface), legacy_hal_(legacy_hal), is_valid_(true) {}
+
+void WifiRttController::invalidate() {
+ legacy_hal_.reset();
+ event_callbacks_.clear();
+ is_valid_ = false;
+}
+
+bool WifiRttController::isValid() {
+ return is_valid_;
+}
+
+std::vector<sp<V1_6::IWifiRttControllerEventCallback>> WifiRttController::getEventCallbacks() {
+ return event_callbacks_;
+}
+
+std::string WifiRttController::getIfaceName() {
+ return ifname_;
+}
+
+Return<void> WifiRttController::getBoundIface(getBoundIface_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+ &WifiRttController::getBoundIfaceInternal, hidl_status_cb);
+}
+
+Return<void> WifiRttController::registerEventCallback(
+ const sp<V1_0::IWifiRttControllerEventCallback>& callback,
+ registerEventCallback_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+ &WifiRttController::registerEventCallbackInternal, hidl_status_cb,
+ callback);
+}
+
+Return<void> WifiRttController::rangeRequest(uint32_t cmd_id,
+ const hidl_vec<V1_0::RttConfig>& rtt_configs,
+ rangeRequest_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+ &WifiRttController::rangeRequestInternal, hidl_status_cb, cmd_id,
+ rtt_configs);
+}
+
+Return<void> WifiRttController::rangeCancel(uint32_t cmd_id,
+ const hidl_vec<hidl_array<uint8_t, 6>>& addrs,
+ rangeCancel_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+ &WifiRttController::rangeCancelInternal, hidl_status_cb, cmd_id, addrs);
+}
+
+Return<void> WifiRttController::getCapabilities(getCapabilities_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+ &WifiRttController::getCapabilitiesInternal, hidl_status_cb);
+}
+
+Return<void> WifiRttController::setLci(uint32_t cmd_id, const RttLciInformation& lci,
+ setLci_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+ &WifiRttController::setLciInternal, hidl_status_cb, cmd_id, lci);
+}
+
+Return<void> WifiRttController::setLcr(uint32_t cmd_id, const RttLcrInformation& lcr,
+ setLcr_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+ &WifiRttController::setLcrInternal, hidl_status_cb, cmd_id, lcr);
+}
+
+Return<void> WifiRttController::getResponderInfo(getResponderInfo_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+ &WifiRttController::getResponderInfoInternal, hidl_status_cb);
+}
+
+Return<void> WifiRttController::enableResponder(uint32_t cmd_id,
+ const V1_0::WifiChannelInfo& channel_hint,
+ uint32_t max_duration_seconds,
+ const V1_0::RttResponder& info,
+ enableResponder_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+ &WifiRttController::enableResponderInternal, hidl_status_cb, cmd_id,
+ channel_hint, max_duration_seconds, info);
+}
+
+Return<void> WifiRttController::disableResponder(uint32_t cmd_id,
+ disableResponder_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+ &WifiRttController::disableResponderInternal, hidl_status_cb, cmd_id);
+}
+
+Return<void> WifiRttController::registerEventCallback_1_4(
+ const sp<V1_4::IWifiRttControllerEventCallback>& callback,
+ registerEventCallback_1_4_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+ &WifiRttController::registerEventCallbackInternal_1_4, hidl_status_cb,
+ callback);
+}
+
+Return<void> WifiRttController::rangeRequest_1_4(uint32_t cmd_id,
+ const hidl_vec<V1_4::RttConfig>& rtt_configs,
+ rangeRequest_1_4_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+ &WifiRttController::rangeRequestInternal_1_4, hidl_status_cb, cmd_id,
+ rtt_configs);
+}
+
+Return<void> WifiRttController::getCapabilities_1_4(getCapabilities_1_4_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+ &WifiRttController::getCapabilitiesInternal_1_4, hidl_status_cb);
+}
+
+Return<void> WifiRttController::getResponderInfo_1_4(getResponderInfo_1_4_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+ &WifiRttController::getResponderInfoInternal_1_4, hidl_status_cb);
+}
+
+Return<void> WifiRttController::enableResponder_1_4(uint32_t cmd_id,
+ const V1_0::WifiChannelInfo& channel_hint,
+ uint32_t max_duration_seconds,
+ const V1_4::RttResponder& info,
+ enableResponder_1_4_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+ &WifiRttController::enableResponderInternal_1_4, hidl_status_cb, cmd_id,
+ channel_hint, max_duration_seconds, info);
+}
+
+Return<void> WifiRttController::registerEventCallback_1_6(
+ const sp<V1_6::IWifiRttControllerEventCallback>& callback,
+ registerEventCallback_1_6_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+ &WifiRttController::registerEventCallbackInternal_1_6, hidl_status_cb,
+ callback);
+}
+
+Return<void> WifiRttController::rangeRequest_1_6(uint32_t cmd_id,
+ const hidl_vec<V1_6::RttConfig>& rtt_configs,
+ rangeRequest_1_6_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+ &WifiRttController::rangeRequestInternal_1_6, hidl_status_cb, cmd_id,
+ rtt_configs);
+}
+
+Return<void> WifiRttController::getCapabilities_1_6(getCapabilities_1_6_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+ &WifiRttController::getCapabilitiesInternal_1_6, hidl_status_cb);
+}
+
+Return<void> WifiRttController::getResponderInfo_1_6(getResponderInfo_1_6_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+ &WifiRttController::getResponderInfoInternal_1_6, hidl_status_cb);
+}
+
+Return<void> WifiRttController::enableResponder_1_6(uint32_t cmd_id,
+ const V1_6::WifiChannelInfo& channel_hint,
+ uint32_t max_duration_seconds,
+ const V1_6::RttResponder& info,
+ enableResponder_1_6_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+ &WifiRttController::enableResponderInternal_1_6, hidl_status_cb, cmd_id,
+ channel_hint, max_duration_seconds, info);
+}
+
+std::pair<WifiStatus, sp<IWifiIface>> WifiRttController::getBoundIfaceInternal() {
+ return {createWifiStatus(WifiStatusCode::SUCCESS), bound_iface_};
+}
+
+WifiStatus WifiRttController::registerEventCallbackInternal(
+ const sp<V1_0::IWifiRttControllerEventCallback>& /* callback */) {
+ // Deprecated support for this api
+ return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiRttController::rangeRequestInternal(
+ uint32_t /* cmd_id */, const std::vector<V1_0::RttConfig>& /* rtt_configs */) {
+ // Deprecated support for this api
+ return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiRttController::rangeCancelInternal(
+ uint32_t cmd_id, const std::vector<hidl_array<uint8_t, 6>>& addrs) {
+ std::vector<std::array<uint8_t, 6>> legacy_addrs;
+ for (const auto& addr : addrs) {
+ legacy_addrs.push_back(addr);
+ }
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->cancelRttRangeRequest(ifname_, cmd_id, legacy_addrs);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, V1_0::RttCapabilities> WifiRttController::getCapabilitiesInternal() {
+ // Deprecated support for this api
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
+}
+
+WifiStatus WifiRttController::setLciInternal(uint32_t cmd_id, const RttLciInformation& lci) {
+ legacy_hal::wifi_lci_information legacy_lci;
+ if (!hidl_struct_util::convertHidlRttLciInformationToLegacy(lci, &legacy_lci)) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->setRttLci(ifname_, cmd_id, legacy_lci);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiRttController::setLcrInternal(uint32_t cmd_id, const RttLcrInformation& lcr) {
+ legacy_hal::wifi_lcr_information legacy_lcr;
+ if (!hidl_struct_util::convertHidlRttLcrInformationToLegacy(lcr, &legacy_lcr)) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->setRttLcr(ifname_, cmd_id, legacy_lcr);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, V1_0::RttResponder> WifiRttController::getResponderInfoInternal() {
+ // Deprecated support for this api
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
+}
+
+WifiStatus WifiRttController::enableResponderInternal(
+ uint32_t /* cmd_id */, const V1_0::WifiChannelInfo& /* channel_hint */,
+ uint32_t /* max_duration_seconds */, const V1_0::RttResponder& /* info */) {
+ // Deprecated support for this api
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED)};
+}
+
+WifiStatus WifiRttController::disableResponderInternal(uint32_t cmd_id) {
+ legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->disableRttResponder(ifname_, cmd_id);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiRttController::registerEventCallbackInternal_1_4(
+ const sp<V1_4::IWifiRttControllerEventCallback>& /* callback */) {
+ // Deprecated support for this api
+ return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiRttController::rangeRequestInternal_1_4(
+ uint32_t /* cmd_id */, const std::vector<V1_4::RttConfig>& /* rtt_configs */) {
+ // Deprecated support for this api
+ return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+std::pair<WifiStatus, V1_4::RttCapabilities> WifiRttController::getCapabilitiesInternal_1_4() {
+ // Deprecated support for this api
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
+}
+
+std::pair<WifiStatus, V1_4::RttResponder> WifiRttController::getResponderInfoInternal_1_4() {
+ // Deprecated support for this api
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
+}
+
+WifiStatus WifiRttController::enableResponderInternal_1_4(
+ uint32_t /* cmd_id */, const V1_0::WifiChannelInfo& /* channel_hint */,
+ uint32_t /* max_duration_seconds */, const V1_4::RttResponder& /* info */) {
+ // Deprecated support for this api
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED)};
+}
+
+WifiStatus WifiRttController::registerEventCallbackInternal_1_6(
+ const sp<V1_6::IWifiRttControllerEventCallback>& callback) {
+ // TODO(b/31632518): remove the callback when the client is destroyed
+ event_callbacks_.emplace_back(callback);
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+WifiStatus WifiRttController::rangeRequestInternal_1_6(
+ uint32_t cmd_id, const std::vector<V1_6::RttConfig>& rtt_configs) {
+ std::vector<legacy_hal::wifi_rtt_config> legacy_configs;
+ if (!hidl_struct_util::convertHidlVectorOfRttConfigToLegacy(rtt_configs, &legacy_configs)) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ android::wp<WifiRttController> weak_ptr_this(this);
+ const auto& on_results_callback =
+ [weak_ptr_this](legacy_hal::wifi_request_id id,
+ const std::vector<const legacy_hal::wifi_rtt_result*>& results) {
+ const auto shared_ptr_this = weak_ptr_this.promote();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ std::vector<V1_6::RttResult> hidl_results;
+ if (!hidl_struct_util::convertLegacyVectorOfRttResultToHidl(results,
+ &hidl_results)) {
+ LOG(ERROR) << "Failed to convert rtt results to HIDL structs";
+ return;
+ }
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->onResults_1_6(id, hidl_results).isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ };
+ legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->startRttRangeRequest(
+ ifname_, cmd_id, legacy_configs, on_results_callback);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, V1_6::RttCapabilities> WifiRttController::getCapabilitiesInternal_1_6() {
+ legacy_hal::wifi_error legacy_status;
+ legacy_hal::wifi_rtt_capabilities legacy_caps;
+ std::tie(legacy_status, legacy_caps) = legacy_hal_.lock()->getRttCapabilities(ifname_);
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ return {createWifiStatusFromLegacyError(legacy_status), {}};
+ }
+ V1_6::RttCapabilities hidl_caps;
+ if (!hidl_struct_util::convertLegacyRttCapabilitiesToHidl(legacy_caps, &hidl_caps)) {
+ return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
+}
+
+std::pair<WifiStatus, V1_6::RttResponder> WifiRttController::getResponderInfoInternal_1_6() {
+ legacy_hal::wifi_error legacy_status;
+ legacy_hal::wifi_rtt_responder legacy_responder;
+ std::tie(legacy_status, legacy_responder) = legacy_hal_.lock()->getRttResponderInfo(ifname_);
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ return {createWifiStatusFromLegacyError(legacy_status), {}};
+ }
+ V1_6::RttResponder hidl_responder;
+ if (!hidl_struct_util::convertLegacyRttResponderToHidl(legacy_responder, &hidl_responder)) {
+ return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_responder};
+}
+
+WifiStatus WifiRttController::enableResponderInternal_1_6(uint32_t cmd_id,
+ const V1_6::WifiChannelInfo& channel_hint,
+ uint32_t max_duration_seconds,
+ const V1_6::RttResponder& info) {
+ legacy_hal::wifi_channel_info legacy_channel_info;
+ if (!hidl_struct_util::convertHidlWifiChannelInfoToLegacy(channel_hint, &legacy_channel_info)) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ legacy_hal::wifi_rtt_responder legacy_responder;
+ if (!hidl_struct_util::convertHidlRttResponderToLegacy(info, &legacy_responder)) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->enableRttResponder(
+ ifname_, cmd_id, legacy_channel_info, max_duration_seconds, legacy_responder);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.6/default/wifi_rtt_controller.h b/wifi/1.6/default/wifi_rtt_controller.h
new file mode 100644
index 0000000..fd5f68b
--- /dev/null
+++ b/wifi/1.6/default/wifi_rtt_controller.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_RTT_CONTROLLER_H_
+#define WIFI_RTT_CONTROLLER_H_
+
+#include <android-base/macros.h>
+#include <android/hardware/wifi/1.0/IWifiIface.h>
+#include <android/hardware/wifi/1.6/IWifiRttController.h>
+#include <android/hardware/wifi/1.6/IWifiRttControllerEventCallback.h>
+
+#include "wifi_legacy_hal.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+
+/**
+ * HIDL interface object used to control all RTT operations.
+ */
+class WifiRttController : public V1_6::IWifiRttController {
+ public:
+ WifiRttController(const std::string& iface_name, const sp<IWifiIface>& bound_iface,
+ const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
+ // Refer to |WifiChip::invalidate()|.
+ void invalidate();
+ bool isValid();
+ std::vector<sp<V1_6::IWifiRttControllerEventCallback>> getEventCallbacks();
+ std::string getIfaceName();
+
+ // HIDL methods exposed.
+ Return<void> getBoundIface(getBoundIface_cb hidl_status_cb) override;
+ Return<void> registerEventCallback(const sp<V1_0::IWifiRttControllerEventCallback>& callback,
+ registerEventCallback_cb hidl_status_cb) override;
+ Return<void> rangeRequest(uint32_t cmd_id, const hidl_vec<V1_0::RttConfig>& rtt_configs,
+ rangeRequest_cb hidl_status_cb) override;
+ Return<void> rangeCancel(uint32_t cmd_id, const hidl_vec<hidl_array<uint8_t, 6>>& addrs,
+ rangeCancel_cb hidl_status_cb) override;
+ Return<void> getCapabilities(getCapabilities_cb hidl_status_cb) override;
+ Return<void> setLci(uint32_t cmd_id, const RttLciInformation& lci,
+ setLci_cb hidl_status_cb) override;
+ Return<void> setLcr(uint32_t cmd_id, const RttLcrInformation& lcr,
+ setLcr_cb hidl_status_cb) override;
+ Return<void> getResponderInfo(getResponderInfo_cb hidl_status_cb) override;
+ Return<void> enableResponder(uint32_t cmd_id, const V1_0::WifiChannelInfo& channel_hint,
+ uint32_t max_duration_seconds, const V1_0::RttResponder& info,
+ enableResponder_cb hidl_status_cb) override;
+ Return<void> disableResponder(uint32_t cmd_id, disableResponder_cb hidl_status_cb) override;
+ Return<void> registerEventCallback_1_4(
+ const sp<V1_4::IWifiRttControllerEventCallback>& callback,
+ registerEventCallback_1_4_cb hidl_status_cb) override;
+ Return<void> rangeRequest_1_4(uint32_t cmd_id, const hidl_vec<V1_4::RttConfig>& rtt_configs,
+ rangeRequest_1_4_cb hidl_status_cb) override;
+ Return<void> getCapabilities_1_4(getCapabilities_1_4_cb hidl_status_cb) override;
+ Return<void> getResponderInfo_1_4(getResponderInfo_1_4_cb hidl_status_cb) override;
+ Return<void> enableResponder_1_4(uint32_t cmd_id, const V1_0::WifiChannelInfo& channel_hint,
+ uint32_t max_duration_seconds, const V1_4::RttResponder& info,
+ enableResponder_1_4_cb hidl_status_cb) override;
+ Return<void> registerEventCallback_1_6(
+ const sp<V1_6::IWifiRttControllerEventCallback>& callback,
+ registerEventCallback_1_6_cb hidl_status_cb) override;
+ Return<void> rangeRequest_1_6(uint32_t cmd_id, const hidl_vec<V1_6::RttConfig>& rtt_configs,
+ rangeRequest_1_6_cb hidl_status_cb) override;
+ Return<void> getCapabilities_1_6(getCapabilities_1_6_cb hidl_status_cb) override;
+ Return<void> getResponderInfo_1_6(getResponderInfo_1_6_cb hidl_status_cb) override;
+ Return<void> enableResponder_1_6(uint32_t cmd_id, const V1_6::WifiChannelInfo& channel_hint,
+ uint32_t max_duration_seconds, const V1_6::RttResponder& info,
+ enableResponder_1_6_cb hidl_status_cb) override;
+
+ private:
+ // Corresponding worker functions for the HIDL methods.
+ std::pair<WifiStatus, sp<IWifiIface>> getBoundIfaceInternal();
+ WifiStatus registerEventCallbackInternal(
+ const sp<V1_0::IWifiRttControllerEventCallback>& callback);
+ WifiStatus rangeRequestInternal(uint32_t cmd_id,
+ const std::vector<V1_0::RttConfig>& rtt_configs);
+ WifiStatus rangeCancelInternal(uint32_t cmd_id,
+ const std::vector<hidl_array<uint8_t, 6>>& addrs);
+ std::pair<WifiStatus, V1_0::RttCapabilities> getCapabilitiesInternal();
+ WifiStatus setLciInternal(uint32_t cmd_id, const RttLciInformation& lci);
+ WifiStatus setLcrInternal(uint32_t cmd_id, const RttLcrInformation& lcr);
+ std::pair<WifiStatus, V1_0::RttResponder> getResponderInfoInternal();
+ WifiStatus enableResponderInternal(uint32_t cmd_id, const V1_0::WifiChannelInfo& channel_hint,
+ uint32_t max_duration_seconds,
+ const V1_0::RttResponder& info);
+ WifiStatus disableResponderInternal(uint32_t cmd_id);
+ WifiStatus registerEventCallbackInternal_1_4(
+ const sp<V1_4::IWifiRttControllerEventCallback>& callback);
+ WifiStatus rangeRequestInternal_1_4(uint32_t cmd_id,
+ const std::vector<V1_4::RttConfig>& rtt_configs);
+ std::pair<WifiStatus, V1_4::RttCapabilities> getCapabilitiesInternal_1_4();
+ std::pair<WifiStatus, V1_4::RttResponder> getResponderInfoInternal_1_4();
+ WifiStatus enableResponderInternal_1_4(uint32_t cmd_id,
+ const V1_0::WifiChannelInfo& channel_hint,
+ uint32_t max_duration_seconds,
+ const V1_4::RttResponder& info);
+ WifiStatus registerEventCallbackInternal_1_6(
+ const sp<V1_6::IWifiRttControllerEventCallback>& callback);
+ WifiStatus rangeRequestInternal_1_6(uint32_t cmd_id,
+ const std::vector<V1_6::RttConfig>& rtt_configs);
+ std::pair<WifiStatus, V1_6::RttCapabilities> getCapabilitiesInternal_1_6();
+ std::pair<WifiStatus, V1_6::RttResponder> getResponderInfoInternal_1_6();
+ WifiStatus enableResponderInternal_1_6(uint32_t cmd_id,
+ const V1_6::WifiChannelInfo& channel_hint,
+ uint32_t max_duration_seconds,
+ const V1_6::RttResponder& info);
+
+ std::string ifname_;
+ sp<IWifiIface> bound_iface_;
+ std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+ std::vector<sp<V1_6::IWifiRttControllerEventCallback>> event_callbacks_;
+ bool is_valid_;
+
+ DISALLOW_COPY_AND_ASSIGN(WifiRttController);
+};
+
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+
+#endif // WIFI_RTT_CONTROLLER_H_
diff --git a/wifi/1.6/default/wifi_sta_iface.cpp b/wifi/1.6/default/wifi_sta_iface.cpp
new file mode 100644
index 0000000..dd11839
--- /dev/null
+++ b/wifi/1.6/default/wifi_sta_iface.cpp
@@ -0,0 +1,592 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+
+#include "hidl_return_util.h"
+#include "hidl_struct_util.h"
+#include "wifi_sta_iface.h"
+#include "wifi_status_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+using hidl_return_util::validateAndCall;
+
+WifiStaIface::WifiStaIface(const std::string& ifname,
+ const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+ const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util)
+ : ifname_(ifname), legacy_hal_(legacy_hal), iface_util_(iface_util), is_valid_(true) {
+ // Turn on DFS channel usage for STA iface.
+ legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->setDfsFlag(ifname_, true);
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ LOG(ERROR) << "Failed to set DFS flag; DFS channels may be unavailable.";
+ }
+}
+
+void WifiStaIface::invalidate() {
+ legacy_hal_.reset();
+ event_cb_handler_.invalidate();
+ is_valid_ = false;
+}
+
+bool WifiStaIface::isValid() {
+ return is_valid_;
+}
+
+std::string WifiStaIface::getName() {
+ return ifname_;
+}
+
+std::set<sp<IWifiStaIfaceEventCallback>> WifiStaIface::getEventCallbacks() {
+ return event_cb_handler_.getCallbacks();
+}
+
+Return<void> WifiStaIface::getName(getName_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::getNameInternal, hidl_status_cb);
+}
+
+Return<void> WifiStaIface::getType(getType_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::getTypeInternal, hidl_status_cb);
+}
+
+Return<void> WifiStaIface::registerEventCallback(const sp<IWifiStaIfaceEventCallback>& callback,
+ registerEventCallback_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::registerEventCallbackInternal, hidl_status_cb, callback);
+}
+
+Return<void> WifiStaIface::getCapabilities(getCapabilities_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::getCapabilitiesInternal, hidl_status_cb);
+}
+
+Return<void> WifiStaIface::getApfPacketFilterCapabilities(
+ getApfPacketFilterCapabilities_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::getApfPacketFilterCapabilitiesInternal, hidl_status_cb);
+}
+
+Return<void> WifiStaIface::installApfPacketFilter(uint32_t cmd_id, const hidl_vec<uint8_t>& program,
+ installApfPacketFilter_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::installApfPacketFilterInternal, hidl_status_cb, cmd_id,
+ program);
+}
+
+Return<void> WifiStaIface::readApfPacketFilterData(readApfPacketFilterData_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::readApfPacketFilterDataInternal, hidl_status_cb);
+}
+
+Return<void> WifiStaIface::getBackgroundScanCapabilities(
+ getBackgroundScanCapabilities_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::getBackgroundScanCapabilitiesInternal, hidl_status_cb);
+}
+
+Return<void> WifiStaIface::getValidFrequenciesForBand(
+ V1_0::WifiBand band, getValidFrequenciesForBand_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::getValidFrequenciesForBandInternal, hidl_status_cb, band);
+}
+
+Return<void> WifiStaIface::startBackgroundScan(uint32_t cmd_id,
+ const StaBackgroundScanParameters& params,
+ startBackgroundScan_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::startBackgroundScanInternal, hidl_status_cb, cmd_id,
+ params);
+}
+
+Return<void> WifiStaIface::stopBackgroundScan(uint32_t cmd_id,
+ stopBackgroundScan_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::stopBackgroundScanInternal, hidl_status_cb, cmd_id);
+}
+
+Return<void> WifiStaIface::enableLinkLayerStatsCollection(
+ bool debug, enableLinkLayerStatsCollection_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::enableLinkLayerStatsCollectionInternal, hidl_status_cb,
+ debug);
+}
+
+Return<void> WifiStaIface::disableLinkLayerStatsCollection(
+ disableLinkLayerStatsCollection_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::disableLinkLayerStatsCollectionInternal, hidl_status_cb);
+}
+
+Return<void> WifiStaIface::getLinkLayerStats(getLinkLayerStats_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::getLinkLayerStatsInternal, hidl_status_cb);
+}
+
+Return<void> WifiStaIface::getLinkLayerStats_1_3(getLinkLayerStats_1_3_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::getLinkLayerStatsInternal_1_3, hidl_status_cb);
+}
+
+Return<void> WifiStaIface::getLinkLayerStats_1_5(getLinkLayerStats_1_5_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::getLinkLayerStatsInternal_1_5, hidl_status_cb);
+}
+
+Return<void> WifiStaIface::getLinkLayerStats_1_6(getLinkLayerStats_1_6_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::getLinkLayerStatsInternal_1_6, hidl_status_cb);
+}
+
+Return<void> WifiStaIface::startRssiMonitoring(uint32_t cmd_id, int32_t max_rssi, int32_t min_rssi,
+ startRssiMonitoring_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::startRssiMonitoringInternal, hidl_status_cb, cmd_id,
+ max_rssi, min_rssi);
+}
+
+Return<void> WifiStaIface::stopRssiMonitoring(uint32_t cmd_id,
+ stopRssiMonitoring_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::stopRssiMonitoringInternal, hidl_status_cb, cmd_id);
+}
+
+Return<void> WifiStaIface::getRoamingCapabilities(getRoamingCapabilities_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::getRoamingCapabilitiesInternal, hidl_status_cb);
+}
+
+Return<void> WifiStaIface::configureRoaming(const StaRoamingConfig& config,
+ configureRoaming_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::configureRoamingInternal, hidl_status_cb, config);
+}
+
+Return<void> WifiStaIface::setRoamingState(StaRoamingState state,
+ setRoamingState_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::setRoamingStateInternal, hidl_status_cb, state);
+}
+
+Return<void> WifiStaIface::enableNdOffload(bool enable, enableNdOffload_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::enableNdOffloadInternal, hidl_status_cb, enable);
+}
+
+Return<void> WifiStaIface::startSendingKeepAlivePackets(
+ uint32_t cmd_id, const hidl_vec<uint8_t>& ip_packet_data, uint16_t ether_type,
+ const hidl_array<uint8_t, 6>& src_address, const hidl_array<uint8_t, 6>& dst_address,
+ uint32_t period_in_ms, startSendingKeepAlivePackets_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::startSendingKeepAlivePacketsInternal, hidl_status_cb,
+ cmd_id, ip_packet_data, ether_type, src_address, dst_address,
+ period_in_ms);
+}
+
+Return<void> WifiStaIface::stopSendingKeepAlivePackets(
+ uint32_t cmd_id, stopSendingKeepAlivePackets_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::stopSendingKeepAlivePacketsInternal, hidl_status_cb,
+ cmd_id);
+}
+
+Return<void> WifiStaIface::setScanningMacOui(const hidl_array<uint8_t, 3>& oui,
+ setScanningMacOui_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::setScanningMacOuiInternal, hidl_status_cb, oui);
+}
+
+Return<void> WifiStaIface::startDebugPacketFateMonitoring(
+ startDebugPacketFateMonitoring_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::startDebugPacketFateMonitoringInternal, hidl_status_cb);
+}
+
+Return<void> WifiStaIface::getDebugTxPacketFates(getDebugTxPacketFates_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::getDebugTxPacketFatesInternal, hidl_status_cb);
+}
+
+Return<void> WifiStaIface::getDebugRxPacketFates(getDebugRxPacketFates_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::getDebugRxPacketFatesInternal, hidl_status_cb);
+}
+
+Return<void> WifiStaIface::setMacAddress(const hidl_array<uint8_t, 6>& mac,
+ setMacAddress_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::setMacAddressInternal, hidl_status_cb, mac);
+}
+
+Return<void> WifiStaIface::getFactoryMacAddress(getFactoryMacAddress_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::getFactoryMacAddressInternal, hidl_status_cb);
+}
+
+Return<void> WifiStaIface::setScanMode(bool enable, setScanMode_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::setScanModeInternal, hidl_status_cb, enable);
+}
+
+std::pair<WifiStatus, std::string> WifiStaIface::getNameInternal() {
+ return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_};
+}
+
+std::pair<WifiStatus, IfaceType> WifiStaIface::getTypeInternal() {
+ return {createWifiStatus(WifiStatusCode::SUCCESS), IfaceType::STA};
+}
+
+WifiStatus WifiStaIface::registerEventCallbackInternal(
+ const sp<IWifiStaIfaceEventCallback>& callback) {
+ if (!event_cb_handler_.addCallback(callback)) {
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+ }
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+std::pair<WifiStatus, uint32_t> WifiStaIface::getCapabilitiesInternal() {
+ legacy_hal::wifi_error legacy_status;
+ uint64_t legacy_feature_set;
+ std::tie(legacy_status, legacy_feature_set) =
+ legacy_hal_.lock()->getSupportedFeatureSet(ifname_);
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ return {createWifiStatusFromLegacyError(legacy_status), 0};
+ }
+ uint32_t legacy_logger_feature_set;
+ std::tie(legacy_status, legacy_logger_feature_set) =
+ legacy_hal_.lock()->getLoggerSupportedFeatureSet(ifname_);
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ // some devices don't support querying logger feature set
+ legacy_logger_feature_set = 0;
+ }
+ uint32_t hidl_caps;
+ if (!hidl_struct_util::convertLegacyFeaturesToHidlStaCapabilities(
+ legacy_feature_set, legacy_logger_feature_set, &hidl_caps)) {
+ return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), 0};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
+}
+
+std::pair<WifiStatus, StaApfPacketFilterCapabilities>
+WifiStaIface::getApfPacketFilterCapabilitiesInternal() {
+ legacy_hal::wifi_error legacy_status;
+ legacy_hal::PacketFilterCapabilities legacy_caps;
+ std::tie(legacy_status, legacy_caps) = legacy_hal_.lock()->getPacketFilterCapabilities(ifname_);
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ return {createWifiStatusFromLegacyError(legacy_status), {}};
+ }
+ StaApfPacketFilterCapabilities hidl_caps;
+ if (!hidl_struct_util::convertLegacyApfCapabilitiesToHidl(legacy_caps, &hidl_caps)) {
+ return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
+}
+
+WifiStatus WifiStaIface::installApfPacketFilterInternal(uint32_t /* cmd_id */,
+ const std::vector<uint8_t>& program) {
+ legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->setPacketFilter(ifname_, program);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, std::vector<uint8_t>> WifiStaIface::readApfPacketFilterDataInternal() {
+ const std::pair<legacy_hal::wifi_error, std::vector<uint8_t>> legacy_status_and_data =
+ legacy_hal_.lock()->readApfPacketFilterData(ifname_);
+ return {createWifiStatusFromLegacyError(legacy_status_and_data.first),
+ std::move(legacy_status_and_data.second)};
+}
+
+std::pair<WifiStatus, StaBackgroundScanCapabilities>
+WifiStaIface::getBackgroundScanCapabilitiesInternal() {
+ legacy_hal::wifi_error legacy_status;
+ legacy_hal::wifi_gscan_capabilities legacy_caps;
+ std::tie(legacy_status, legacy_caps) = legacy_hal_.lock()->getGscanCapabilities(ifname_);
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ return {createWifiStatusFromLegacyError(legacy_status), {}};
+ }
+ StaBackgroundScanCapabilities hidl_caps;
+ if (!hidl_struct_util::convertLegacyGscanCapabilitiesToHidl(legacy_caps, &hidl_caps)) {
+ return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
+}
+
+std::pair<WifiStatus, std::vector<WifiChannelInMhz>>
+WifiStaIface::getValidFrequenciesForBandInternal(V1_0::WifiBand band) {
+ static_assert(sizeof(WifiChannelInMhz) == sizeof(uint32_t), "Size mismatch");
+ legacy_hal::wifi_error legacy_status;
+ std::vector<uint32_t> valid_frequencies;
+ std::tie(legacy_status, valid_frequencies) = legacy_hal_.lock()->getValidFrequenciesForBand(
+ ifname_, hidl_struct_util::convertHidlWifiBandToLegacy(band));
+ return {createWifiStatusFromLegacyError(legacy_status), valid_frequencies};
+}
+
+WifiStatus WifiStaIface::startBackgroundScanInternal(uint32_t cmd_id,
+ const StaBackgroundScanParameters& params) {
+ legacy_hal::wifi_scan_cmd_params legacy_params;
+ if (!hidl_struct_util::convertHidlGscanParamsToLegacy(params, &legacy_params)) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ android::wp<WifiStaIface> weak_ptr_this(this);
+ const auto& on_failure_callback = [weak_ptr_this](legacy_hal::wifi_request_id id) {
+ const auto shared_ptr_this = weak_ptr_this.promote();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->onBackgroundScanFailure(id).isOk()) {
+ LOG(ERROR) << "Failed to invoke onBackgroundScanFailure callback";
+ }
+ }
+ };
+ const auto& on_results_callback =
+ [weak_ptr_this](legacy_hal::wifi_request_id id,
+ const std::vector<legacy_hal::wifi_cached_scan_results>& results) {
+ const auto shared_ptr_this = weak_ptr_this.promote();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ std::vector<StaScanData> hidl_scan_datas;
+ if (!hidl_struct_util::convertLegacyVectorOfCachedGscanResultsToHidl(
+ results, &hidl_scan_datas)) {
+ LOG(ERROR) << "Failed to convert scan results to HIDL structs";
+ return;
+ }
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->onBackgroundScanResults(id, hidl_scan_datas).isOk()) {
+ LOG(ERROR) << "Failed to invoke onBackgroundScanResults callback";
+ }
+ }
+ };
+ const auto& on_full_result_callback = [weak_ptr_this](
+ legacy_hal::wifi_request_id id,
+ const legacy_hal::wifi_scan_result* result,
+ uint32_t buckets_scanned) {
+ const auto shared_ptr_this = weak_ptr_this.promote();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ StaScanResult hidl_scan_result;
+ if (!hidl_struct_util::convertLegacyGscanResultToHidl(*result, true, &hidl_scan_result)) {
+ LOG(ERROR) << "Failed to convert full scan results to HIDL structs";
+ return;
+ }
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->onBackgroundFullScanResult(id, buckets_scanned, hidl_scan_result)
+ .isOk()) {
+ LOG(ERROR) << "Failed to invoke onBackgroundFullScanResult callback";
+ }
+ }
+ };
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->startGscan(ifname_, cmd_id, legacy_params, on_failure_callback,
+ on_results_callback, on_full_result_callback);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::stopBackgroundScanInternal(uint32_t cmd_id) {
+ legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->stopGscan(ifname_, cmd_id);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::enableLinkLayerStatsCollectionInternal(bool debug) {
+ legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->enableLinkLayerStats(ifname_, debug);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::disableLinkLayerStatsCollectionInternal() {
+ legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->disableLinkLayerStats(ifname_);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, V1_0::StaLinkLayerStats> WifiStaIface::getLinkLayerStatsInternal() {
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
+}
+
+std::pair<WifiStatus, V1_3::StaLinkLayerStats> WifiStaIface::getLinkLayerStatsInternal_1_3() {
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
+}
+
+std::pair<WifiStatus, V1_5::StaLinkLayerStats> WifiStaIface::getLinkLayerStatsInternal_1_5() {
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
+}
+
+std::pair<WifiStatus, V1_6::StaLinkLayerStats> WifiStaIface::getLinkLayerStatsInternal_1_6() {
+ legacy_hal::wifi_error legacy_status;
+ legacy_hal::LinkLayerStats legacy_stats;
+ std::tie(legacy_status, legacy_stats) = legacy_hal_.lock()->getLinkLayerStats(ifname_);
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ return {createWifiStatusFromLegacyError(legacy_status), {}};
+ }
+ V1_6::StaLinkLayerStats hidl_stats;
+ if (!hidl_struct_util::convertLegacyLinkLayerStatsToHidl(legacy_stats, &hidl_stats)) {
+ return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_stats};
+}
+
+WifiStatus WifiStaIface::startRssiMonitoringInternal(uint32_t cmd_id, int32_t max_rssi,
+ int32_t min_rssi) {
+ android::wp<WifiStaIface> weak_ptr_this(this);
+ const auto& on_threshold_breached_callback = [weak_ptr_this](legacy_hal::wifi_request_id id,
+ std::array<uint8_t, 6> bssid,
+ int8_t rssi) {
+ const auto shared_ptr_this = weak_ptr_this.promote();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->onRssiThresholdBreached(id, bssid, rssi).isOk()) {
+ LOG(ERROR) << "Failed to invoke onRssiThresholdBreached callback";
+ }
+ }
+ };
+ legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->startRssiMonitoring(
+ ifname_, cmd_id, max_rssi, min_rssi, on_threshold_breached_callback);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::stopRssiMonitoringInternal(uint32_t cmd_id) {
+ legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->stopRssiMonitoring(ifname_, cmd_id);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, StaRoamingCapabilities> WifiStaIface::getRoamingCapabilitiesInternal() {
+ legacy_hal::wifi_error legacy_status;
+ legacy_hal::wifi_roaming_capabilities legacy_caps;
+ std::tie(legacy_status, legacy_caps) = legacy_hal_.lock()->getRoamingCapabilities(ifname_);
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ return {createWifiStatusFromLegacyError(legacy_status), {}};
+ }
+ StaRoamingCapabilities hidl_caps;
+ if (!hidl_struct_util::convertLegacyRoamingCapabilitiesToHidl(legacy_caps, &hidl_caps)) {
+ return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
+}
+
+WifiStatus WifiStaIface::configureRoamingInternal(const StaRoamingConfig& config) {
+ legacy_hal::wifi_roaming_config legacy_config;
+ if (!hidl_struct_util::convertHidlRoamingConfigToLegacy(config, &legacy_config)) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->configureRoaming(ifname_, legacy_config);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::setRoamingStateInternal(StaRoamingState state) {
+ legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->enableFirmwareRoaming(
+ ifname_, hidl_struct_util::convertHidlRoamingStateToLegacy(state));
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::enableNdOffloadInternal(bool enable) {
+ legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->configureNdOffload(ifname_, enable);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::startSendingKeepAlivePacketsInternal(
+ uint32_t cmd_id, const std::vector<uint8_t>& ip_packet_data, uint16_t ether_type,
+ const std::array<uint8_t, 6>& src_address, const std::array<uint8_t, 6>& dst_address,
+ uint32_t period_in_ms) {
+ legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->startSendingOffloadedPacket(
+ ifname_, cmd_id, ether_type, ip_packet_data, src_address, dst_address, period_in_ms);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::stopSendingKeepAlivePacketsInternal(uint32_t cmd_id) {
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->stopSendingOffloadedPacket(ifname_, cmd_id);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::setScanningMacOuiInternal(const std::array<uint8_t, 3>& /* oui */) {
+ // deprecated.
+ return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiStaIface::startDebugPacketFateMonitoringInternal() {
+ legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->startPktFateMonitoring(ifname_);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, std::vector<WifiDebugTxPacketFateReport>>
+WifiStaIface::getDebugTxPacketFatesInternal() {
+ legacy_hal::wifi_error legacy_status;
+ std::vector<legacy_hal::wifi_tx_report> legacy_fates;
+ std::tie(legacy_status, legacy_fates) = legacy_hal_.lock()->getTxPktFates(ifname_);
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ return {createWifiStatusFromLegacyError(legacy_status), {}};
+ }
+ std::vector<WifiDebugTxPacketFateReport> hidl_fates;
+ if (!hidl_struct_util::convertLegacyVectorOfDebugTxPacketFateToHidl(legacy_fates,
+ &hidl_fates)) {
+ return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_fates};
+}
+
+std::pair<WifiStatus, std::vector<WifiDebugRxPacketFateReport>>
+WifiStaIface::getDebugRxPacketFatesInternal() {
+ legacy_hal::wifi_error legacy_status;
+ std::vector<legacy_hal::wifi_rx_report> legacy_fates;
+ std::tie(legacy_status, legacy_fates) = legacy_hal_.lock()->getRxPktFates(ifname_);
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ return {createWifiStatusFromLegacyError(legacy_status), {}};
+ }
+ std::vector<WifiDebugRxPacketFateReport> hidl_fates;
+ if (!hidl_struct_util::convertLegacyVectorOfDebugRxPacketFateToHidl(legacy_fates,
+ &hidl_fates)) {
+ return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_fates};
+}
+
+WifiStatus WifiStaIface::setMacAddressInternal(const std::array<uint8_t, 6>& mac) {
+ bool status = iface_util_.lock()->setMacAddress(ifname_, mac);
+ if (!status) {
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+ }
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+std::pair<WifiStatus, std::array<uint8_t, 6>> WifiStaIface::getFactoryMacAddressInternal() {
+ std::array<uint8_t, 6> mac = iface_util_.lock()->getFactoryMacAddress(ifname_);
+ if (mac[0] == 0 && mac[1] == 0 && mac[2] == 0 && mac[3] == 0 && mac[4] == 0 && mac[5] == 0) {
+ return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), mac};
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), mac};
+}
+
+WifiStatus WifiStaIface::setScanModeInternal(bool enable) {
+ // OEM's need to implement this on their devices if needed.
+ LOG(WARNING) << "setScanModeInternal(" << enable << ") not supported";
+ return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.6/default/wifi_sta_iface.h b/wifi/1.6/default/wifi_sta_iface.h
new file mode 100644
index 0000000..c01c50b
--- /dev/null
+++ b/wifi/1.6/default/wifi_sta_iface.h
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_STA_IFACE_H_
+#define WIFI_STA_IFACE_H_
+
+#include <android-base/macros.h>
+#include <android/hardware/wifi/1.0/IWifiStaIfaceEventCallback.h>
+#include <android/hardware/wifi/1.6/IWifiStaIface.h>
+
+#include "hidl_callback_util.h"
+#include "wifi_iface_util.h"
+#include "wifi_legacy_hal.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+using namespace android::hardware::wifi::V1_0;
+
+/**
+ * HIDL interface object used to control a STA Iface instance.
+ */
+class WifiStaIface : public V1_6::IWifiStaIface {
+ public:
+ WifiStaIface(const std::string& ifname,
+ const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+ const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util);
+ // Refer to |WifiChip::invalidate()|.
+ void invalidate();
+ bool isValid();
+ std::set<sp<IWifiStaIfaceEventCallback>> getEventCallbacks();
+ std::string getName();
+
+ // HIDL methods exposed.
+ Return<void> getName(getName_cb hidl_status_cb) override;
+ Return<void> getType(getType_cb hidl_status_cb) override;
+ Return<void> registerEventCallback(const sp<IWifiStaIfaceEventCallback>& callback,
+ registerEventCallback_cb hidl_status_cb) override;
+ Return<void> getCapabilities(getCapabilities_cb hidl_status_cb) override;
+ Return<void> getApfPacketFilterCapabilities(
+ getApfPacketFilterCapabilities_cb hidl_status_cb) override;
+ Return<void> installApfPacketFilter(uint32_t cmd_id, const hidl_vec<uint8_t>& program,
+ installApfPacketFilter_cb hidl_status_cb) override;
+ Return<void> readApfPacketFilterData(readApfPacketFilterData_cb hidl_status_cb) override;
+ Return<void> getBackgroundScanCapabilities(
+ getBackgroundScanCapabilities_cb hidl_status_cb) override;
+ Return<void> getValidFrequenciesForBand(V1_0::WifiBand band,
+ getValidFrequenciesForBand_cb hidl_status_cb) override;
+ Return<void> startBackgroundScan(uint32_t cmd_id, const StaBackgroundScanParameters& params,
+ startBackgroundScan_cb hidl_status_cb) override;
+ Return<void> stopBackgroundScan(uint32_t cmd_id, stopBackgroundScan_cb hidl_status_cb) override;
+ Return<void> enableLinkLayerStatsCollection(
+ bool debug, enableLinkLayerStatsCollection_cb hidl_status_cb) override;
+ Return<void> disableLinkLayerStatsCollection(
+ disableLinkLayerStatsCollection_cb hidl_status_cb) override;
+ Return<void> getLinkLayerStats(getLinkLayerStats_cb hidl_status_cb) override;
+ Return<void> getLinkLayerStats_1_3(getLinkLayerStats_1_3_cb hidl_status_cb) override;
+ Return<void> getLinkLayerStats_1_5(getLinkLayerStats_1_5_cb hidl_status_cb) override;
+ Return<void> getLinkLayerStats_1_6(getLinkLayerStats_1_6_cb hidl_status_cb) override;
+ Return<void> startRssiMonitoring(uint32_t cmd_id, int32_t max_rssi, int32_t min_rssi,
+ startRssiMonitoring_cb hidl_status_cb) override;
+ Return<void> stopRssiMonitoring(uint32_t cmd_id, stopRssiMonitoring_cb hidl_status_cb) override;
+ Return<void> getRoamingCapabilities(getRoamingCapabilities_cb hidl_status_cb) override;
+ Return<void> configureRoaming(const StaRoamingConfig& config,
+ configureRoaming_cb hidl_status_cb) override;
+ Return<void> setRoamingState(StaRoamingState state, setRoamingState_cb hidl_status_cb) override;
+ Return<void> enableNdOffload(bool enable, enableNdOffload_cb hidl_status_cb) override;
+ Return<void> startSendingKeepAlivePackets(
+ uint32_t cmd_id, const hidl_vec<uint8_t>& ip_packet_data, uint16_t ether_type,
+ const hidl_array<uint8_t, 6>& src_address, const hidl_array<uint8_t, 6>& dst_address,
+ uint32_t period_in_ms, startSendingKeepAlivePackets_cb hidl_status_cb) override;
+ Return<void> stopSendingKeepAlivePackets(
+ uint32_t cmd_id, stopSendingKeepAlivePackets_cb hidl_status_cb) override;
+ Return<void> setScanningMacOui(const hidl_array<uint8_t, 3>& oui,
+ setScanningMacOui_cb hidl_status_cb) override;
+ Return<void> startDebugPacketFateMonitoring(
+ startDebugPacketFateMonitoring_cb hidl_status_cb) override;
+ Return<void> getDebugTxPacketFates(getDebugTxPacketFates_cb hidl_status_cb) override;
+ Return<void> getDebugRxPacketFates(getDebugRxPacketFates_cb hidl_status_cb) override;
+ Return<void> setMacAddress(const hidl_array<uint8_t, 6>& mac,
+ setMacAddress_cb hidl_status_cb) override;
+ Return<void> getFactoryMacAddress(getFactoryMacAddress_cb hidl_status_cb) override;
+ Return<void> setScanMode(bool enable, setScanMode_cb hidl_status_cb) override;
+
+ private:
+ // Corresponding worker functions for the HIDL methods.
+ std::pair<WifiStatus, std::string> getNameInternal();
+ std::pair<WifiStatus, IfaceType> getTypeInternal();
+ WifiStatus registerEventCallbackInternal(const sp<IWifiStaIfaceEventCallback>& callback);
+ std::pair<WifiStatus, uint32_t> getCapabilitiesInternal();
+ std::pair<WifiStatus, StaApfPacketFilterCapabilities> getApfPacketFilterCapabilitiesInternal();
+ WifiStatus installApfPacketFilterInternal(uint32_t cmd_id, const std::vector<uint8_t>& program);
+ std::pair<WifiStatus, std::vector<uint8_t>> readApfPacketFilterDataInternal();
+ std::pair<WifiStatus, StaBackgroundScanCapabilities> getBackgroundScanCapabilitiesInternal();
+ std::pair<WifiStatus, std::vector<WifiChannelInMhz>> getValidFrequenciesForBandInternal(
+ V1_0::WifiBand band);
+ WifiStatus startBackgroundScanInternal(uint32_t cmd_id,
+ const StaBackgroundScanParameters& params);
+ WifiStatus stopBackgroundScanInternal(uint32_t cmd_id);
+ WifiStatus enableLinkLayerStatsCollectionInternal(bool debug);
+ WifiStatus disableLinkLayerStatsCollectionInternal();
+ std::pair<WifiStatus, V1_0::StaLinkLayerStats> getLinkLayerStatsInternal();
+ std::pair<WifiStatus, V1_3::StaLinkLayerStats> getLinkLayerStatsInternal_1_3();
+ std::pair<WifiStatus, V1_5::StaLinkLayerStats> getLinkLayerStatsInternal_1_5();
+ std::pair<WifiStatus, V1_6::StaLinkLayerStats> getLinkLayerStatsInternal_1_6();
+ WifiStatus startRssiMonitoringInternal(uint32_t cmd_id, int32_t max_rssi, int32_t min_rssi);
+ WifiStatus stopRssiMonitoringInternal(uint32_t cmd_id);
+ std::pair<WifiStatus, StaRoamingCapabilities> getRoamingCapabilitiesInternal();
+ WifiStatus configureRoamingInternal(const StaRoamingConfig& config);
+ WifiStatus setRoamingStateInternal(StaRoamingState state);
+ WifiStatus enableNdOffloadInternal(bool enable);
+ WifiStatus startSendingKeepAlivePacketsInternal(uint32_t cmd_id,
+ const std::vector<uint8_t>& ip_packet_data,
+ uint16_t ether_type,
+ const std::array<uint8_t, 6>& src_address,
+ const std::array<uint8_t, 6>& dst_address,
+ uint32_t period_in_ms);
+ WifiStatus stopSendingKeepAlivePacketsInternal(uint32_t cmd_id);
+ WifiStatus setScanningMacOuiInternal(const std::array<uint8_t, 3>& oui);
+ WifiStatus startDebugPacketFateMonitoringInternal();
+ std::pair<WifiStatus, std::vector<WifiDebugTxPacketFateReport>> getDebugTxPacketFatesInternal();
+ std::pair<WifiStatus, std::vector<WifiDebugRxPacketFateReport>> getDebugRxPacketFatesInternal();
+ WifiStatus setMacAddressInternal(const std::array<uint8_t, 6>& mac);
+ std::pair<WifiStatus, std::array<uint8_t, 6>> getFactoryMacAddressInternal();
+ WifiStatus setScanModeInternal(bool enable);
+
+ std::string ifname_;
+ std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+ std::weak_ptr<iface_util::WifiIfaceUtil> iface_util_;
+ bool is_valid_;
+ hidl_callback_util::HidlCallbackHandler<IWifiStaIfaceEventCallback> event_cb_handler_;
+
+ DISALLOW_COPY_AND_ASSIGN(WifiStaIface);
+};
+
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+
+#endif // WIFI_STA_IFACE_H_
diff --git a/wifi/1.6/default/wifi_status_util.cpp b/wifi/1.6/default/wifi_status_util.cpp
new file mode 100644
index 0000000..3b18e53
--- /dev/null
+++ b/wifi/1.6/default/wifi_status_util.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "wifi_status_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+
+std::string legacyErrorToString(legacy_hal::wifi_error error) {
+ switch (error) {
+ case legacy_hal::WIFI_SUCCESS:
+ return "SUCCESS";
+ case legacy_hal::WIFI_ERROR_UNINITIALIZED:
+ return "UNINITIALIZED";
+ case legacy_hal::WIFI_ERROR_NOT_AVAILABLE:
+ return "NOT_AVAILABLE";
+ case legacy_hal::WIFI_ERROR_NOT_SUPPORTED:
+ return "NOT_SUPPORTED";
+ case legacy_hal::WIFI_ERROR_INVALID_ARGS:
+ return "INVALID_ARGS";
+ case legacy_hal::WIFI_ERROR_INVALID_REQUEST_ID:
+ return "INVALID_REQUEST_ID";
+ case legacy_hal::WIFI_ERROR_TIMED_OUT:
+ return "TIMED_OUT";
+ case legacy_hal::WIFI_ERROR_TOO_MANY_REQUESTS:
+ return "TOO_MANY_REQUESTS";
+ case legacy_hal::WIFI_ERROR_OUT_OF_MEMORY:
+ return "OUT_OF_MEMORY";
+ case legacy_hal::WIFI_ERROR_BUSY:
+ return "BUSY";
+ case legacy_hal::WIFI_ERROR_UNKNOWN:
+ return "UNKNOWN";
+ default:
+ return "UNKNOWN ERROR";
+ }
+}
+
+WifiStatus createWifiStatus(WifiStatusCode code, const std::string& description) {
+ return {code, description};
+}
+
+WifiStatus createWifiStatus(WifiStatusCode code) {
+ return createWifiStatus(code, "");
+}
+
+WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error, const std::string& desc) {
+ switch (error) {
+ case legacy_hal::WIFI_ERROR_UNINITIALIZED:
+ case legacy_hal::WIFI_ERROR_NOT_AVAILABLE:
+ return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE, desc);
+
+ case legacy_hal::WIFI_ERROR_NOT_SUPPORTED:
+ return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED, desc);
+
+ case legacy_hal::WIFI_ERROR_INVALID_ARGS:
+ case legacy_hal::WIFI_ERROR_INVALID_REQUEST_ID:
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS, desc);
+
+ case legacy_hal::WIFI_ERROR_TIMED_OUT:
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, desc + ", timed out");
+
+ case legacy_hal::WIFI_ERROR_TOO_MANY_REQUESTS:
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, desc + ", too many requests");
+
+ case legacy_hal::WIFI_ERROR_OUT_OF_MEMORY:
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, desc + ", out of memory");
+
+ case legacy_hal::WIFI_ERROR_BUSY:
+ return createWifiStatus(WifiStatusCode::ERROR_BUSY);
+
+ case legacy_hal::WIFI_ERROR_NONE:
+ return createWifiStatus(WifiStatusCode::SUCCESS, desc);
+
+ case legacy_hal::WIFI_ERROR_UNKNOWN:
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, "unknown");
+
+ default:
+ return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, "unknown error");
+ }
+}
+
+WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error) {
+ return createWifiStatusFromLegacyError(error, "");
+}
+
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.6/default/wifi_status_util.h b/wifi/1.6/default/wifi_status_util.h
new file mode 100644
index 0000000..ea1c294
--- /dev/null
+++ b/wifi/1.6/default/wifi_status_util.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_STATUS_UTIL_H_
+#define WIFI_STATUS_UTIL_H_
+
+#include <android/hardware/wifi/1.4/IWifi.h>
+
+#include "wifi_legacy_hal.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_6 {
+namespace implementation {
+using namespace android::hardware::wifi::V1_0;
+
+std::string legacyErrorToString(legacy_hal::wifi_error error);
+WifiStatus createWifiStatus(WifiStatusCode code, const std::string& description);
+WifiStatus createWifiStatus(WifiStatusCode code);
+WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error,
+ const std::string& description);
+WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error);
+
+} // namespace implementation
+} // namespace V1_6
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+
+#endif // WIFI_STATUS_UTIL_H_
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/IWifiNanIface.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiNanIface.aidl
index 070ca24..3dff5bf 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiNanIface.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiNanIface.aidl
@@ -50,6 +50,10 @@
void stopSubscribeRequest(in char cmdId, in byte sessionId);
void terminateDataPathRequest(in char cmdId, in int ndpInstanceId);
void transmitFollowupRequest(in char cmdId, in android.hardware.wifi.NanTransmitFollowupRequest msg);
+ void initiatePairingRequest(in char cmdId, in android.hardware.wifi.NanPairingRequest msg);
+ void respondToPairingIndicationRequest(in char cmdId, in android.hardware.wifi.NanRespondToPairingIndicationRequest msg);
+ void initiateBootstrappingRequest(in char cmdId, in android.hardware.wifi.NanBootstrappingRequest msg);
+ void respondToBootstrappingIndicationRequest(in char cmdId, in android.hardware.wifi.NanBootstrappingResponse msg);
const int MIN_DATA_PATH_CONFIG_PASSPHRASE_LENGTH = 8;
const int MAX_DATA_PATH_CONFIG_PASSPHRASE_LENGTH = 63;
}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiNanIfaceEventCallback.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiNanIfaceEventCallback.aidl
index 591cd8c..b6c9d1f 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiNanIfaceEventCallback.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiNanIfaceEventCallback.aidl
@@ -60,4 +60,12 @@
oneway void notifyStopSubscribeResponse(in char id, in android.hardware.wifi.NanStatus status);
oneway void notifyTerminateDataPathResponse(in char id, in android.hardware.wifi.NanStatus status);
oneway void notifyTransmitFollowupResponse(in char id, in android.hardware.wifi.NanStatus status);
+ oneway void eventPairingRequest(in android.hardware.wifi.NanPairingRequestInd event);
+ oneway void eventPairingConfirm(in android.hardware.wifi.NanPairingConfirmInd event);
+ oneway void notifyInitiatePairingResponse(in char id, in android.hardware.wifi.NanStatus status, in int pairingInstanceId);
+ oneway void notifyRespondToPairingIndicationResponse(in char id, in android.hardware.wifi.NanStatus status);
+ oneway void eventBootstrappingRequest(in android.hardware.wifi.NanBootstrappingRequestInd event);
+ oneway void eventBootstrappingConfirm(in android.hardware.wifi.NanBootstrappingConfirmInd event);
+ oneway void notifyInitiateBootstrappingResponse(in char id, in android.hardware.wifi.NanStatus status, in int bootstrappingInstanceId);
+ oneway void notifyRespondToBootstrappingIndicationResponse(in char id, in android.hardware.wifi.NanStatus status);
}
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/NanBootstrappingConfirmInd.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/NanBootstrappingConfirmInd.aidl
index 8ad4848..65e85af 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/NanBootstrappingConfirmInd.aidl
@@ -31,27 +31,10 @@
// with such a backward incompatible 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 NanBootstrappingConfirmInd {
+ int bootstrappingInstanceId;
+ boolean acceptRequest;
+ android.hardware.wifi.NanStatus reasonCode;
}
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/NanBootstrappingMethod.aidl
similarity index 74%
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/NanBootstrappingMethod.aidl
index 8ad4848..e5f0975 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/NanBootstrappingMethod.aidl
@@ -31,27 +31,18 @@
// with such a backward incompatible 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.wifi;
+@Backing(type="int") @VintfStability
+enum NanBootstrappingMethod {
+ BOOTSTRAPPING_OPPORTUNISTIC_MASK = 1,
+ BOOTSTRAPPING_PIN_CODE_DISPLAY_MASK = 2,
+ BOOTSTRAPPING_PASSPHRASE_DISPLAY_MASK = 4,
+ BOOTSTRAPPING_QR_DISPLAY_MASK = 8,
+ BOOTSTRAPPING_NFC_TAG_MASK = 16,
+ BOOTSTRAPPING_PIN_CODE_KEYPAD_MASK = 32,
+ BOOTSTRAPPING_PASSPHRASE_KEYPAD_MASK = 64,
+ BOOTSTRAPPING_QR_SCAN_MASK = 128,
+ BOOTSTRAPPING_NFC_READER_MASK = 256,
+ BOOTSTRAPPING_SERVICE_MANAGED_MASK = 16384,
+ BOOTSTRAPPING_HANDSHAKE_SHIP_MASK = 32768,
}
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/NanBootstrappingRequest.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/NanBootstrappingRequest.aidl
index 8ad4848..2be8924 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/NanBootstrappingRequest.aidl
@@ -31,27 +31,10 @@
// with such a backward incompatible 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 NanBootstrappingRequest {
+ int peerId;
+ byte[6] peerDiscMacAddr;
+ android.hardware.wifi.NanBootstrappingMethod requestBootstrappingMethod;
}
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/NanBootstrappingRequestInd.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/NanBootstrappingRequestInd.aidl
index 8ad4848..a4398e9 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/NanBootstrappingRequestInd.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.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 NanBootstrappingRequestInd {
+ byte discoverySessionId;
+ int peerId;
+ byte[6] peerDiscMacAddr;
+ int bootstrappingInstanceId;
+ android.hardware.wifi.NanBootstrappingMethod requestBootstrappingMethod;
}
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/NanBootstrappingResponse.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/NanBootstrappingResponse.aidl
index 8ad4848..6dd9b26 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/NanBootstrappingResponse.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 NanBootstrappingResponse {
+ int bootstrappingInstanceId;
+ boolean acceptRequest;
}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanCapabilities.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanCapabilities.aidl
index c44654e..5b59945 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanCapabilities.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanCapabilities.aidl
@@ -49,4 +49,7 @@
int maxSubscribeInterfaceAddresses;
android.hardware.wifi.NanCipherSuiteType supportedCipherSuites;
boolean instantCommunicationModeSupportFlag;
+ boolean supports6g;
+ boolean supportsHe;
+ boolean supportsPairing;
}
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/NanIdentityResolutionAttribute.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/NanIdentityResolutionAttribute.aidl
index 8ad4848..843107e 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/NanIdentityResolutionAttribute.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 NanIdentityResolutionAttribute {
+ byte[8] nonce;
+ byte[8] tag;
}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanMatchInd.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanMatchInd.aidl
index ae430c4..6757bec 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanMatchInd.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanMatchInd.aidl
@@ -49,4 +49,6 @@
int rangingMeasurementInMm;
android.hardware.wifi.NanRangingIndication rangingIndicationType;
byte[] scid;
+ android.hardware.wifi.NanPairingConfig peerPairingConfig;
+ android.hardware.wifi.NanIdentityResolutionAttribute peerNira;
}
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/NanPairingAkm.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/NanPairingAkm.aidl
index 8ad4848..05bbaee 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/NanPairingAkm.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;
-@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.wifi;
+@Backing(type="int") @VintfStability
+enum NanPairingAkm {
+ SAE = 0,
+ PASN = 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/NanPairingConfig.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/NanPairingConfig.aidl
index 8ad4848..1c04a96 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/NanPairingConfig.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.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 NanPairingConfig {
+ boolean enablePairingSetup;
+ boolean enablePairingCache;
+ boolean enablePairingVerification;
+ int supportedBootstrappingMethods;
}
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/NanPairingConfirmInd.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/NanPairingConfirmInd.aidl
index 8ad4848..8ecf22a 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/NanPairingConfirmInd.aidl
@@ -31,27 +31,13 @@
// with such a backward incompatible 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 NanPairingConfirmInd {
+ int pairingInstanceId;
+ boolean pairingSuccess;
+ android.hardware.wifi.NanStatus status;
+ android.hardware.wifi.NanPairingRequestType requestType;
+ boolean enablePairingCache;
+ android.hardware.wifi.NpkSecurityAssociation npksa;
}
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/NanPairingRequest.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/NanPairingRequest.aidl
index 8ad4848..2a644ae 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/NanPairingRequest.aidl
@@ -31,27 +31,13 @@
// with such a backward incompatible 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 NanPairingRequest {
+ int peerId;
+ byte[6] peerDiscMacAddr;
+ android.hardware.wifi.NanPairingRequestType requestType;
+ boolean enablePairingCache;
+ byte[16] pairingIdentityKey;
+ android.hardware.wifi.NanPairingSecurityConfig securityConfig;
}
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/NanPairingRequestInd.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/NanPairingRequestInd.aidl
index 8ad4848..66762b9 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/NanPairingRequestInd.aidl
@@ -31,27 +31,14 @@
// with such a backward incompatible 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 NanPairingRequestInd {
+ byte discoverySessionId;
+ int peerId;
+ byte[6] peerDiscMacAddr;
+ int pairingInstanceId;
+ android.hardware.wifi.NanPairingRequestType requestType;
+ boolean enablePairingCache;
+ android.hardware.wifi.NanIdentityResolutionAttribute peerNira;
}
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/NanPairingRequestType.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/NanPairingRequestType.aidl
index 8ad4848..9e73e80 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/NanPairingRequestType.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;
-@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.wifi;
+@Backing(type="int") @VintfStability
+enum NanPairingRequestType {
+ NAN_PAIRING_SETUP = 0,
+ NAN_PAIRING_VERIFICATION = 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/NanPairingSecurityConfig.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/NanPairingSecurityConfig.aidl
index 8ad4848..45af25d 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/NanPairingSecurityConfig.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.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 NanPairingSecurityConfig {
+ android.hardware.wifi.NanPairingSecurityType securityType;
+ byte[32] pmk;
+ byte[] passphrase;
+ android.hardware.wifi.NanPairingAkm akm;
}
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/NanPairingSecurityType.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/NanPairingSecurityType.aidl
index 8ad4848..a08a00f 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/NanPairingSecurityType.aidl
@@ -31,27 +31,10 @@
// with such a backward incompatible 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.wifi;
+@Backing(type="int") @VintfStability
+enum NanPairingSecurityType {
+ OPPORTUNISTIC = 0,
+ PMK = 1,
+ PASSPHRASE = 2,
}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPublishRequest.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPublishRequest.aidl
index d8d6b1b..c49f5f9 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPublishRequest.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPublishRequest.aidl
@@ -38,4 +38,6 @@
android.hardware.wifi.NanPublishType publishType;
android.hardware.wifi.NanTxType txType;
boolean autoAcceptDataPathRequests;
+ android.hardware.wifi.NanPairingConfig pairingConfig;
+ byte[16] identityKey;
}
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/NanRespondToPairingIndicationRequest.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/NanRespondToPairingIndicationRequest.aidl
index 8ad4848..a58890c 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/NanRespondToPairingIndicationRequest.aidl
@@ -31,27 +31,13 @@
// with such a backward incompatible 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 NanRespondToPairingIndicationRequest {
+ boolean acceptRequest;
+ int pairingInstanceId;
+ android.hardware.wifi.NanPairingRequestType requestType;
+ boolean enablePairingCache;
+ byte[16] pairingIdentityKey;
+ android.hardware.wifi.NanPairingSecurityConfig securityConfig;
}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanStatusCode.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanStatusCode.aidl
index 9eaf518..0fe2245 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanStatusCode.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanStatusCode.aidl
@@ -47,4 +47,6 @@
ALREADY_ENABLED = 10,
FOLLOWUP_TX_QUEUE_FULL = 11,
UNSUPPORTED_CONCURRENCY_NAN_DISABLED = 12,
+ INVALID_PAIRING_ID = 13,
+ INVALID_BOOTSTRAPPING_ID = 14,
}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanSubscribeRequest.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanSubscribeRequest.aidl
index bf176a5..96be096 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanSubscribeRequest.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanSubscribeRequest.aidl
@@ -41,4 +41,6 @@
boolean shouldUseSrf;
boolean isSsiRequiredForMatch;
android.hardware.wifi.MacAddress[] intfAddr;
+ android.hardware.wifi.NanPairingConfig pairingConfig;
+ byte[16] identityKey;
}
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/NpkSecurityAssociation.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/NpkSecurityAssociation.aidl
index 8ad4848..c558716 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/NpkSecurityAssociation.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.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 NpkSecurityAssociation {
+ byte[16] peerNanIdentityKey;
+ byte[16] localNanIdentityKey;
+ byte[32] npk;
+ android.hardware.wifi.NanPairingAkm akm;
}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttBw.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttBw.aidl
index bd7efff..f5bf894 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttBw.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttBw.aidl
@@ -34,6 +34,7 @@
package android.hardware.wifi;
@Backing(type="int") @VintfStability
enum RttBw {
+ BW_UNSPECIFIED = 0,
BW_5MHZ = 1,
BW_10MHZ = 2,
BW_20MHZ = 4,
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttResult.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttResult.aidl
index 743e0bd..8375dcb 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttResult.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttResult.aidl
@@ -57,4 +57,6 @@
int negotiatedBurstNum;
android.hardware.wifi.WifiInformationElement lci;
android.hardware.wifi.WifiInformationElement lcr;
+ int channelFreqMHz;
+ android.hardware.wifi.RttBw packetBw;
}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaLinkLayerIfaceStats.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaLinkLayerIfaceStats.aidl
index cf68fc6..a419207 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaLinkLayerIfaceStats.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaLinkLayerIfaceStats.aidl
@@ -34,16 +34,5 @@
package android.hardware.wifi;
@VintfStability
parcelable StaLinkLayerIfaceStats {
- int beaconRx;
- int avgRssiMgmt;
- android.hardware.wifi.StaLinkLayerIfacePacketStats wmeBePktStats;
- android.hardware.wifi.StaLinkLayerIfacePacketStats wmeBkPktStats;
- android.hardware.wifi.StaLinkLayerIfacePacketStats wmeViPktStats;
- android.hardware.wifi.StaLinkLayerIfacePacketStats wmeVoPktStats;
- byte timeSliceDutyCycleInPercent;
- android.hardware.wifi.StaLinkLayerIfaceContentionTimeStats wmeBeContentionTimeStats;
- android.hardware.wifi.StaLinkLayerIfaceContentionTimeStats wmeBkContentionTimeStats;
- android.hardware.wifi.StaLinkLayerIfaceContentionTimeStats wmeViContentionTimeStats;
- android.hardware.wifi.StaLinkLayerIfaceContentionTimeStats wmeVoContentionTimeStats;
- android.hardware.wifi.StaPeerInfo[] peers;
+ android.hardware.wifi.StaLinkLayerLinkStats[] links;
}
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/StaLinkLayerLinkStats.aidl
similarity index 66%
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/StaLinkLayerLinkStats.aidl
index 8ad4848..2bc3254 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/StaLinkLayerLinkStats.aidl
@@ -31,27 +31,22 @@
// with such a backward incompatible 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 StaLinkLayerLinkStats {
+ int linkId;
+ int radioId;
+ int frequencyMhz;
+ int beaconRx;
+ int avgRssiMgmt;
+ android.hardware.wifi.StaLinkLayerIfacePacketStats wmeBePktStats;
+ android.hardware.wifi.StaLinkLayerIfacePacketStats wmeBkPktStats;
+ android.hardware.wifi.StaLinkLayerIfacePacketStats wmeViPktStats;
+ android.hardware.wifi.StaLinkLayerIfacePacketStats wmeVoPktStats;
+ byte timeSliceDutyCycleInPercent;
+ android.hardware.wifi.StaLinkLayerIfaceContentionTimeStats wmeBeContentionTimeStats;
+ android.hardware.wifi.StaLinkLayerIfaceContentionTimeStats wmeBkContentionTimeStats;
+ android.hardware.wifi.StaLinkLayerIfaceContentionTimeStats wmeViContentionTimeStats;
+ android.hardware.wifi.StaLinkLayerIfaceContentionTimeStats wmeVoContentionTimeStats;
+ android.hardware.wifi.StaPeerInfo[] peers;
}
diff --git a/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/IWifiNanIface.aidl b/wifi/aidl/android/hardware/wifi/IWifiNanIface.aidl
index 45644b4..31c7ece 100644
--- a/wifi/aidl/android/hardware/wifi/IWifiNanIface.aidl
+++ b/wifi/aidl/android/hardware/wifi/IWifiNanIface.aidl
@@ -17,12 +17,16 @@
package android.hardware.wifi;
import android.hardware.wifi.IWifiNanIfaceEventCallback;
+import android.hardware.wifi.NanBootstrappingRequest;
+import android.hardware.wifi.NanBootstrappingResponse;
import android.hardware.wifi.NanConfigRequest;
import android.hardware.wifi.NanConfigRequestSupplemental;
import android.hardware.wifi.NanEnableRequest;
import android.hardware.wifi.NanInitiateDataPathRequest;
+import android.hardware.wifi.NanPairingRequest;
import android.hardware.wifi.NanPublishRequest;
import android.hardware.wifi.NanRespondToDataPathIndicationRequest;
+import android.hardware.wifi.NanRespondToPairingIndicationRequest;
import android.hardware.wifi.NanSubscribeRequest;
import android.hardware.wifi.NanTransmitFollowupRequest;
@@ -248,4 +252,62 @@
* |WifiStatusCode.ERROR_UNKNOWN|
*/
void transmitFollowupRequest(in char cmdId, in NanTransmitFollowupRequest msg);
+
+ /**
+ * Initiate a NAN pairing operation: Initiator.
+ * Asynchronous response is with |IWifiNanIfaceEventCallback.notifyInitiatePairingResponse|.
+ *
+ * @param cmdId Command Id to use for this invocation.
+ * @param msg Instance of |NanPairingRequest|.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_INVALID_ARGS|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ void initiatePairingRequest(in char cmdId, in NanPairingRequest msg);
+
+ /**
+ * Respond to a received request indication of NAN pairing setup operation.
+ * An indication is received by the Responder from the Initiator.
+ * Asynchronous response is with
+ * |IWifiNanIfaceEventCallback.notifyRespondToPairingIndicationResponse|.
+ *
+ * @param cmdId Command Id to use for this invocation.
+ * @param msg Instance of |NanRespondToPairingIndicationRequest|.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_INVALID_ARGS|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ void respondToPairingIndicationRequest(
+ in char cmdId, in NanRespondToPairingIndicationRequest msg);
+
+ /**
+ * Initiate a NAN pairing bootstrapping operation: Initiator.
+ * Asynchronous response is with
+ * |IWifiNanIfaceEventCallback.notifyInitiateBootstrappingResponse|.
+ *
+ * @param cmdId Command Id to use for this invocation.
+ * @param msg Instance of |NanBootstrappingRequest|.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_INVALID_ARGS|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ void initiateBootstrappingRequest(in char cmdId, in NanBootstrappingRequest msg);
+
+ /**
+ * Respond to a received request indication of NAN pairing bootstrapping operation.
+ * An indication is received by the Responder from the Initiator.
+ * Asynchronous response is with
+ * |IWifiNanIfaceEventCallback.notifyRespondToPairingIndicationResponse|.
+ *
+ * @param cmdId Command Id to use for this invocation.
+ * @param msg Instance of |notifyRespondToBootstrappingIndicationResponse|.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+ * |WifiStatusCode.ERROR_INVALID_ARGS|,
+ * |WifiStatusCode.ERROR_UNKNOWN|
+ */
+ void respondToBootstrappingIndicationRequest(in char cmdId, in NanBootstrappingResponse msg);
}
diff --git a/wifi/aidl/android/hardware/wifi/IWifiNanIfaceEventCallback.aidl b/wifi/aidl/android/hardware/wifi/IWifiNanIfaceEventCallback.aidl
index 470b7ba..6b06def 100644
--- a/wifi/aidl/android/hardware/wifi/IWifiNanIfaceEventCallback.aidl
+++ b/wifi/aidl/android/hardware/wifi/IWifiNanIfaceEventCallback.aidl
@@ -16,6 +16,8 @@
package android.hardware.wifi;
+import android.hardware.wifi.NanBootstrappingConfirmInd;
+import android.hardware.wifi.NanBootstrappingRequestInd;
import android.hardware.wifi.NanCapabilities;
import android.hardware.wifi.NanClusterEventInd;
import android.hardware.wifi.NanDataPathConfirmInd;
@@ -23,6 +25,8 @@
import android.hardware.wifi.NanDataPathScheduleUpdateInd;
import android.hardware.wifi.NanFollowupReceivedInd;
import android.hardware.wifi.NanMatchInd;
+import android.hardware.wifi.NanPairingConfirmInd;
+import android.hardware.wifi.NanPairingRequestInd;
import android.hardware.wifi.NanStatus;
/**
@@ -319,4 +323,95 @@
* |NanStatusCode.FOLLOWUP_TX_QUEUE_FULL|
*/
void notifyTransmitFollowupResponse(in char id, in NanStatus status);
+
+ /**
+ * Callback indicating that a NAN pairing setup/verification has been requested by
+ * an Initiator peer (received by the intended Responder).
+ *
+ * @param event NanPairingRequestInd containing event details.
+ */
+ void eventPairingRequest(in NanPairingRequestInd event);
+
+ /**
+ * Callback indicating that a NAN pairing setup/verification has been completed.
+ * Received by both Initiator and Responder.
+ *
+ * @param event NanPairingConfirmInd containing event details.
+ */
+ void eventPairingConfirm(in NanPairingConfirmInd event);
+
+ /**
+ * Callback invoked in response to an initiate NAN pairing request
+ * |IWifiNanIface.initiatePairingRequest|.
+ *
+ * @param cmdId Command Id corresponding to the original request.
+ * @param status NanStatus of the operation. Possible status codes are:
+ * |NanStatusCode.SUCCESS|
+ * |NanStatusCode.INVALID_ARGS|
+ * |NanStatusCode.INTERNAL_FAILURE|
+ * |NanStatusCode.PROTOCOL_FAILURE|
+ * |NanStatusCode.INVALID_PEER_ID|
+ * @param pairingInstanceId ID of the new pairing being negotiated (on successful status).
+ */
+ void notifyInitiatePairingResponse(in char id, in NanStatus status, in int pairingInstanceId);
+
+ /**
+ * Callback invoked in response to a respond to NAN pairing indication request
+ * |IWifiNanIface.respondToPairingIndicationRequest|.
+ *
+ * @param cmdId Command Id corresponding to the original request.
+ * @param status NanStatus of the operation. Possible status codes are:
+ * |NanStatusCode.SUCCESS|
+ * |NanStatusCode.INVALID_ARGS|
+ * |NanStatusCode.INTERNAL_FAILURE|
+ * |NanStatusCode.PROTOCOL_FAILURE|
+ * |NanStatusCode.INVALID_NDP_ID|
+ */
+ void notifyRespondToPairingIndicationResponse(in char id, in NanStatus status);
+
+ /**
+ * Callback indicating that a NAN bootstrapping setup has been requested by
+ * an Initiator peer (received by the intended Responder).
+ *
+ * @param event NanBootstrappingRequestInd containing event details.
+ */
+ void eventBootstrappingRequest(in NanBootstrappingRequestInd event);
+
+ /**
+ * Callback indicating that a NAN bootstrapping setuphas been completed.
+ * Received by Initiator.
+ *
+ * @param event NanBootstrappingConfirmInd containing event details.
+ */
+ void eventBootstrappingConfirm(in NanBootstrappingConfirmInd event);
+
+ /**
+ * Callback invoked in response to an initiate NAN pairing bootstrapping request
+ * |IWifiNanIface.initiateBootstrappingRequest|.
+ *
+ * @param cmdId Command Id corresponding to the original request.
+ * @param status NanStatus of the operation. Possible status codes are:
+ * |NanStatusCode.SUCCESS|
+ * |NanStatusCode.INVALID_ARGS|
+ * |NanStatusCode.INTERNAL_FAILURE|
+ * |NanStatusCode.PROTOCOL_FAILURE|
+ * |NanStatusCode.INVALID_PEER_ID|
+ * @param bootstrappingInstanceId ID of the new pairing being negotiated (on successful status).
+ */
+ void notifyInitiateBootstrappingResponse(
+ in char id, in NanStatus status, in int bootstrappingInstanceId);
+
+ /**
+ * Callback invoked in response to a respond to pairing bootstrapping indication request
+ * |IWifiNanIface.respondToBootstrappingIndicationRequest|.
+ *
+ * @param cmdId Command Id corresponding to the original request.
+ * @param status NanStatus of the operation. Possible status codes are:
+ * |NanStatusCode.SUCCESS|
+ * |NanStatusCode.INVALID_ARGS|
+ * |NanStatusCode.INTERNAL_FAILURE|
+ * |NanStatusCode.PROTOCOL_FAILURE|
+ * |NanStatusCode.INVALID_NDP_ID|
+ */
+ void notifyRespondToBootstrappingIndicationResponse(in char id, in NanStatus status);
}
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/NanBootstrappingConfirmInd.aidl b/wifi/aidl/android/hardware/wifi/NanBootstrappingConfirmInd.aidl
new file mode 100644
index 0000000..5a539ee
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanBootstrappingConfirmInd.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.NanBootstrappingMethod;
+import android.hardware.wifi.NanStatus;
+
+@VintfStability
+parcelable NanBootstrappingConfirmInd {
+ /**
+ * Id of the bootstrapping session. Obtained as part of earlier
+ |IWifiNanIface.initiateBootstrappingRequest| success notification.
+ */
+ int bootstrappingInstanceId;
+
+ /**
+ * Indicate whether the bootstrapping method negotiation accept or not
+ */
+ boolean acceptRequest;
+
+ /**
+ * Failure reason if |acceptRequest| is false.
+ */
+ NanStatus reasonCode;
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanBootstrappingMethod.aidl b/wifi/aidl/android/hardware/wifi/NanBootstrappingMethod.aidl
new file mode 100644
index 0000000..8960794
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanBootstrappingMethod.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Pairing bootstrapping method flag
+ */
+@VintfStability
+@Backing(type="int")
+enum NanBootstrappingMethod {
+ BOOTSTRAPPING_OPPORTUNISTIC_MASK = 1 << 0,
+ BOOTSTRAPPING_PIN_CODE_DISPLAY_MASK = 1 << 1,
+ BOOTSTRAPPING_PASSPHRASE_DISPLAY_MASK = 1 << 2,
+ BOOTSTRAPPING_QR_DISPLAY_MASK = 1 << 3,
+ BOOTSTRAPPING_NFC_TAG_MASK = 1 << 4,
+ BOOTSTRAPPING_PIN_CODE_KEYPAD_MASK = 1 << 5,
+ BOOTSTRAPPING_PASSPHRASE_KEYPAD_MASK = 1 << 6,
+ BOOTSTRAPPING_QR_SCAN_MASK = 1 << 7,
+ BOOTSTRAPPING_NFC_READER_MASK = 1 << 8,
+ BOOTSTRAPPING_SERVICE_MANAGED_MASK = 1 << 14,
+ BOOTSTRAPPING_HANDSHAKE_SHIP_MASK = 1 << 15
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanBootstrappingRequest.aidl b/wifi/aidl/android/hardware/wifi/NanBootstrappingRequest.aidl
new file mode 100644
index 0000000..d553245
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanBootstrappingRequest.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.NanBootstrappingMethod;
+
+@VintfStability
+parcelable NanBootstrappingRequest {
+ /**
+ * ID of the peer. Obtained as part of an earlier |IWifiNanIfaceEventCallback.eventMatch| or
+ * |IWifiNanIfaceEventCallback.eventFollowupReceived|.
+ */
+ int peerId;
+
+ /**
+ * NAN management interface MAC address of the peer. Obtained as part of an earlier
+ * |IWifiNanIfaceEventCallback.eventMatch| or
+ * |IWifiNanIfaceEventCallback.eventFollowupReceived|.
+ */
+ byte[6] peerDiscMacAddr;
+
+ /**
+ * Bootstrapping method in the request, one of the |NanBootstrappingMethod|
+ */
+ NanBootstrappingMethod requestBootstrappingMethod;
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanBootstrappingRequestInd.aidl b/wifi/aidl/android/hardware/wifi/NanBootstrappingRequestInd.aidl
new file mode 100644
index 0000000..e11122f
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanBootstrappingRequestInd.aidl
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.NanBootstrappingMethod;
+
+/**
+ * NAN Data path request indication message structure.
+ * Event indication received by an intended Responder when a NAN
+ * data request initiated by an Initiator.
+ */
+@VintfStability
+parcelable NanBootstrappingRequestInd {
+ /**
+ * Discovery session (publish or subscribe) ID of a previously created discovery session. The
+ * bootstrapping request is received in the context of this discovery session.
+ * NAN Spec: Service Descriptor Attribute (SDA) / Instance ID
+ */
+ byte discoverySessionId;
+ /**
+ * A unique ID of the peer. Can be subsequently used in |IWifiNanIface.transmitFollowupRequest|
+ * or to set up a data-path.
+ */
+ int peerId;
+ /**
+ * MAC address of the Initiator peer. This is the MAC address of the peer's
+ * management/discovery NAN interface.
+ */
+ byte[6] peerDiscMacAddr;
+
+ /**
+ * ID of bootstrapping session. Used to identify the bootstrapping further negotiation/APIs.
+ */
+ int bootstrappingInstanceId;
+
+ /**
+ * Bootstrapping method in the incoming request, one of the |NanBootstrappingMethod|
+ */
+ NanBootstrappingMethod requestBootstrappingMethod;
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanBootstrappingResponse.aidl b/wifi/aidl/android/hardware/wifi/NanBootstrappingResponse.aidl
new file mode 100644
index 0000000..0a7d621
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanBootstrappingResponse.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.NanBootstrappingMethod;
+
+@VintfStability
+parcelable NanBootstrappingResponse {
+ /**
+ * ID of bootstrapping session. Used to identify the bootstrapping further negotiation/APIs.
+ */
+ int bootstrappingInstanceId;
+ /**
+ * True if accept the request, false otherwise.
+ */
+ boolean acceptRequest;
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanCapabilities.aidl b/wifi/aidl/android/hardware/wifi/NanCapabilities.aidl
index 6042a05..0955b4c 100644
--- a/wifi/aidl/android/hardware/wifi/NanCapabilities.aidl
+++ b/wifi/aidl/android/hardware/wifi/NanCapabilities.aidl
@@ -82,7 +82,19 @@
*/
NanCipherSuiteType supportedCipherSuites;
/**
- * Flag to indicate id instant communication mode is supported.
+ * Flag to indicate if instant communication mode is supported.
*/
boolean instantCommunicationModeSupportFlag;
+ /**
+ * Flag to indicate if 6 GHz is supported.
+ */
+ boolean supports6g;
+ /**
+ * Flag to indicate if High Efficiency is supported.
+ */
+ boolean supportsHe;
+ /**
+ * Flag to indicate if NAN pairing is supported.
+ */
+ boolean supportsPairing;
}
diff --git a/wifi/aidl/android/hardware/wifi/NanIdentityResolutionAttribute.aidl b/wifi/aidl/android/hardware/wifi/NanIdentityResolutionAttribute.aidl
new file mode 100644
index 0000000..917feff
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanIdentityResolutionAttribute.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * NIRA for pairing identity resolution
+ */
+@VintfStability
+parcelable NanIdentityResolutionAttribute {
+ /**
+ * A random byte string to generate tag
+ */
+ byte[8] nonce;
+
+ /**
+ * A resolvable identity to identify Nan identity key
+ */
+ byte[8] tag;
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanMatchInd.aidl b/wifi/aidl/android/hardware/wifi/NanMatchInd.aidl
index 896cde0..be2fa31 100644
--- a/wifi/aidl/android/hardware/wifi/NanMatchInd.aidl
+++ b/wifi/aidl/android/hardware/wifi/NanMatchInd.aidl
@@ -17,6 +17,8 @@
package android.hardware.wifi;
import android.hardware.wifi.NanCipherSuiteType;
+import android.hardware.wifi.NanIdentityResolutionAttribute;
+import android.hardware.wifi.NanPairingConfig;
import android.hardware.wifi.NanRangingIndication;
/**
@@ -126,4 +128,12 @@
* setting up the Secure Data Path.
*/
byte[] scid;
+ /**
+ * The config for NAN pairing set by the peer
+ */
+ NanPairingConfig peerPairingConfig;
+ /**
+ * The NIRA from peer for NAN pairing verification
+ */
+ NanIdentityResolutionAttribute peerNira;
}
diff --git a/wifi/aidl/android/hardware/wifi/NanPairingAkm.aidl b/wifi/aidl/android/hardware/wifi/NanPairingAkm.aidl
new file mode 100644
index 0000000..31eeb2b
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanPairingAkm.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.wifi;
+
+/**
+ * THe AKM used of NAN pairing
+ */
+@VintfStability @Backing(type="int") enum NanPairingAkm { SAE = 0, PASN=1 }
diff --git a/wifi/aidl/android/hardware/wifi/NanPairingConfig.aidl b/wifi/aidl/android/hardware/wifi/NanPairingConfig.aidl
new file mode 100644
index 0000000..4f9c3ae
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanPairingConfig.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.NanBootstrappingMethod;
+
+/**
+ * The NAN pairing config
+ */
+@VintfStability
+parcelable NanPairingConfig {
+ /**
+ * Enable NAN pairing setup
+ */
+ boolean enablePairingSetup;
+ /**
+ * Enable cache NIK/NPK after NAN pairing setup
+ */
+ boolean enablePairingCache;
+ /**
+ * Enable NAN pairing verification with cached NIK/NPK
+ */
+ boolean enablePairingVerification;
+ /**
+ * The set of supported bootstrapping methods. The |NanBootstrappingMethod| bit fields are used.
+ */
+ int supportedBootstrappingMethods;
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanPairingConfirmInd.aidl b/wifi/aidl/android/hardware/wifi/NanPairingConfirmInd.aidl
new file mode 100644
index 0000000..cd98c72
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanPairingConfirmInd.aidl
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.NanDataPathChannelInfo;
+import android.hardware.wifi.NanPairingRequestType;
+import android.hardware.wifi.NanStatus;
+import android.hardware.wifi.NpkSecurityAssociation;
+
+/**
+ * NAN pairing confirmation indication structure. Event indication is
+ * received on both initiator and responder side when negotiation for a
+ * pairing finishes on success or failure.
+ */
+@VintfStability
+parcelable NanPairingConfirmInd {
+ /**
+ * ID of the pairing session.
+ */
+ int pairingInstanceId;
+ /**
+ * Indicates whether the pairing setup succeeded (true) or failed (false).
+ */
+ boolean pairingSuccess;
+ /**
+ * Failure reason if |pairingSuccess| is false.
+ */
+ NanStatus status;
+ /**
+ * Indicate the pairing session is of setup or verification
+ */
+ NanPairingRequestType requestType;
+ /**
+ * Whether should cache the negotiated NIK/NPK for future verification
+ */
+ boolean enablePairingCache;
+ /**
+ * The security association negotiated for the pairing, can be cached for future verification
+ */
+ NpkSecurityAssociation npksa;
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanPairingRequest.aidl b/wifi/aidl/android/hardware/wifi/NanPairingRequest.aidl
new file mode 100644
index 0000000..6f1a072
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanPairingRequest.aidl
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.NanPairingRequestType;
+import android.hardware.wifi.NanPairingSecurityConfig;
+
+/**
+ * NAN pairing initiate request
+ * Which can be used for setup(the initial pairing request) or
+ * verification(re-pairing for paired devices)
+ */
+@VintfStability
+parcelable NanPairingRequest {
+ /**
+ * ID of the peer. Obtained as part of an earlier |IWifiNanIfaceEventCallback.eventMatch| or
+ * |IWifiNanIfaceEventCallback.eventFollowupReceived|.
+ */
+ int peerId;
+ /**
+ * NAN management interface MAC address of the peer. Obtained as part of an earlier
+ * |IWifiNanIfaceEventCallback.eventMatch| or
+ * |IWifiNanIfaceEventCallback.eventFollowupReceived|.
+ */
+ byte[6] peerDiscMacAddr;
+ /**
+ * Indicate the pairing session is for setup or verification
+ */
+ NanPairingRequestType requestType;
+ /**
+ * Whether to cache the negotiated NIK/NPK for future verification
+ */
+ boolean enablePairingCache;
+ /**
+ * The Identity key for pairing, can be used for pairing verification
+ */
+ byte[16] pairingIdentityKey;
+ /**
+ * Security config used for the pairing
+ */
+ NanPairingSecurityConfig securityConfig;
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanPairingRequestInd.aidl b/wifi/aidl/android/hardware/wifi/NanPairingRequestInd.aidl
new file mode 100644
index 0000000..f247e45
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanPairingRequestInd.aidl
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.NanIdentityResolutionAttribute;
+import android.hardware.wifi.NanPairingRequestType;
+
+/**
+ * NAN pairing request indication message structure.
+ * Event indication received by an intended Responder when a
+ * pairing request initiated by an Initiator.
+ */
+@VintfStability
+parcelable NanPairingRequestInd {
+ /**
+ * Discovery session (publish or subscribe) ID of a previously created discovery session. The
+ * pairing request is received in the context of this discovery session.
+ * NAN Spec: Service Descriptor Attribute (SDA) / Instance ID
+ */
+ byte discoverySessionId;
+ /**
+ * A unique ID of the peer. Can be subsequently used in |IWifiNanIface.transmitFollowupRequest|
+ * or to set up a data-path.
+ */
+ int peerId;
+ /**
+ * MAC address of the Initiator peer. This is the MAC address of the peer's
+ * management/discovery NAN interface.
+ */
+ byte[6] peerDiscMacAddr;
+ /**
+ * ID of the NAN pairing Used to identify the pairing in further negotiation/APIs.
+ */
+ int pairingInstanceId;
+ /**
+ * Indicate the pairing session is of setup or verification
+ */
+ NanPairingRequestType requestType;
+ /**
+ * Whether should cache the negotiated NIK/NPK for future verification
+ */
+ boolean enablePairingCache;
+ /**
+ * The NIRA from peer for NAN pairing verification
+ */
+ NanIdentityResolutionAttribute peerNira;
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanPairingRequestType.aidl b/wifi/aidl/android/hardware/wifi/NanPairingRequestType.aidl
new file mode 100644
index 0000000..a69d04e
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanPairingRequestType.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Type of the request of pairing
+ */
+@VintfStability
+@Backing(type="int")
+enum NanPairingRequestType {
+ NAN_PAIRING_SETUP = 0,
+ NAN_PAIRING_VERIFICATION
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanPairingSecurityConfig.aidl b/wifi/aidl/android/hardware/wifi/NanPairingSecurityConfig.aidl
new file mode 100644
index 0000000..273c07e
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanPairingSecurityConfig.aidl
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.NanPairingAkm;
+import android.hardware.wifi.NanPairingSecurityType;
+
+/**
+ * Configuration of NAN data-path security.
+ */
+@VintfStability
+parcelable NanPairingSecurityConfig {
+ /**
+ * Security configuration of the NAN pairing. |NanPairingSecurityType.PMK| for verification.
+ * |NanPairingSecurityType.PASSPHRASE| and |NanPairingSecurityType.OPPORTUNISTIC| for setup
+ */
+ NanPairingSecurityType securityType;
+ /**
+ * Optional Pairwise Master Key (PMK). Must be specified (and is only used) if |securityType| is
+ * set to |NanDataPathSecurityType.PMK|.
+ * Ref: IEEE 802.11i
+ */
+ byte[32] pmk;
+ /**
+ * Optional Passphrase. Must be specified (and is only used) if |securityType| is set to
+ * |NanDataPathSecurityType.PASSPHRASE|.
+ * Min length: |IWifiNanIface.MIN_DATA_PATH_CONFIG_PASSPHRASE_LENGTH|
+ * Max length: |IWifiNanIface.MAX_DATA_PATH_CONFIG_PASSPHRASE_LENGTH|
+ * NAN Spec: Appendix: Mapping passphrase to PMK for NCS-SK Cipher Suites
+ */
+ byte[] passphrase;
+ /**
+ * The AKM for key exchange
+ */
+ NanPairingAkm akm;
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanPairingSecurityType.aidl b/wifi/aidl/android/hardware/wifi/NanPairingSecurityType.aidl
new file mode 100644
index 0000000..0f97d51
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanPairingSecurityType.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * NAN pairing security configuration options.
+ */
+@VintfStability
+@Backing(type="int")
+enum NanPairingSecurityType {
+ OPPORTUNISTIC,
+ PMK,
+ PASSPHRASE,
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanPublishRequest.aidl b/wifi/aidl/android/hardware/wifi/NanPublishRequest.aidl
index 6dd079c..956a7df 100644
--- a/wifi/aidl/android/hardware/wifi/NanPublishRequest.aidl
+++ b/wifi/aidl/android/hardware/wifi/NanPublishRequest.aidl
@@ -17,6 +17,7 @@
package android.hardware.wifi;
import android.hardware.wifi.NanDiscoveryCommonConfig;
+import android.hardware.wifi.NanPairingConfig;
import android.hardware.wifi.NanPublishType;
import android.hardware.wifi.NanTxType;
@@ -46,4 +47,12 @@
* the device must automatically accept the data-path request and complete the negotiation.
*/
boolean autoAcceptDataPathRequests;
+ /**
+ * The config for NAN pairing
+ */
+ NanPairingConfig pairingConfig;
+ /**
+ * The Identity key for pairing, will generate NIRA for verification by the peer
+ */
+ byte[16] identityKey;
}
diff --git a/wifi/aidl/android/hardware/wifi/NanRespondToPairingIndicationRequest.aidl b/wifi/aidl/android/hardware/wifi/NanRespondToPairingIndicationRequest.aidl
new file mode 100644
index 0000000..456b430
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanRespondToPairingIndicationRequest.aidl
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.NanPairingRequestType;
+import android.hardware.wifi.NanPairingSecurityConfig;
+
+/**
+ * Response to a pairing request from a peer.
+ */
+@VintfStability
+parcelable NanRespondToPairingIndicationRequest {
+ /**
+ * Accept (true) or reject (false) the request.
+ * NAN Spec: Data Path Attributes / NDP Attribute / Type and Status
+ */
+ boolean acceptRequest;
+ /**
+ * ID of the NAN pairing for which we're responding. Obtained as part of the request in
+ * |IWifiNanIfaceEventCallback.eventPairingRequest|.
+ */
+ int pairingInstanceId;
+ /**
+ * Indicate the pairing session is of setup or verification
+ */
+ NanPairingRequestType requestType;
+ /**
+ * Whether should cache the negotiated NIK/NPK for future verification
+ */
+ boolean enablePairingCache;
+ /**
+ * The Identity key for pairing, can be used for pairing verification
+ */
+ byte[16] pairingIdentityKey;
+ /**
+ * Security config used for the pairing
+ */
+ NanPairingSecurityConfig securityConfig;
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanStatusCode.aidl b/wifi/aidl/android/hardware/wifi/NanStatusCode.aidl
index d63a50e..efce867 100644
--- a/wifi/aidl/android/hardware/wifi/NanStatusCode.aidl
+++ b/wifi/aidl/android/hardware/wifi/NanStatusCode.aidl
@@ -71,4 +71,12 @@
* Unsupported concurrency of NAN and another feature - NAN disabled.
*/
UNSUPPORTED_CONCURRENCY_NAN_DISABLED = 12,
+ /**
+ * If the pairing id is invalid
+ */
+ INVALID_PAIRING_ID = 13,
+ /**
+ * If the bootstrapping id is invalid
+ */
+ INVALID_BOOTSTRAPPING_ID = 14
}
diff --git a/wifi/aidl/android/hardware/wifi/NanSubscribeRequest.aidl b/wifi/aidl/android/hardware/wifi/NanSubscribeRequest.aidl
index 12c1170..0b246ed 100644
--- a/wifi/aidl/android/hardware/wifi/NanSubscribeRequest.aidl
+++ b/wifi/aidl/android/hardware/wifi/NanSubscribeRequest.aidl
@@ -18,6 +18,7 @@
import android.hardware.wifi.MacAddress;
import android.hardware.wifi.NanDiscoveryCommonConfig;
+import android.hardware.wifi.NanPairingConfig;
import android.hardware.wifi.NanSrfType;
import android.hardware.wifi.NanSubscribeType;
@@ -67,4 +68,12 @@
* NAN Spec: Service Descriptor Attribute (SDA) / Service Response Filter / Address Set
*/
MacAddress[] intfAddr;
+ /**
+ * Security config used for the pairing
+ */
+ NanPairingConfig pairingConfig;
+ /**
+ * The Identity key for pairing, will generate NIRA for verification by the peer
+ */
+ byte[16] identityKey;
}
diff --git a/wifi/aidl/android/hardware/wifi/NpkSecurityAssociation.aidl b/wifi/aidl/android/hardware/wifi/NpkSecurityAssociation.aidl
new file mode 100644
index 0000000..42612c0
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NpkSecurityAssociation.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.NanPairingAkm;
+
+/**
+ * The security sssociation info after Aware Pairing setup.
+ */
+@VintfStability
+parcelable NpkSecurityAssociation {
+ /**
+ * The Aware pairing identity from the peer
+ */
+ byte[16] peerNanIdentityKey;
+ /**
+ * The Aware pairing identity for local device
+ */
+ byte[16] localNanIdentityKey;
+ /**
+ * The PMK is used in this security association
+ */
+ byte[32] npk;
+ /**
+ * The AKM is used for key exchange in this security sssociation
+ */
+ NanPairingAkm akm;
+}
diff --git a/wifi/aidl/android/hardware/wifi/RttBw.aidl b/wifi/aidl/android/hardware/wifi/RttBw.aidl
index 9d42dc0..be9ecbd 100644
--- a/wifi/aidl/android/hardware/wifi/RttBw.aidl
+++ b/wifi/aidl/android/hardware/wifi/RttBw.aidl
@@ -22,6 +22,7 @@
@VintfStability
@Backing(type="int")
enum RttBw {
+ BW_UNSPECIFIED = 0x0,
BW_5MHZ = 0x01,
BW_10MHZ = 0x02,
BW_20MHZ = 0x04,
diff --git a/wifi/aidl/android/hardware/wifi/RttResult.aidl b/wifi/aidl/android/hardware/wifi/RttResult.aidl
index 565cce7..6c45e2c 100644
--- a/wifi/aidl/android/hardware/wifi/RttResult.aidl
+++ b/wifi/aidl/android/hardware/wifi/RttResult.aidl
@@ -16,6 +16,7 @@
package android.hardware.wifi;
+import android.hardware.wifi.RttBw;
import android.hardware.wifi.RttStatus;
import android.hardware.wifi.RttType;
import android.hardware.wifi.WifiInformationElement;
@@ -132,4 +133,15 @@
* For 11mc only.
*/
WifiInformationElement lcr;
+ /**
+ * RTT channel frequency in MHz
+ * If frequency is unknown, this will be set to 0.
+ */
+ int channelFreqMHz;
+ /**
+ * RTT packet bandwidth.
+ * This value is an average bandwidth of the bandwidths of measurement
+ * frames. Cap the average close to a specific valid RttBw.
+ */
+ RttBw packetBw;
}
diff --git a/wifi/aidl/android/hardware/wifi/StaLinkLayerIfaceStats.aidl b/wifi/aidl/android/hardware/wifi/StaLinkLayerIfaceStats.aidl
index 78f8caa..3f8718f 100644
--- a/wifi/aidl/android/hardware/wifi/StaLinkLayerIfaceStats.aidl
+++ b/wifi/aidl/android/hardware/wifi/StaLinkLayerIfaceStats.aidl
@@ -16,64 +16,13 @@
package android.hardware.wifi;
-import android.hardware.wifi.StaLinkLayerIfaceContentionTimeStats;
-import android.hardware.wifi.StaLinkLayerIfacePacketStats;
-import android.hardware.wifi.StaPeerInfo;
+import android.hardware.wifi.StaLinkLayerLinkStats;
/**
- * Iface statistics for the current connection.
+ * Iface statistics for the current connection. Current connection may have
+ * single or multiple links.
*/
@VintfStability
parcelable StaLinkLayerIfaceStats {
- /**
- * Number beacons received from the connected AP.
- */
- int beaconRx;
- /**
- * Access Point Beacon and Management frames RSSI (averaged).
- */
- int avgRssiMgmt;
- /**
- * WME Best Effort Access Category packet counters.
- */
- StaLinkLayerIfacePacketStats wmeBePktStats;
- /**
- * WME Background Access Category packet counters.
- */
- StaLinkLayerIfacePacketStats wmeBkPktStats;
- /**
- * WME Video Access Category packet counters.
- */
- StaLinkLayerIfacePacketStats wmeViPktStats;
- /**
- * WME Voice Access Category packet counters.
- */
- StaLinkLayerIfacePacketStats wmeVoPktStats;
- /**
- * Duty cycle for the iface.
- * If this iface is being served using time slicing on a radio with one or more ifaces
- * (i.e MCC), then the duty cycle assigned to this iface in %.
- * If not using time slicing (i.e SCC or DBS), set to 100.
- */
- byte timeSliceDutyCycleInPercent;
- /**
- * WME Best Effort (BE) Access Category (AC) contention time statistics.
- */
- StaLinkLayerIfaceContentionTimeStats wmeBeContentionTimeStats;
- /**
- * WME Background (BK) Access Category (AC) contention time statistics.
- */
- StaLinkLayerIfaceContentionTimeStats wmeBkContentionTimeStats;
- /**
- * WME Video (VI) Access Category (AC) contention time statistics.
- */
- StaLinkLayerIfaceContentionTimeStats wmeViContentionTimeStats;
- /**
- * WME Voice (VO) Access Category (AC) contention time statistics.
- */
- StaLinkLayerIfaceContentionTimeStats wmeVoContentionTimeStats;
- /**
- * Per peer statistics.
- */
- StaPeerInfo[] peers;
+ StaLinkLayerLinkStats[] links;
}
diff --git a/wifi/aidl/android/hardware/wifi/StaLinkLayerLinkStats.aidl b/wifi/aidl/android/hardware/wifi/StaLinkLayerLinkStats.aidl
new file mode 100644
index 0000000..d8d7975
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/StaLinkLayerLinkStats.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.wifi;
+
+import android.hardware.wifi.StaLinkLayerIfaceContentionTimeStats;
+import android.hardware.wifi.StaLinkLayerIfacePacketStats;
+import android.hardware.wifi.StaPeerInfo;
+
+/**
+ * Per Link statistics for the current connection. For MLO, this is
+ * the statistics for one link in the connection.
+ */
+@VintfStability
+parcelable StaLinkLayerLinkStats {
+ /**
+ * Identifier for the link within MLO. For single link operation this field
+ * is not relevant and can be set to 0.
+ */
+ int linkId;
+ /**
+ * Radio identifier on which the link is currently operating. Refer
+ * |StaLinkLayerRadioStats.radioId|.
+ */
+ int radioId;
+ /**
+ * Frequency of the link in Mhz.
+ */
+ int frequencyMhz;
+ /**
+ * Number of beacons received from the connected AP on the link.
+ */
+ int beaconRx;
+ /**
+ * Access Point Beacon and Management frames RSSI (averaged) on the link.
+ */
+ int avgRssiMgmt;
+ /**
+ * WME Best Effort Access Category packet counters on the link.
+ */
+ StaLinkLayerIfacePacketStats wmeBePktStats;
+ /**
+ * WME Background Access Category packet counters on the link.
+ */
+ StaLinkLayerIfacePacketStats wmeBkPktStats;
+ /**
+ * WME Video Access Category packet counters on the link.
+ */
+ StaLinkLayerIfacePacketStats wmeViPktStats;
+ /**
+ * WME Voice Access Category packet counters on the link.
+ */
+ StaLinkLayerIfacePacketStats wmeVoPktStats;
+ /**
+ * Duty cycle for the link.
+ * If this link is being served using time slicing on a radio with one or
+ * more links then the duty cycle assigned to this link in %. If not using
+ * time slicing, set to 100.
+ */
+ byte timeSliceDutyCycleInPercent;
+ /**
+ * WME Best Effort (BE) Access Category (AC) contention time statistics on
+ * the link.
+ */
+ StaLinkLayerIfaceContentionTimeStats wmeBeContentionTimeStats;
+ /**
+ * WME Background (BK) Access Category (AC) contention time statistics on
+ * the link.
+ */
+ StaLinkLayerIfaceContentionTimeStats wmeBkContentionTimeStats;
+ /**
+ * WME Video (VI) Access Category (AC) contention time statistics on the
+ * link.
+ */
+ StaLinkLayerIfaceContentionTimeStats wmeViContentionTimeStats;
+ /**
+ * WME Voice (VO) Access Category (AC) contention time statistics on the
+ * link.
+ */
+ StaLinkLayerIfaceContentionTimeStats wmeVoContentionTimeStats;
+ /**
+ * Per peer statistics for the link.
+ */
+ StaPeerInfo[] peers;
+}
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..22319ae 100644
--- a/wifi/aidl/default/aidl_struct_util.cpp
+++ b/wifi/aidl/default/aidl_struct_util.cpp
@@ -940,69 +940,160 @@
return true;
}
+bool convertLegacyLinkLayerMlStatsToAidl(const legacy_hal::LinkLayerMlStats& legacy_ml_stats,
+ StaLinkLayerStats* aidl_stats) {
+ if (!aidl_stats) {
+ return false;
+ }
+ *aidl_stats = {};
+ std::vector<StaLinkLayerLinkStats> links;
+ // Iterate over each links
+ for (const auto& link : legacy_ml_stats.links) {
+ StaLinkLayerLinkStats linkStats = {};
+ linkStats.linkId = link.stat.link_id;
+ linkStats.radioId = link.stat.radio;
+ linkStats.frequencyMhz = link.stat.frequency;
+ linkStats.beaconRx = link.stat.beacon_rx;
+ linkStats.avgRssiMgmt = link.stat.rssi_mgmt;
+ linkStats.wmeBePktStats.rxMpdu = link.stat.ac[legacy_hal::WIFI_AC_BE].rx_mpdu;
+ linkStats.wmeBePktStats.txMpdu = link.stat.ac[legacy_hal::WIFI_AC_BE].tx_mpdu;
+ linkStats.wmeBePktStats.lostMpdu = link.stat.ac[legacy_hal::WIFI_AC_BE].mpdu_lost;
+ linkStats.wmeBePktStats.retries = link.stat.ac[legacy_hal::WIFI_AC_BE].retries;
+ linkStats.wmeBeContentionTimeStats.contentionTimeMinInUsec =
+ link.stat.ac[legacy_hal::WIFI_AC_BE].contention_time_min;
+ linkStats.wmeBeContentionTimeStats.contentionTimeMaxInUsec =
+ link.stat.ac[legacy_hal::WIFI_AC_BE].contention_time_max;
+ linkStats.wmeBeContentionTimeStats.contentionTimeAvgInUsec =
+ link.stat.ac[legacy_hal::WIFI_AC_BE].contention_time_avg;
+ linkStats.wmeBeContentionTimeStats.contentionNumSamples =
+ link.stat.ac[legacy_hal::WIFI_AC_BE].contention_num_samples;
+ linkStats.wmeBkPktStats.rxMpdu = link.stat.ac[legacy_hal::WIFI_AC_BK].rx_mpdu;
+ linkStats.wmeBkPktStats.txMpdu = link.stat.ac[legacy_hal::WIFI_AC_BK].tx_mpdu;
+ linkStats.wmeBkPktStats.lostMpdu = link.stat.ac[legacy_hal::WIFI_AC_BK].mpdu_lost;
+ linkStats.wmeBkPktStats.retries = link.stat.ac[legacy_hal::WIFI_AC_BK].retries;
+ linkStats.wmeBkContentionTimeStats.contentionTimeMinInUsec =
+ link.stat.ac[legacy_hal::WIFI_AC_BK].contention_time_min;
+ linkStats.wmeBkContentionTimeStats.contentionTimeMaxInUsec =
+ link.stat.ac[legacy_hal::WIFI_AC_BK].contention_time_max;
+ linkStats.wmeBkContentionTimeStats.contentionTimeAvgInUsec =
+ link.stat.ac[legacy_hal::WIFI_AC_BK].contention_time_avg;
+ linkStats.wmeBkContentionTimeStats.contentionNumSamples =
+ link.stat.ac[legacy_hal::WIFI_AC_BK].contention_num_samples;
+ linkStats.wmeViPktStats.rxMpdu = link.stat.ac[legacy_hal::WIFI_AC_VI].rx_mpdu;
+ linkStats.wmeViPktStats.txMpdu = link.stat.ac[legacy_hal::WIFI_AC_VI].tx_mpdu;
+ linkStats.wmeViPktStats.lostMpdu = link.stat.ac[legacy_hal::WIFI_AC_VI].mpdu_lost;
+ linkStats.wmeViPktStats.retries = link.stat.ac[legacy_hal::WIFI_AC_VI].retries;
+ linkStats.wmeViContentionTimeStats.contentionTimeMinInUsec =
+ link.stat.ac[legacy_hal::WIFI_AC_VI].contention_time_min;
+ linkStats.wmeViContentionTimeStats.contentionTimeMaxInUsec =
+ link.stat.ac[legacy_hal::WIFI_AC_VI].contention_time_max;
+ linkStats.wmeViContentionTimeStats.contentionTimeAvgInUsec =
+ link.stat.ac[legacy_hal::WIFI_AC_VI].contention_time_avg;
+ linkStats.wmeViContentionTimeStats.contentionNumSamples =
+ link.stat.ac[legacy_hal::WIFI_AC_VI].contention_num_samples;
+ linkStats.wmeVoPktStats.rxMpdu = link.stat.ac[legacy_hal::WIFI_AC_VO].rx_mpdu;
+ linkStats.wmeVoPktStats.txMpdu = link.stat.ac[legacy_hal::WIFI_AC_VO].tx_mpdu;
+ linkStats.wmeVoPktStats.lostMpdu = link.stat.ac[legacy_hal::WIFI_AC_VO].mpdu_lost;
+ linkStats.wmeVoPktStats.retries = link.stat.ac[legacy_hal::WIFI_AC_VO].retries;
+ linkStats.wmeVoContentionTimeStats.contentionTimeMinInUsec =
+ link.stat.ac[legacy_hal::WIFI_AC_VO].contention_time_min;
+ linkStats.wmeVoContentionTimeStats.contentionTimeMaxInUsec =
+ link.stat.ac[legacy_hal::WIFI_AC_VO].contention_time_max;
+ linkStats.wmeVoContentionTimeStats.contentionTimeAvgInUsec =
+ link.stat.ac[legacy_hal::WIFI_AC_VO].contention_time_avg;
+ linkStats.wmeVoContentionTimeStats.contentionNumSamples =
+ link.stat.ac[legacy_hal::WIFI_AC_VO].contention_num_samples;
+ linkStats.timeSliceDutyCycleInPercent = link.stat.time_slicing_duty_cycle_percent;
+ // peer info legacy_stats conversion.
+ std::vector<StaPeerInfo> aidl_peers_info_stats;
+ for (const auto& legacy_peer_info_stats : link.peers) {
+ StaPeerInfo aidl_peer_info_stats;
+ if (!convertLegacyPeerInfoStatsToAidl(legacy_peer_info_stats, &aidl_peer_info_stats)) {
+ return false;
+ }
+ aidl_peers_info_stats.push_back(aidl_peer_info_stats);
+ }
+ linkStats.peers = aidl_peers_info_stats;
+ // Push link stats to aidl stats.
+ links.push_back(linkStats);
+ }
+ aidl_stats->iface.links = links;
+ // radio legacy_stats conversion.
+ std::vector<StaLinkLayerRadioStats> aidl_radios_stats;
+ for (const auto& legacy_radio_stats : legacy_ml_stats.radios) {
+ StaLinkLayerRadioStats aidl_radio_stats;
+ if (!convertLegacyLinkLayerRadioStatsToAidl(legacy_radio_stats, &aidl_radio_stats)) {
+ return false;
+ }
+ aidl_radios_stats.push_back(aidl_radio_stats);
+ }
+ aidl_stats->radios = aidl_radios_stats;
+ aidl_stats->timeStampInMs = ::android::uptimeMillis();
+
+ return true;
+}
+
bool convertLegacyLinkLayerStatsToAidl(const legacy_hal::LinkLayerStats& legacy_stats,
StaLinkLayerStats* aidl_stats) {
if (!aidl_stats) {
return false;
}
*aidl_stats = {};
+ std::vector<StaLinkLayerLinkStats> links;
+ StaLinkLayerLinkStats linkStats = {};
// iface legacy_stats conversion.
- aidl_stats->iface.beaconRx = legacy_stats.iface.beacon_rx;
- aidl_stats->iface.avgRssiMgmt = legacy_stats.iface.rssi_mgmt;
- aidl_stats->iface.wmeBePktStats.rxMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu;
- aidl_stats->iface.wmeBePktStats.txMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].tx_mpdu;
- aidl_stats->iface.wmeBePktStats.lostMpdu =
- legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].mpdu_lost;
- aidl_stats->iface.wmeBePktStats.retries = legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].retries;
- aidl_stats->iface.wmeBeContentionTimeStats.contentionTimeMinInUsec =
+ linkStats.linkId = 0;
+ linkStats.beaconRx = legacy_stats.iface.beacon_rx;
+ linkStats.avgRssiMgmt = legacy_stats.iface.rssi_mgmt;
+ linkStats.wmeBePktStats.rxMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu;
+ linkStats.wmeBePktStats.txMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].tx_mpdu;
+ linkStats.wmeBePktStats.lostMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].mpdu_lost;
+ linkStats.wmeBePktStats.retries = legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].retries;
+ linkStats.wmeBeContentionTimeStats.contentionTimeMinInUsec =
legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_min;
- aidl_stats->iface.wmeBeContentionTimeStats.contentionTimeMaxInUsec =
+ linkStats.wmeBeContentionTimeStats.contentionTimeMaxInUsec =
legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_max;
- aidl_stats->iface.wmeBeContentionTimeStats.contentionTimeAvgInUsec =
+ linkStats.wmeBeContentionTimeStats.contentionTimeAvgInUsec =
legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_avg;
- aidl_stats->iface.wmeBeContentionTimeStats.contentionNumSamples =
+ linkStats.wmeBeContentionTimeStats.contentionNumSamples =
legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_num_samples;
- aidl_stats->iface.wmeBkPktStats.rxMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].rx_mpdu;
- aidl_stats->iface.wmeBkPktStats.txMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].tx_mpdu;
- aidl_stats->iface.wmeBkPktStats.lostMpdu =
- legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].mpdu_lost;
- aidl_stats->iface.wmeBkPktStats.retries = legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].retries;
- aidl_stats->iface.wmeBkContentionTimeStats.contentionTimeMinInUsec =
+ linkStats.wmeBkPktStats.rxMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].rx_mpdu;
+ linkStats.wmeBkPktStats.txMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].tx_mpdu;
+ linkStats.wmeBkPktStats.lostMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].mpdu_lost;
+ linkStats.wmeBkPktStats.retries = legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].retries;
+ linkStats.wmeBkContentionTimeStats.contentionTimeMinInUsec =
legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_min;
- aidl_stats->iface.wmeBkContentionTimeStats.contentionTimeMaxInUsec =
+ linkStats.wmeBkContentionTimeStats.contentionTimeMaxInUsec =
legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_max;
- aidl_stats->iface.wmeBkContentionTimeStats.contentionTimeAvgInUsec =
+ linkStats.wmeBkContentionTimeStats.contentionTimeAvgInUsec =
legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_avg;
- aidl_stats->iface.wmeBkContentionTimeStats.contentionNumSamples =
+ linkStats.wmeBkContentionTimeStats.contentionNumSamples =
legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_num_samples;
- aidl_stats->iface.wmeViPktStats.rxMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].rx_mpdu;
- aidl_stats->iface.wmeViPktStats.txMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].tx_mpdu;
- aidl_stats->iface.wmeViPktStats.lostMpdu =
- legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].mpdu_lost;
- aidl_stats->iface.wmeViPktStats.retries = legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].retries;
- aidl_stats->iface.wmeViContentionTimeStats.contentionTimeMinInUsec =
+ linkStats.wmeViPktStats.rxMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].rx_mpdu;
+ linkStats.wmeViPktStats.txMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].tx_mpdu;
+ linkStats.wmeViPktStats.lostMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].mpdu_lost;
+ linkStats.wmeViPktStats.retries = legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].retries;
+ linkStats.wmeViContentionTimeStats.contentionTimeMinInUsec =
legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_min;
- aidl_stats->iface.wmeViContentionTimeStats.contentionTimeMaxInUsec =
+ linkStats.wmeViContentionTimeStats.contentionTimeMaxInUsec =
legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_max;
- aidl_stats->iface.wmeViContentionTimeStats.contentionTimeAvgInUsec =
+ linkStats.wmeViContentionTimeStats.contentionTimeAvgInUsec =
legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_avg;
- aidl_stats->iface.wmeViContentionTimeStats.contentionNumSamples =
+ linkStats.wmeViContentionTimeStats.contentionNumSamples =
legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_num_samples;
- aidl_stats->iface.wmeVoPktStats.rxMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].rx_mpdu;
- aidl_stats->iface.wmeVoPktStats.txMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].tx_mpdu;
- aidl_stats->iface.wmeVoPktStats.lostMpdu =
- legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost;
- aidl_stats->iface.wmeVoPktStats.retries = legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries;
- aidl_stats->iface.wmeVoContentionTimeStats.contentionTimeMinInUsec =
+ linkStats.wmeVoPktStats.rxMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].rx_mpdu;
+ linkStats.wmeVoPktStats.txMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].tx_mpdu;
+ linkStats.wmeVoPktStats.lostMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost;
+ linkStats.wmeVoPktStats.retries = legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries;
+ linkStats.wmeVoContentionTimeStats.contentionTimeMinInUsec =
legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_min;
- aidl_stats->iface.wmeVoContentionTimeStats.contentionTimeMaxInUsec =
+ linkStats.wmeVoContentionTimeStats.contentionTimeMaxInUsec =
legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_max;
- aidl_stats->iface.wmeVoContentionTimeStats.contentionTimeAvgInUsec =
+ linkStats.wmeVoContentionTimeStats.contentionTimeAvgInUsec =
legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_avg;
- aidl_stats->iface.wmeVoContentionTimeStats.contentionNumSamples =
+ linkStats.wmeVoContentionTimeStats.contentionNumSamples =
legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_num_samples;
- aidl_stats->iface.timeSliceDutyCycleInPercent =
- legacy_stats.iface.info.time_slicing_duty_cycle_percent;
+ linkStats.timeSliceDutyCycleInPercent = legacy_stats.iface.info.time_slicing_duty_cycle_percent;
// peer info legacy_stats conversion.
std::vector<StaPeerInfo> aidl_peers_info_stats;
for (const auto& legacy_peer_info_stats : legacy_stats.peers) {
@@ -1012,7 +1103,9 @@
}
aidl_peers_info_stats.push_back(aidl_peer_info_stats);
}
- aidl_stats->iface.peers = aidl_peers_info_stats;
+ linkStats.peers = aidl_peers_info_stats;
+ links.push_back(linkStats);
+ aidl_stats->iface.links = links;
// radio legacy_stats conversion.
std::vector<StaLinkLayerRadioStats> aidl_radios_stats;
for (const auto& legacy_radio_stats : legacy_stats.radios) {
@@ -1168,6 +1261,165 @@
CHECK(false);
}
+legacy_hal::NanPairingRequestType convertAidlNanPairingRequestTypeToLegacy(
+ NanPairingRequestType type) {
+ switch (type) {
+ case NanPairingRequestType::NAN_PAIRING_SETUP:
+ return legacy_hal::NAN_PAIRING_SETUP;
+ case NanPairingRequestType::NAN_PAIRING_VERIFICATION:
+ return legacy_hal::NAN_PAIRING_VERIFICATION;
+ }
+ LOG(FATAL);
+}
+
+NanPairingRequestType convertLegacyNanPairingRequestTypeToAidl(
+ legacy_hal::NanPairingRequestType type) {
+ switch (type) {
+ case legacy_hal::NAN_PAIRING_SETUP:
+ return NanPairingRequestType::NAN_PAIRING_SETUP;
+ case legacy_hal::NAN_PAIRING_VERIFICATION:
+ return NanPairingRequestType::NAN_PAIRING_VERIFICATION;
+ }
+ LOG(FATAL);
+}
+
+legacy_hal::Akm convertAidlAkmTypeToLegacy(NanPairingAkm type) {
+ switch (type) {
+ case NanPairingAkm::SAE:
+ return legacy_hal::SAE;
+ case NanPairingAkm::PASN:
+ return legacy_hal::PASN;
+ }
+ LOG(FATAL);
+}
+
+NanPairingAkm convertLegacyAkmTypeToAidl(legacy_hal::Akm type) {
+ switch (type) {
+ case legacy_hal::SAE:
+ return NanPairingAkm::SAE;
+ case legacy_hal::PASN:
+ return NanPairingAkm::PASN;
+ }
+ LOG(FATAL);
+}
+
+uint16_t convertAidlBootstrappingMethodToLegacy(NanBootstrappingMethod type) {
+ switch (type) {
+ case NanBootstrappingMethod::BOOTSTRAPPING_OPPORTUNISTIC_MASK:
+ return NAN_PAIRING_BOOTSTRAPPING_OPPORTUNISTIC_MASK;
+ case NanBootstrappingMethod::BOOTSTRAPPING_PIN_CODE_DISPLAY_MASK:
+ return NAN_PAIRING_BOOTSTRAPPING_PIN_CODE_DISPLAY_MASK;
+ case NanBootstrappingMethod::BOOTSTRAPPING_PASSPHRASE_DISPLAY_MASK:
+ return NAN_PAIRING_BOOTSTRAPPING_PASSPHRASE_DISPLAY_MASK;
+ case NanBootstrappingMethod::BOOTSTRAPPING_QR_DISPLAY_MASK:
+ return NAN_PAIRING_BOOTSTRAPPING_QR_DISPLAY_MASK;
+ case NanBootstrappingMethod::BOOTSTRAPPING_NFC_TAG_MASK:
+ return NAN_PAIRING_BOOTSTRAPPING_NFC_TAG_MASK;
+ case NanBootstrappingMethod::BOOTSTRAPPING_PIN_CODE_KEYPAD_MASK:
+ return NAN_PAIRING_BOOTSTRAPPING_PIN_CODE_KEYPAD_MASK;
+ case NanBootstrappingMethod::BOOTSTRAPPING_PASSPHRASE_KEYPAD_MASK:
+ return NAN_PAIRING_BOOTSTRAPPING_PASSPHRASE_KEYPAD_MASK;
+ case NanBootstrappingMethod::BOOTSTRAPPING_QR_SCAN_MASK:
+ return NAN_PAIRING_BOOTSTRAPPING_QR_SCAN_MASK;
+ case NanBootstrappingMethod::BOOTSTRAPPING_NFC_READER_MASK:
+ return NAN_PAIRING_BOOTSTRAPPING_NFC_READER_MASK;
+ case NanBootstrappingMethod::BOOTSTRAPPING_SERVICE_MANAGED_MASK:
+ return NAN_PAIRING_BOOTSTRAPPING_SERVICE_MANAGED_MASK;
+ case NanBootstrappingMethod::BOOTSTRAPPING_HANDSHAKE_SHIP_MASK:
+ return NAN_PAIRING_BOOTSTRAPPING_HANDSHAKE_SHIP_MASK;
+ }
+ LOG(FATAL);
+}
+
+NanBootstrappingMethod convertLegacyBootstrappingMethodToAidl(uint16_t type) {
+ switch (type) {
+ case NAN_PAIRING_BOOTSTRAPPING_OPPORTUNISTIC_MASK:
+ return NanBootstrappingMethod::BOOTSTRAPPING_OPPORTUNISTIC_MASK;
+ case NAN_PAIRING_BOOTSTRAPPING_PIN_CODE_DISPLAY_MASK:
+ return NanBootstrappingMethod::BOOTSTRAPPING_PIN_CODE_DISPLAY_MASK;
+ case NAN_PAIRING_BOOTSTRAPPING_PASSPHRASE_DISPLAY_MASK:
+ return NanBootstrappingMethod::BOOTSTRAPPING_PASSPHRASE_DISPLAY_MASK;
+ case NAN_PAIRING_BOOTSTRAPPING_QR_DISPLAY_MASK:
+ return NanBootstrappingMethod::BOOTSTRAPPING_QR_DISPLAY_MASK;
+ case NAN_PAIRING_BOOTSTRAPPING_NFC_TAG_MASK:
+ return NanBootstrappingMethod::BOOTSTRAPPING_NFC_TAG_MASK;
+ case NAN_PAIRING_BOOTSTRAPPING_PIN_CODE_KEYPAD_MASK:
+ return NanBootstrappingMethod::BOOTSTRAPPING_PIN_CODE_KEYPAD_MASK;
+ case NAN_PAIRING_BOOTSTRAPPING_PASSPHRASE_KEYPAD_MASK:
+ return NanBootstrappingMethod::BOOTSTRAPPING_PASSPHRASE_KEYPAD_MASK;
+ case NAN_PAIRING_BOOTSTRAPPING_QR_SCAN_MASK:
+ return NanBootstrappingMethod::BOOTSTRAPPING_QR_SCAN_MASK;
+ case NAN_PAIRING_BOOTSTRAPPING_NFC_READER_MASK:
+ return NanBootstrappingMethod::BOOTSTRAPPING_NFC_READER_MASK;
+ case NAN_PAIRING_BOOTSTRAPPING_SERVICE_MANAGED_MASK:
+ return NanBootstrappingMethod::BOOTSTRAPPING_SERVICE_MANAGED_MASK;
+ case NAN_PAIRING_BOOTSTRAPPING_HANDSHAKE_SHIP_MASK:
+ return NanBootstrappingMethod::BOOTSTRAPPING_HANDSHAKE_SHIP_MASK;
+ }
+ LOG(FATAL);
+ return {};
+}
+
+bool covertAidlPairingConfigToLegacy(const NanPairingConfig& aidl_config,
+ legacy_hal::NanPairingConfig* legacy_config) {
+ if (!legacy_config) {
+ LOG(ERROR) << "covertAidlPairingConfigToLegacy: legacy_config is null";
+ return false;
+ }
+ legacy_config->enable_pairing_setup = aidl_config.enablePairingSetup ? 0x1 : 0x0;
+ legacy_config->enable_pairing_cache = aidl_config.enablePairingCache ? 0x1 : 0x0;
+ legacy_config->enable_pairing_verification = aidl_config.enablePairingVerification ? 0x1 : 0x0;
+ legacy_config->supported_bootstrapping_methods = aidl_config.supportedBootstrappingMethods;
+ return true;
+}
+
+bool convertLegacyPairingConfigToAidl(const legacy_hal::NanPairingConfig& legacy_config,
+ NanPairingConfig* aidl_config) {
+ if (!aidl_config) {
+ LOG(ERROR) << "convertLegacyPairingConfigToAidl: aidl_nira is null";
+ return false;
+ }
+ *aidl_config = {};
+ aidl_config->enablePairingSetup = legacy_config.enable_pairing_setup == 0x1;
+ aidl_config->enablePairingCache = legacy_config.enable_pairing_cache == 0x1;
+ aidl_config->enablePairingVerification = legacy_config.enable_pairing_verification == 0x1;
+ aidl_config->supportedBootstrappingMethods = legacy_config.supported_bootstrapping_methods;
+ return true;
+}
+
+bool convertLegacyNiraToAidl(const legacy_hal::NanIdentityResolutionAttribute& legacy_nira,
+ NanIdentityResolutionAttribute* aidl_nira) {
+ if (!aidl_nira) {
+ LOG(ERROR) << "convertLegacyNiraToAidl: aidl_nira is null";
+ return false;
+ }
+ *aidl_nira = {};
+ aidl_nira->nonce = std::array<uint8_t, 8>();
+ std::copy(legacy_nira.nonce, legacy_nira.nonce + 8, std::begin(aidl_nira->nonce));
+ aidl_nira->tag = std::array<uint8_t, 8>();
+ std::copy(legacy_nira.tag, legacy_nira.tag + 8, std::begin(aidl_nira->tag));
+ return true;
+}
+
+bool convertLegacyNpsaToAidl(const legacy_hal::NpkSecurityAssociation& legacy_npsa,
+ NpkSecurityAssociation* aidl_npsa) {
+ if (!aidl_npsa) {
+ LOG(ERROR) << "convertLegacyNiraToAidl: aidl_nira is null";
+ return false;
+ }
+ *aidl_npsa = {};
+ aidl_npsa->peerNanIdentityKey = std::array<uint8_t, 16>();
+ std::copy(legacy_npsa.peer_nan_identity_key, legacy_npsa.peer_nan_identity_key + 16,
+ std::begin(aidl_npsa->peerNanIdentityKey));
+ aidl_npsa->localNanIdentityKey = std::array<uint8_t, 16>();
+ std::copy(legacy_npsa.local_nan_identity_key, legacy_npsa.local_nan_identity_key + 16,
+ std::begin(aidl_npsa->localNanIdentityKey));
+ aidl_npsa->npk = std::array<uint8_t, 32>();
+ std::copy(legacy_npsa.npk.pmk, legacy_npsa.npk.pmk + 32, std::begin(aidl_npsa->npk));
+ aidl_npsa->akm = convertLegacyAkmTypeToAidl(legacy_npsa.akm);
+ return true;
+}
+
NanStatusCode convertLegacyNanStatusTypeToAidl(legacy_hal::NanStatusType type) {
switch (type) {
case legacy_hal::NAN_STATUS_SUCCESS:
@@ -1196,6 +1448,10 @@
return NanStatusCode::FOLLOWUP_TX_QUEUE_FULL;
case legacy_hal::NAN_STATUS_UNSUPPORTED_CONCURRENCY_NAN_DISABLED:
return NanStatusCode::UNSUPPORTED_CONCURRENCY_NAN_DISABLED;
+ case legacy_hal::NAN_STATUS_INVALID_PAIRING_ID:
+ return NanStatusCode::INVALID_PAIRING_ID;
+ case legacy_hal::NAN_STATUS_INVALID_BOOTSTRAPPING_ID:
+ return NanStatusCode::INVALID_BOOTSTRAPPING_ID;
}
CHECK(false);
}
@@ -1586,6 +1842,12 @@
legacy_request->service_responder_policy = aidl_request.autoAcceptDataPathRequests
? legacy_hal::NAN_SERVICE_ACCEPT_POLICY_ALL
: legacy_hal::NAN_SERVICE_ACCEPT_POLICY_NONE;
+ memcpy(legacy_request->nan_identity_key, aidl_request.identityKey.data(), NAN_IDENTITY_KEY_LEN);
+ if (!covertAidlPairingConfigToLegacy(aidl_request.pairingConfig,
+ &legacy_request->nan_pairing_config)) {
+ LOG(ERROR) << "convertAidlNanPublishRequestToLegacy: invalid pairing config";
+ return false;
+ }
return true;
}
@@ -1726,7 +1988,12 @@
for (int i = 0; i < legacy_request->num_intf_addr_present; i++) {
memcpy(legacy_request->intf_addr[i], aidl_request.intfAddr[i].data.data(), 6);
}
-
+ memcpy(legacy_request->nan_identity_key, aidl_request.identityKey.data(), NAN_IDENTITY_KEY_LEN);
+ if (!covertAidlPairingConfigToLegacy(aidl_request.pairingConfig,
+ &legacy_request->nan_pairing_config)) {
+ LOG(ERROR) << "convertAidlNanSubscribeRequestToLegacy: invalid pairing config";
+ return false;
+ }
return true;
}
@@ -1975,7 +2242,9 @@
aidl_response->supportedCipherSuites =
static_cast<NanCipherSuiteType>(legacy_response.cipher_suites_supported);
aidl_response->instantCommunicationModeSupportFlag = legacy_response.is_instant_mode_supported;
-
+ aidl_response->supports6g = legacy_response.is_6g_supported;
+ aidl_response->supportsHe = legacy_response.is_he_supported;
+ aidl_response->supportsPairing = legacy_response.is_pairing_supported;
return true;
}
@@ -2012,6 +2281,16 @@
aidl_ind->rangingIndicationType =
static_cast<NanRangingIndication>(legacy_ind.range_info.ranging_event_type);
aidl_ind->scid = std::vector<uint8_t>(legacy_ind.scid, legacy_ind.scid + legacy_ind.scid_len);
+
+ if (!convertLegacyNiraToAidl(legacy_ind.nira, &aidl_ind->peerNira)) {
+ LOG(ERROR) << "convertLegacyNanMatchIndToAidl: invalid NIRA";
+ return false;
+ }
+ if (!convertLegacyPairingConfigToAidl(legacy_ind.peer_pairing_config,
+ &aidl_ind->peerPairingConfig)) {
+ LOG(ERROR) << "convertLegacyNanMatchIndToAidl: invalid pairing config";
+ return false;
+ }
return true;
}
@@ -2270,6 +2549,8 @@
return legacy_hal::WIFI_RTT_BW_160;
case RttBw::BW_320MHZ:
return legacy_hal::WIFI_RTT_BW_320;
+ case RttBw::BW_UNSPECIFIED:
+ return legacy_hal::WIFI_RTT_BW_UNSPECIFIED;
};
CHECK(false);
}
@@ -2290,6 +2571,8 @@
return RttBw::BW_160MHZ;
case legacy_hal::WIFI_RTT_BW_320:
return RttBw::BW_320MHZ;
+ case legacy_hal::WIFI_RTT_BW_UNSPECIFIED:
+ return RttBw::BW_UNSPECIFIED;
};
CHECK(false) << "Unknown legacy type: " << type;
}
@@ -2619,6 +2902,28 @@
if (!convertLegacyRttResultToAidl(*legacy_result, &aidl_result)) {
return false;
}
+ aidl_result.channelFreqMHz = 0;
+ aidl_result.packetBw = RttBw::BW_UNSPECIFIED;
+ aidl_results->push_back(aidl_result);
+ }
+ return true;
+}
+
+bool convertLegacyVectorOfRttResultV2ToAidl(
+ const std::vector<const legacy_hal::wifi_rtt_result_v2*>& legacy_results,
+ std::vector<RttResult>* aidl_results) {
+ if (!aidl_results) {
+ return false;
+ }
+ *aidl_results = {};
+ for (const auto legacy_result : legacy_results) {
+ RttResult aidl_result;
+ if (!convertLegacyRttResultToAidl(legacy_result->rtt_result, &aidl_result)) {
+ return false;
+ }
+ aidl_result.channelFreqMHz =
+ legacy_result->frequency != UNSPECIFIED ? legacy_result->frequency : 0;
+ aidl_result.packetBw = convertLegacyRttBwToAidl(legacy_result->packet_bw);
aidl_results->push_back(aidl_result);
}
return true;
@@ -2768,6 +3073,244 @@
return true;
}
+bool convertAidlNanPairingInitiatorRequestToLegacy(const NanPairingRequest& aidl_request,
+ legacy_hal::NanPairingRequest* legacy_request) {
+ if (!legacy_request) {
+ LOG(ERROR) << "convertAidlNanPairingInitiatorRequestToLegacy: "
+ "legacy_request is null";
+ return false;
+ }
+ *legacy_request = {};
+
+ legacy_request->requestor_instance_id = aidl_request.peerId;
+ memcpy(legacy_request->peer_disc_mac_addr, aidl_request.peerDiscMacAddr.data(), 6);
+ legacy_request->nan_pairing_request_type =
+ convertAidlNanPairingRequestTypeToLegacy(aidl_request.requestType);
+ legacy_request->enable_pairing_cache = aidl_request.enablePairingCache;
+
+ memcpy(legacy_request->nan_identity_key, aidl_request.pairingIdentityKey.data(),
+ NAN_IDENTITY_KEY_LEN);
+
+ legacy_request->is_opportunistic =
+ aidl_request.securityConfig.securityType == NanPairingSecurityType::OPPORTUNISTIC ? 1
+ : 0;
+ legacy_request->akm = convertAidlAkmTypeToLegacy(aidl_request.securityConfig.akm);
+ if (aidl_request.securityConfig.securityType == NanPairingSecurityType::PMK) {
+ legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
+ legacy_request->key_info.body.pmk_info.pmk_len = aidl_request.securityConfig.pmk.size();
+ if (legacy_request->key_info.body.pmk_info.pmk_len != NAN_PMK_INFO_LEN) {
+ LOG(ERROR) << "convertAidlNanPairingInitiatorRequestToLegacy: "
+ "invalid pmk_len";
+ return false;
+ }
+ memcpy(legacy_request->key_info.body.pmk_info.pmk, aidl_request.securityConfig.pmk.data(),
+ legacy_request->key_info.body.pmk_info.pmk_len);
+ }
+ if (aidl_request.securityConfig.securityType == NanPairingSecurityType::PASSPHRASE) {
+ legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
+ legacy_request->key_info.body.passphrase_info.passphrase_len =
+ aidl_request.securityConfig.passphrase.size();
+ if (legacy_request->key_info.body.passphrase_info.passphrase_len <
+ NAN_SECURITY_MIN_PASSPHRASE_LEN) {
+ LOG(ERROR) << "convertAidlNanPairingInitiatorRequestToLegacy: "
+ "passphrase_len too small";
+ return false;
+ }
+ if (legacy_request->key_info.body.passphrase_info.passphrase_len >
+ NAN_SECURITY_MAX_PASSPHRASE_LEN) {
+ LOG(ERROR) << "convertAidlNanPairingInitiatorRequestToLegacy: "
+ "passphrase_len too large";
+ return false;
+ }
+ memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
+ aidl_request.securityConfig.passphrase.data(),
+ legacy_request->key_info.body.passphrase_info.passphrase_len);
+ }
+
+ return true;
+}
+
+bool convertAidlNanPairingIndicationResponseToLegacy(
+ const NanRespondToPairingIndicationRequest& aidl_request,
+ legacy_hal::NanPairingIndicationResponse* legacy_request) {
+ if (!legacy_request) {
+ LOG(ERROR) << "convertAidlNanPairingIndicationResponseToLegacy: "
+ "legacy_request is null";
+ return false;
+ }
+ *legacy_request = {};
+
+ legacy_request->pairing_instance_id = aidl_request.pairingInstanceId;
+ legacy_request->nan_pairing_request_type =
+ convertAidlNanPairingRequestTypeToLegacy(aidl_request.requestType);
+ legacy_request->enable_pairing_cache = aidl_request.enablePairingCache;
+
+ memcpy(legacy_request->nan_identity_key, aidl_request.pairingIdentityKey.data(),
+ NAN_IDENTITY_KEY_LEN);
+
+ legacy_request->is_opportunistic =
+ aidl_request.securityConfig.securityType == NanPairingSecurityType::OPPORTUNISTIC ? 1
+ : 0;
+ legacy_request->akm = convertAidlAkmTypeToLegacy(aidl_request.securityConfig.akm);
+ legacy_request->rsp_code =
+ aidl_request.acceptRequest ? NAN_PAIRING_REQUEST_ACCEPT : NAN_PAIRING_REQUEST_REJECT;
+ if (aidl_request.securityConfig.securityType == NanPairingSecurityType::PMK) {
+ legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
+ legacy_request->key_info.body.pmk_info.pmk_len = aidl_request.securityConfig.pmk.size();
+ if (legacy_request->key_info.body.pmk_info.pmk_len != NAN_PMK_INFO_LEN) {
+ LOG(ERROR) << "convertAidlNanPairingIndicationResponseToLegacy: "
+ "invalid pmk_len";
+ return false;
+ }
+ memcpy(legacy_request->key_info.body.pmk_info.pmk, aidl_request.securityConfig.pmk.data(),
+ legacy_request->key_info.body.pmk_info.pmk_len);
+ }
+ if (aidl_request.securityConfig.securityType == NanPairingSecurityType::PASSPHRASE) {
+ legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
+ legacy_request->key_info.body.passphrase_info.passphrase_len =
+ aidl_request.securityConfig.passphrase.size();
+ if (legacy_request->key_info.body.passphrase_info.passphrase_len <
+ NAN_SECURITY_MIN_PASSPHRASE_LEN) {
+ LOG(ERROR) << "convertAidlNanPairingIndicationResponseToLegacy: "
+ "passphrase_len too small";
+ return false;
+ }
+ if (legacy_request->key_info.body.passphrase_info.passphrase_len >
+ NAN_SECURITY_MAX_PASSPHRASE_LEN) {
+ LOG(ERROR) << "convertAidlNanPairingIndicationResponseToLegacy: "
+ "passphrase_len too large";
+ return false;
+ }
+ memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
+ aidl_request.securityConfig.passphrase.data(),
+ legacy_request->key_info.body.passphrase_info.passphrase_len);
+ }
+
+ return true;
+}
+
+bool convertAidlNanBootstrappingInitiatorRequestToLegacy(
+ const NanBootstrappingRequest& aidl_request,
+ legacy_hal::NanBootstrappingRequest* legacy_request) {
+ if (!legacy_request) {
+ LOG(ERROR) << "convertAidlNanBootstrappingInitiatorRequestToLegacy: "
+ "legacy_request is null";
+ return false;
+ }
+ *legacy_request = {};
+
+ legacy_request->requestor_instance_id = aidl_request.peerId;
+ memcpy(legacy_request->peer_disc_mac_addr, aidl_request.peerDiscMacAddr.data(), 6);
+ legacy_request->request_bootstrapping_method =
+ convertAidlBootstrappingMethodToLegacy(aidl_request.requestBootstrappingMethod);
+
+ return true;
+}
+
+bool convertAidlNanBootstrappingIndicationResponseToLegacy(
+ const NanBootstrappingResponse& aidl_request,
+ legacy_hal::NanBootstrappingIndicationResponse* legacy_request) {
+ if (!legacy_request) {
+ LOG(ERROR) << "convertAidlNanBootstrappingIndicationResponseToLegacy: "
+ "legacy_request is null";
+ return false;
+ }
+ *legacy_request = {};
+
+ legacy_request->service_instance_id = aidl_request.bootstrappingInstanceId;
+ legacy_request->rsp_code = aidl_request.acceptRequest ? NAN_BOOTSTRAPPING_REQUEST_ACCEPT
+ : NAN_BOOTSTRAPPING_REQUEST_REJECT;
+
+ return true;
+}
+
+bool convertLegacyNanPairingRequestIndToAidl(const legacy_hal::NanPairingRequestInd& legacy_ind,
+ NanPairingRequestInd* aidl_ind) {
+ if (!aidl_ind) {
+ LOG(ERROR) << "convertLegacyNanPairingRequestIndToAidl: aidl_ind is null";
+ return false;
+ }
+ *aidl_ind = {};
+
+ aidl_ind->discoverySessionId = legacy_ind.publish_subscribe_id;
+ aidl_ind->peerId = legacy_ind.requestor_instance_id;
+ aidl_ind->peerDiscMacAddr = std::array<uint8_t, 6>();
+ std::copy(legacy_ind.peer_disc_mac_addr, legacy_ind.peer_disc_mac_addr + 6,
+ std::begin(aidl_ind->peerDiscMacAddr));
+ aidl_ind->pairingInstanceId = legacy_ind.pairing_instance_id;
+ aidl_ind->enablePairingCache = legacy_ind.enable_pairing_cache == 1;
+ aidl_ind->requestType =
+ convertLegacyNanPairingRequestTypeToAidl(legacy_ind.nan_pairing_request_type);
+ if (!convertLegacyNiraToAidl(legacy_ind.nira, &aidl_ind->peerNira)) {
+ return false;
+ }
+ return true;
+}
+
+bool convertLegacyNanPairingConfirmIndToAidl(const legacy_hal::NanPairingConfirmInd& legacy_ind,
+ NanPairingConfirmInd* aidl_ind) {
+ if (!aidl_ind) {
+ LOG(ERROR) << "convertLegacyNanPairingRequestIndToAidl: aidl_ind is null";
+ return false;
+ }
+ *aidl_ind = {};
+
+ aidl_ind->pairingInstanceId = legacy_ind.pairing_instance_id;
+ aidl_ind->enablePairingCache = legacy_ind.enable_pairing_cache == 1;
+ aidl_ind->requestType =
+ convertLegacyNanPairingRequestTypeToAidl(legacy_ind.nan_pairing_request_type);
+ aidl_ind->pairingSuccess = legacy_ind.rsp_code == NAN_PAIRING_REQUEST_ACCEPT;
+ aidl_ind->status.status = convertLegacyNanStatusTypeToAidl(legacy_ind.reason_code);
+ if (!convertLegacyNpsaToAidl(legacy_ind.npk_security_association, &aidl_ind->npksa)) {
+ return false;
+ }
+ return true;
+}
+
+bool convertLegacyNanBootstrappingRequestIndToAidl(
+ const legacy_hal::NanBootstrappingRequestInd& legacy_ind,
+ NanBootstrappingRequestInd* aidl_ind) {
+ if (!aidl_ind) {
+ LOG(ERROR) << "convertLegacyNanBootstrappingRequestIndToAidl: aidl_ind is null";
+ return false;
+ }
+ *aidl_ind = {};
+
+ aidl_ind->discoverySessionId = legacy_ind.publish_subscribe_id;
+ aidl_ind->peerId = legacy_ind.requestor_instance_id;
+ aidl_ind->peerDiscMacAddr = std::array<uint8_t, 6>();
+ std::copy(legacy_ind.peer_disc_mac_addr, legacy_ind.peer_disc_mac_addr + 6,
+ std::begin(aidl_ind->peerDiscMacAddr));
+ aidl_ind->bootstrappingInstanceId = legacy_ind.bootstrapping_instance_id;
+ aidl_ind->requestBootstrappingMethod =
+ convertLegacyBootstrappingMethodToAidl(legacy_ind.request_bootstrapping_method);
+ return true;
+}
+
+bool convertLegacyNanBootstrappingConfirmIndToAidl(
+ const legacy_hal::NanBootstrappingConfirmInd& legacy_ind,
+ NanBootstrappingConfirmInd* aidl_ind) {
+ if (!aidl_ind) {
+ LOG(ERROR) << "convertLegacyNanBootstrappingConfirmIndToAidl: aidl_ind is null";
+ return false;
+ }
+ *aidl_ind = {};
+
+ aidl_ind->bootstrappingInstanceId = legacy_ind.bootstrapping_instance_id;
+ aidl_ind->acceptRequest = legacy_ind.rsp_code == NAN_BOOTSTRAPPING_REQUEST_ACCEPT;
+ aidl_ind->reasonCode.status = convertLegacyNanStatusTypeToAidl(legacy_ind.reason_code);
+ 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..e478fed 100644
--- a/wifi/aidl/default/aidl_struct_util.h
+++ b/wifi/aidl/default/aidl_struct_util.h
@@ -89,6 +89,8 @@
bool convertLegacyVectorOfCachedGscanResultsToAidl(
const std::vector<legacy_hal::wifi_cached_scan_results>& legacy_cached_scan_results,
std::vector<StaScanData>* aidl_scan_datas);
+bool convertLegacyLinkLayerMlStatsToAidl(const legacy_hal::LinkLayerMlStats& legacy_ml_stats,
+ StaLinkLayerStats* aidl_stats);
bool convertLegacyLinkLayerStatsToAidl(const legacy_hal::LinkLayerStats& legacy_stats,
StaLinkLayerStats* aidl_stats);
bool convertLegacyRoamingCapabilitiesToAidl(
@@ -161,6 +163,9 @@
bool convertLegacyVectorOfRttResultToAidl(
const std::vector<const legacy_hal::wifi_rtt_result*>& legacy_results,
std::vector<RttResult>* aidl_results);
+bool convertLegacyVectorOfRttResultV2ToAidl(
+ const std::vector<const legacy_hal::wifi_rtt_result_v2*>& legacy_results,
+ std::vector<RttResult>* aidl_results);
uint32_t convertAidlWifiBandToLegacyMacBand(WifiBand band);
uint32_t convertAidlWifiIfaceModeToLegacy(uint32_t aidl_iface_mask);
uint32_t convertAidlUsableChannelFilterToLegacy(uint32_t aidl_filter_mask);
@@ -171,6 +176,30 @@
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);
+bool convertAidlNanPairingInitiatorRequestToLegacy(const NanPairingRequest& aidl_request,
+ legacy_hal::NanPairingRequest* legacy_request);
+bool convertAidlNanPairingIndicationResponseToLegacy(
+ const NanRespondToPairingIndicationRequest& aidl_response,
+ legacy_hal::NanPairingIndicationResponse* legacy_response);
+bool convertAidlNanBootstrappingInitiatorRequestToLegacy(
+ const NanBootstrappingRequest& aidl_request,
+ legacy_hal::NanBootstrappingRequest* legacy_request);
+bool convertAidlNanBootstrappingIndicationResponseToLegacy(
+ const NanBootstrappingResponse& aidl_response,
+ legacy_hal::NanBootstrappingIndicationResponse* legacy_response);
+bool convertLegacyNanPairingRequestIndToAidl(const legacy_hal::NanPairingRequestInd& legacy_ind,
+ NanPairingRequestInd* aidl_ind);
+bool convertLegacyNanPairingConfirmIndToAidl(const legacy_hal::NanPairingConfirmInd& legacy_ind,
+ NanPairingConfirmInd* aidl_ind);
+bool convertLegacyNanBootstrappingRequestIndToAidl(
+ const legacy_hal::NanBootstrappingRequestInd& legacy_ind,
+ NanBootstrappingRequestInd* aidl_ind);
+bool convertLegacyNanBootstrappingConfirmIndToAidl(
+ const legacy_hal::NanBootstrappingConfirmInd& legacy_ind,
+ NanBootstrappingConfirmInd* aidl_ind);
} // namespace aidl_struct_util
} // namespace wifi
} // namespace hardware
diff --git a/wifi/aidl/default/tests/aidl_struct_util_unit_tests.cpp b/wifi/aidl/default/tests/aidl_struct_util_unit_tests.cpp
index 4a69c24..9b9d96d 100644
--- a/wifi/aidl/default/tests/aidl_struct_util_unit_tests.cpp
+++ b/wifi/aidl/default/tests/aidl_struct_util_unit_tests.cpp
@@ -29,6 +29,12 @@
constexpr uint32_t kIfaceChannel2 = 5;
constexpr char kIfaceName1[] = "wlan0";
constexpr char kIfaceName2[] = "wlan1";
+constexpr uint8_t kMacAddress[] = {0x02, 0x12, 0x45, 0x56, 0xab, 0xcc};
+byte LCI[] = {0x27, 0x1A, 0x1, 0x00, 0x8, 0x01, 0x00, 0x08, 0x00, 0x10, 0x52,
+ 0x83, 0x4d, 0x12, 0xef, 0xd2, 0xb0, 0x8b, 0x9b, 0x4b, 0xf1, 0xcc,
+ 0x2c, 0x00, 0x00, 0x41, 0x06, 0x03, 0x06, 0x00, 0x80};
+byte LCR[] = {0x27, 0xE, 0x1, 0x00, 0xB, 0x01, 0x00, 0x0b, 0x00, 0x09,
+ 0x55, 0x53, 0x18, 0x05, 0x39, 0x34, 0x30, 0x34, 0x33};
} // namespace
namespace aidl {
@@ -112,6 +118,290 @@
EXPECT_EQ(static_cast<int32_t>(legacy_iface_info2.channel), aidl_iface_info2.channel);
}
+TEST_F(AidlStructUtilTest, canConvertLegacyLinkLayerMlStatsToAidl) {
+ legacy_hal::LinkLayerMlStats legacy_ml_stats{};
+ // Add two radio stats
+ legacy_ml_stats.radios.push_back(legacy_hal::LinkLayerRadioStats{});
+ legacy_ml_stats.radios.push_back(legacy_hal::LinkLayerRadioStats{});
+ // Add two links.
+ legacy_ml_stats.links.push_back(legacy_hal::LinkStats{});
+ legacy_ml_stats.links.push_back(legacy_hal::LinkStats{});
+ // Set stats for each link.
+ for (legacy_hal::LinkStats& link : legacy_ml_stats.links) {
+ link.peers.push_back(legacy_hal::WifiPeerInfo{});
+ link.peers.push_back(legacy_hal::WifiPeerInfo{});
+ link.stat.beacon_rx = rand();
+ link.stat.link_id = rand() % 15;
+ link.stat.radio = rand() % 4;
+ link.stat.frequency = rand();
+ link.stat.rssi_mgmt = rand();
+ link.stat.ac[legacy_hal::WIFI_AC_BE].rx_mpdu = rand();
+ link.stat.ac[legacy_hal::WIFI_AC_BE].tx_mpdu = rand();
+ link.stat.ac[legacy_hal::WIFI_AC_BE].mpdu_lost = rand();
+ link.stat.ac[legacy_hal::WIFI_AC_BE].retries = rand();
+ link.stat.ac[legacy_hal::WIFI_AC_BE].contention_time_min = rand();
+ link.stat.ac[legacy_hal::WIFI_AC_BE].contention_time_max = rand();
+ link.stat.ac[legacy_hal::WIFI_AC_BE].contention_time_avg = rand();
+ link.stat.ac[legacy_hal::WIFI_AC_BE].contention_num_samples = rand();
+
+ link.stat.ac[legacy_hal::WIFI_AC_BK].rx_mpdu = rand();
+ link.stat.ac[legacy_hal::WIFI_AC_BK].tx_mpdu = rand();
+ link.stat.ac[legacy_hal::WIFI_AC_BK].mpdu_lost = rand();
+ link.stat.ac[legacy_hal::WIFI_AC_BK].retries = rand();
+ link.stat.ac[legacy_hal::WIFI_AC_BK].contention_time_min = rand();
+ link.stat.ac[legacy_hal::WIFI_AC_BK].contention_time_max = rand();
+ link.stat.ac[legacy_hal::WIFI_AC_BK].contention_time_avg = rand();
+ link.stat.ac[legacy_hal::WIFI_AC_BK].contention_num_samples = rand();
+
+ link.stat.ac[legacy_hal::WIFI_AC_VI].rx_mpdu = rand();
+ link.stat.ac[legacy_hal::WIFI_AC_VI].tx_mpdu = rand();
+ link.stat.ac[legacy_hal::WIFI_AC_VI].mpdu_lost = rand();
+ link.stat.ac[legacy_hal::WIFI_AC_VI].retries = rand();
+ link.stat.ac[legacy_hal::WIFI_AC_VI].contention_time_min = rand();
+ link.stat.ac[legacy_hal::WIFI_AC_VI].contention_time_max = rand();
+ link.stat.ac[legacy_hal::WIFI_AC_VI].contention_time_avg = rand();
+ link.stat.ac[legacy_hal::WIFI_AC_VI].contention_num_samples = rand();
+
+ link.stat.ac[legacy_hal::WIFI_AC_VO].rx_mpdu = rand();
+ link.stat.ac[legacy_hal::WIFI_AC_VO].tx_mpdu = rand();
+ link.stat.ac[legacy_hal::WIFI_AC_VO].mpdu_lost = rand();
+ link.stat.ac[legacy_hal::WIFI_AC_VO].retries = rand();
+ link.stat.ac[legacy_hal::WIFI_AC_VO].contention_time_min = rand();
+ link.stat.ac[legacy_hal::WIFI_AC_VO].contention_time_max = rand();
+ link.stat.ac[legacy_hal::WIFI_AC_VO].contention_time_avg = rand();
+ link.stat.ac[legacy_hal::WIFI_AC_VO].contention_num_samples = rand();
+
+ link.stat.time_slicing_duty_cycle_percent = rand();
+ link.stat.num_peers = 2;
+
+ // Set peer stats for each of the peers.
+ for (auto& peer : link.peers) {
+ peer.peer_info.bssload.sta_count = rand();
+ peer.peer_info.bssload.chan_util = rand();
+ wifi_rate_stat rate_stat1 = {
+ .rate = {3, 1, 2, 5, 0, 0},
+ .tx_mpdu = 0,
+ .rx_mpdu = 1,
+ .mpdu_lost = 2,
+ .retries = 3,
+ .retries_short = 4,
+ .retries_long = 5,
+ };
+ wifi_rate_stat rate_stat2 = {
+ .rate = {2, 2, 1, 6, 0, 1},
+ .tx_mpdu = 6,
+ .rx_mpdu = 7,
+ .mpdu_lost = 8,
+ .retries = 9,
+ .retries_short = 10,
+ .retries_long = 11,
+ };
+ peer.rate_stats.push_back(rate_stat1);
+ peer.rate_stats.push_back(rate_stat2);
+ }
+ }
+ // Set radio stats
+ for (auto& radio : legacy_ml_stats.radios) {
+ radio.stats.radio = rand();
+ radio.stats.on_time = rand();
+ radio.stats.tx_time = rand();
+ radio.stats.rx_time = rand();
+ radio.stats.on_time_scan = rand();
+ radio.stats.on_time_nbd = rand();
+ radio.stats.on_time_gscan = rand();
+ radio.stats.on_time_roam_scan = rand();
+ radio.stats.on_time_pno_scan = rand();
+ radio.stats.on_time_hs20 = rand();
+ for (int i = 0; i < 4; i++) {
+ radio.tx_time_per_levels.push_back(rand());
+ }
+
+ legacy_hal::wifi_channel_stat channel_stat1 = {
+ .channel = {legacy_hal::WIFI_CHAN_WIDTH_20, 2437, 2437, 0},
+ .on_time = 0x1111,
+ .cca_busy_time = 0x55,
+ };
+ legacy_hal::wifi_channel_stat channel_stat2 = {
+ .channel = {legacy_hal::WIFI_CHAN_WIDTH_20, 5180, 5180, 0},
+ .on_time = 0x2222,
+ .cca_busy_time = 0x66,
+ };
+ radio.channel_stats.push_back(channel_stat1);
+ radio.channel_stats.push_back(channel_stat2);
+ }
+ // Convert to AIDL
+ StaLinkLayerStats converted{};
+ aidl_struct_util::convertLegacyLinkLayerMlStatsToAidl(legacy_ml_stats, &converted);
+ // Validate
+ int l = 0;
+ for (legacy_hal::LinkStats& link : legacy_ml_stats.links) {
+ EXPECT_EQ(link.stat.link_id, (uint8_t)converted.iface.links[l].linkId);
+ EXPECT_EQ(link.stat.radio, converted.iface.links[l].radioId);
+ EXPECT_EQ(link.stat.frequency, (uint32_t)converted.iface.links[l].frequencyMhz);
+ EXPECT_EQ(link.stat.beacon_rx, (uint32_t)converted.iface.links[l].beaconRx);
+ EXPECT_EQ(link.stat.rssi_mgmt, converted.iface.links[l].avgRssiMgmt);
+ EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_BE].rx_mpdu,
+ converted.iface.links[l].wmeBePktStats.rxMpdu);
+ EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_BE].tx_mpdu,
+ converted.iface.links[l].wmeBePktStats.txMpdu);
+ EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_BE].mpdu_lost,
+ converted.iface.links[l].wmeBePktStats.lostMpdu);
+ EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_BE].retries,
+ converted.iface.links[l].wmeBePktStats.retries);
+ EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_BE].contention_time_min,
+ (uint32_t)converted.iface.links[l]
+ .wmeBeContentionTimeStats.contentionTimeMinInUsec);
+ EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_BE].contention_time_max,
+ (uint32_t)converted.iface.links[l]
+ .wmeBeContentionTimeStats.contentionTimeMaxInUsec);
+ EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_BE].contention_time_avg,
+ (uint32_t)converted.iface.links[l]
+ .wmeBeContentionTimeStats.contentionTimeAvgInUsec);
+ EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_BE].contention_num_samples,
+ (uint32_t)converted.iface.links[l].wmeBeContentionTimeStats.contentionNumSamples);
+
+ EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_BK].rx_mpdu,
+ converted.iface.links[l].wmeBkPktStats.rxMpdu);
+ EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_BK].tx_mpdu,
+ converted.iface.links[l].wmeBkPktStats.txMpdu);
+ EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_BK].mpdu_lost,
+ converted.iface.links[l].wmeBkPktStats.lostMpdu);
+ EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_BK].retries,
+ converted.iface.links[l].wmeBkPktStats.retries);
+ EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_BK].contention_time_min,
+ (uint32_t)converted.iface.links[l]
+ .wmeBkContentionTimeStats.contentionTimeMinInUsec);
+ EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_BK].contention_time_max,
+ (uint32_t)converted.iface.links[l]
+ .wmeBkContentionTimeStats.contentionTimeMaxInUsec);
+ EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_BK].contention_time_avg,
+ (uint32_t)converted.iface.links[l]
+ .wmeBkContentionTimeStats.contentionTimeAvgInUsec);
+ EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_BK].contention_num_samples,
+ (uint32_t)converted.iface.links[l].wmeBkContentionTimeStats.contentionNumSamples);
+
+ EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_VI].rx_mpdu,
+ converted.iface.links[l].wmeViPktStats.rxMpdu);
+ EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_VI].tx_mpdu,
+ converted.iface.links[l].wmeViPktStats.txMpdu);
+ EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_VI].mpdu_lost,
+ converted.iface.links[l].wmeViPktStats.lostMpdu);
+ EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_VI].retries,
+ converted.iface.links[l].wmeViPktStats.retries);
+ EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_VI].contention_time_min,
+ (uint32_t)converted.iface.links[l]
+ .wmeViContentionTimeStats.contentionTimeMinInUsec);
+ EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_VI].contention_time_max,
+ (uint32_t)converted.iface.links[l]
+ .wmeViContentionTimeStats.contentionTimeMaxInUsec);
+ EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_VI].contention_time_avg,
+ (uint32_t)converted.iface.links[l]
+ .wmeViContentionTimeStats.contentionTimeAvgInUsec);
+ EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_VI].contention_num_samples,
+ (uint32_t)converted.iface.links[l].wmeViContentionTimeStats.contentionNumSamples);
+
+ EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_VO].rx_mpdu,
+ converted.iface.links[l].wmeVoPktStats.rxMpdu);
+ EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_VO].tx_mpdu,
+ converted.iface.links[l].wmeVoPktStats.txMpdu);
+ EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_VO].mpdu_lost,
+ converted.iface.links[l].wmeVoPktStats.lostMpdu);
+ EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_VO].retries,
+ converted.iface.links[l].wmeVoPktStats.retries);
+ EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_VO].contention_time_min,
+ (uint32_t)converted.iface.links[l]
+ .wmeVoContentionTimeStats.contentionTimeMinInUsec);
+ EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_VO].contention_time_max,
+ (uint32_t)converted.iface.links[l]
+ .wmeVoContentionTimeStats.contentionTimeMaxInUsec);
+ EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_VO].contention_time_avg,
+ (uint32_t)converted.iface.links[l]
+ .wmeVoContentionTimeStats.contentionTimeAvgInUsec);
+ EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_VO].contention_num_samples,
+ (uint32_t)converted.iface.links[l].wmeVoContentionTimeStats.contentionNumSamples);
+
+ EXPECT_EQ(link.stat.time_slicing_duty_cycle_percent,
+ converted.iface.links[l].timeSliceDutyCycleInPercent);
+
+ EXPECT_EQ(link.peers.size(), converted.iface.links[l].peers.size());
+ for (size_t i = 0; i < link.peers.size(); i++) {
+ EXPECT_EQ(link.peers[i].peer_info.bssload.sta_count,
+ converted.iface.links[l].peers[i].staCount);
+ EXPECT_EQ(link.peers[i].peer_info.bssload.chan_util,
+ converted.iface.links[l].peers[i].chanUtil);
+ for (size_t j = 0; j < link.peers[i].rate_stats.size(); j++) {
+ EXPECT_EQ(
+ link.peers[i].rate_stats[j].rate.preamble,
+ (uint32_t)converted.iface.links[l].peers[i].rateStats[j].rateInfo.preamble);
+ EXPECT_EQ(link.peers[i].rate_stats[j].rate.nss,
+ (uint32_t)converted.iface.links[l].peers[i].rateStats[j].rateInfo.nss);
+ EXPECT_EQ(link.peers[i].rate_stats[j].rate.bw,
+ (uint32_t)converted.iface.links[l].peers[i].rateStats[j].rateInfo.bw);
+ EXPECT_EQ(link.peers[i].rate_stats[j].rate.rateMcsIdx,
+ (uint32_t)converted.iface.links[l]
+ .peers[i]
+ .rateStats[j]
+ .rateInfo.rateMcsIdx);
+ EXPECT_EQ(link.peers[i].rate_stats[j].tx_mpdu,
+ (uint32_t)converted.iface.links[l].peers[i].rateStats[j].txMpdu);
+ EXPECT_EQ(link.peers[i].rate_stats[j].rx_mpdu,
+ (uint32_t)converted.iface.links[l].peers[i].rateStats[j].rxMpdu);
+ EXPECT_EQ(link.peers[i].rate_stats[j].mpdu_lost,
+ (uint32_t)converted.iface.links[l].peers[i].rateStats[j].mpduLost);
+ EXPECT_EQ(link.peers[i].rate_stats[j].retries,
+ (uint32_t)converted.iface.links[l].peers[i].rateStats[j].retries);
+ }
+ }
+ ++l;
+ } // loop over links
+
+ EXPECT_EQ(legacy_ml_stats.radios.size(), converted.radios.size());
+ for (size_t i = 0; i < legacy_ml_stats.radios.size(); i++) {
+ EXPECT_EQ(legacy_ml_stats.radios[i].stats.radio, converted.radios[i].radioId);
+ EXPECT_EQ(legacy_ml_stats.radios[i].stats.on_time,
+ (uint32_t)converted.radios[i].onTimeInMs);
+ EXPECT_EQ(legacy_ml_stats.radios[i].stats.tx_time,
+ (uint32_t)converted.radios[i].txTimeInMs);
+ EXPECT_EQ(legacy_ml_stats.radios[i].stats.rx_time,
+ (uint32_t)converted.radios[i].rxTimeInMs);
+ EXPECT_EQ(legacy_ml_stats.radios[i].stats.on_time_scan,
+ (uint32_t)converted.radios[i].onTimeInMsForScan);
+ EXPECT_EQ(legacy_ml_stats.radios[i].tx_time_per_levels.size(),
+ converted.radios[i].txTimeInMsPerLevel.size());
+ for (size_t j = 0; j < legacy_ml_stats.radios[i].tx_time_per_levels.size(); j++) {
+ EXPECT_EQ(legacy_ml_stats.radios[i].tx_time_per_levels[j],
+ (uint32_t)converted.radios[i].txTimeInMsPerLevel[j]);
+ }
+ EXPECT_EQ(legacy_ml_stats.radios[i].stats.on_time_nbd,
+ (uint32_t)converted.radios[i].onTimeInMsForNanScan);
+ EXPECT_EQ(legacy_ml_stats.radios[i].stats.on_time_gscan,
+ (uint32_t)converted.radios[i].onTimeInMsForBgScan);
+ EXPECT_EQ(legacy_ml_stats.radios[i].stats.on_time_roam_scan,
+ (uint32_t)converted.radios[i].onTimeInMsForRoamScan);
+ EXPECT_EQ(legacy_ml_stats.radios[i].stats.on_time_pno_scan,
+ (uint32_t)converted.radios[i].onTimeInMsForPnoScan);
+ EXPECT_EQ(legacy_ml_stats.radios[i].stats.on_time_hs20,
+ (uint32_t)converted.radios[i].onTimeInMsForHs20Scan);
+ EXPECT_EQ(legacy_ml_stats.radios[i].channel_stats.size(),
+ converted.radios[i].channelStats.size());
+ for (size_t k = 0; k < legacy_ml_stats.radios[i].channel_stats.size(); k++) {
+ auto& legacy_channel_st = legacy_ml_stats.radios[i].channel_stats[k];
+ EXPECT_EQ(WifiChannelWidthInMhz::WIDTH_20,
+ converted.radios[i].channelStats[k].channel.width);
+ EXPECT_EQ(legacy_channel_st.channel.center_freq,
+ converted.radios[i].channelStats[k].channel.centerFreq);
+ EXPECT_EQ(legacy_channel_st.channel.center_freq0,
+ converted.radios[i].channelStats[k].channel.centerFreq0);
+ EXPECT_EQ(legacy_channel_st.channel.center_freq1,
+ converted.radios[i].channelStats[k].channel.centerFreq1);
+ EXPECT_EQ(legacy_channel_st.cca_busy_time,
+ (uint32_t)converted.radios[i].channelStats[k].ccaBusyTimeInMs);
+ EXPECT_EQ(legacy_channel_st.on_time,
+ (uint32_t)converted.radios[i].channelStats[k].onTimeInMs);
+ }
+ }
+}
+
TEST_F(AidlStructUtilTest, canConvertLegacyLinkLayerStatsToAidl) {
legacy_hal::LinkLayerStats legacy_stats{};
legacy_stats.radios.push_back(legacy_hal::LinkLayerRadioStats{});
@@ -215,78 +505,79 @@
StaLinkLayerStats converted{};
aidl_struct_util::convertLegacyLinkLayerStatsToAidl(legacy_stats, &converted);
- EXPECT_EQ(legacy_stats.iface.beacon_rx, (uint32_t)converted.iface.beaconRx);
- EXPECT_EQ(legacy_stats.iface.rssi_mgmt, converted.iface.avgRssiMgmt);
+ EXPECT_EQ(0, converted.iface.links[0].linkId);
+ EXPECT_EQ(legacy_stats.iface.beacon_rx, (uint32_t)converted.iface.links[0].beaconRx);
+ EXPECT_EQ(legacy_stats.iface.rssi_mgmt, converted.iface.links[0].avgRssiMgmt);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu,
- converted.iface.wmeBePktStats.rxMpdu);
+ converted.iface.links[0].wmeBePktStats.rxMpdu);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].tx_mpdu,
- converted.iface.wmeBePktStats.txMpdu);
+ converted.iface.links[0].wmeBePktStats.txMpdu);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].mpdu_lost,
- converted.iface.wmeBePktStats.lostMpdu);
+ converted.iface.links[0].wmeBePktStats.lostMpdu);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].retries,
- converted.iface.wmeBePktStats.retries);
+ converted.iface.links[0].wmeBePktStats.retries);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_min,
- (uint32_t)converted.iface.wmeBeContentionTimeStats.contentionTimeMinInUsec);
+ (uint32_t)converted.iface.links[0].wmeBeContentionTimeStats.contentionTimeMinInUsec);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_max,
- (uint32_t)converted.iface.wmeBeContentionTimeStats.contentionTimeMaxInUsec);
+ (uint32_t)converted.iface.links[0].wmeBeContentionTimeStats.contentionTimeMaxInUsec);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_avg,
- (uint32_t)converted.iface.wmeBeContentionTimeStats.contentionTimeAvgInUsec);
+ (uint32_t)converted.iface.links[0].wmeBeContentionTimeStats.contentionTimeAvgInUsec);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_num_samples,
- (uint32_t)converted.iface.wmeBeContentionTimeStats.contentionNumSamples);
+ (uint32_t)converted.iface.links[0].wmeBeContentionTimeStats.contentionNumSamples);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].rx_mpdu,
- converted.iface.wmeBkPktStats.rxMpdu);
+ converted.iface.links[0].wmeBkPktStats.rxMpdu);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].tx_mpdu,
- converted.iface.wmeBkPktStats.txMpdu);
+ converted.iface.links[0].wmeBkPktStats.txMpdu);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].mpdu_lost,
- converted.iface.wmeBkPktStats.lostMpdu);
+ converted.iface.links[0].wmeBkPktStats.lostMpdu);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].retries,
- converted.iface.wmeBkPktStats.retries);
+ converted.iface.links[0].wmeBkPktStats.retries);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_min,
- (uint32_t)converted.iface.wmeBkContentionTimeStats.contentionTimeMinInUsec);
+ (uint32_t)converted.iface.links[0].wmeBkContentionTimeStats.contentionTimeMinInUsec);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_max,
- (uint32_t)converted.iface.wmeBkContentionTimeStats.contentionTimeMaxInUsec);
+ (uint32_t)converted.iface.links[0].wmeBkContentionTimeStats.contentionTimeMaxInUsec);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_avg,
- (uint32_t)converted.iface.wmeBkContentionTimeStats.contentionTimeAvgInUsec);
+ (uint32_t)converted.iface.links[0].wmeBkContentionTimeStats.contentionTimeAvgInUsec);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_num_samples,
- (uint32_t)converted.iface.wmeBkContentionTimeStats.contentionNumSamples);
+ (uint32_t)converted.iface.links[0].wmeBkContentionTimeStats.contentionNumSamples);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].rx_mpdu,
- converted.iface.wmeViPktStats.rxMpdu);
+ converted.iface.links[0].wmeViPktStats.rxMpdu);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].tx_mpdu,
- converted.iface.wmeViPktStats.txMpdu);
+ converted.iface.links[0].wmeViPktStats.txMpdu);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].mpdu_lost,
- converted.iface.wmeViPktStats.lostMpdu);
+ converted.iface.links[0].wmeViPktStats.lostMpdu);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].retries,
- converted.iface.wmeViPktStats.retries);
+ converted.iface.links[0].wmeViPktStats.retries);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_min,
- (uint32_t)converted.iface.wmeViContentionTimeStats.contentionTimeMinInUsec);
+ (uint32_t)converted.iface.links[0].wmeViContentionTimeStats.contentionTimeMinInUsec);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_max,
- (uint32_t)converted.iface.wmeViContentionTimeStats.contentionTimeMaxInUsec);
+ (uint32_t)converted.iface.links[0].wmeViContentionTimeStats.contentionTimeMaxInUsec);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_avg,
- (uint32_t)converted.iface.wmeViContentionTimeStats.contentionTimeAvgInUsec);
+ (uint32_t)converted.iface.links[0].wmeViContentionTimeStats.contentionTimeAvgInUsec);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_num_samples,
- (uint32_t)converted.iface.wmeViContentionTimeStats.contentionNumSamples);
+ (uint32_t)converted.iface.links[0].wmeViContentionTimeStats.contentionNumSamples);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].rx_mpdu,
- converted.iface.wmeVoPktStats.rxMpdu);
+ converted.iface.links[0].wmeVoPktStats.rxMpdu);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].tx_mpdu,
- converted.iface.wmeVoPktStats.txMpdu);
+ converted.iface.links[0].wmeVoPktStats.txMpdu);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost,
- converted.iface.wmeVoPktStats.lostMpdu);
+ converted.iface.links[0].wmeVoPktStats.lostMpdu);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries,
- converted.iface.wmeVoPktStats.retries);
+ converted.iface.links[0].wmeVoPktStats.retries);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_min,
- (uint32_t)converted.iface.wmeVoContentionTimeStats.contentionTimeMinInUsec);
+ (uint32_t)converted.iface.links[0].wmeVoContentionTimeStats.contentionTimeMinInUsec);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_max,
- (uint32_t)converted.iface.wmeVoContentionTimeStats.contentionTimeMaxInUsec);
+ (uint32_t)converted.iface.links[0].wmeVoContentionTimeStats.contentionTimeMaxInUsec);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_avg,
- (uint32_t)converted.iface.wmeVoContentionTimeStats.contentionTimeAvgInUsec);
+ (uint32_t)converted.iface.links[0].wmeVoContentionTimeStats.contentionTimeAvgInUsec);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_num_samples,
- (uint32_t)converted.iface.wmeVoContentionTimeStats.contentionNumSamples);
+ (uint32_t)converted.iface.links[0].wmeVoContentionTimeStats.contentionNumSamples);
EXPECT_EQ(legacy_stats.iface.info.time_slicing_duty_cycle_percent,
- converted.iface.timeSliceDutyCycleInPercent);
+ converted.iface.links[0].timeSliceDutyCycleInPercent);
EXPECT_EQ(legacy_stats.radios.size(), converted.radios.size());
for (size_t i = 0; i < legacy_stats.radios.size(); i++) {
@@ -331,29 +622,29 @@
}
}
- EXPECT_EQ(legacy_stats.peers.size(), converted.iface.peers.size());
+ EXPECT_EQ(legacy_stats.peers.size(), converted.iface.links[0].peers.size());
for (size_t i = 0; i < legacy_stats.peers.size(); i++) {
EXPECT_EQ(legacy_stats.peers[i].peer_info.bssload.sta_count,
- converted.iface.peers[i].staCount);
+ converted.iface.links[0].peers[i].staCount);
EXPECT_EQ(legacy_stats.peers[i].peer_info.bssload.chan_util,
- converted.iface.peers[i].chanUtil);
+ converted.iface.links[0].peers[i].chanUtil);
for (size_t j = 0; j < legacy_stats.peers[i].rate_stats.size(); j++) {
EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].rate.preamble,
- (uint32_t)converted.iface.peers[i].rateStats[j].rateInfo.preamble);
+ (uint32_t)converted.iface.links[0].peers[i].rateStats[j].rateInfo.preamble);
EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].rate.nss,
- (uint32_t)converted.iface.peers[i].rateStats[j].rateInfo.nss);
+ (uint32_t)converted.iface.links[0].peers[i].rateStats[j].rateInfo.nss);
EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].rate.bw,
- (uint32_t)converted.iface.peers[i].rateStats[j].rateInfo.bw);
+ (uint32_t)converted.iface.links[0].peers[i].rateStats[j].rateInfo.bw);
EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].rate.rateMcsIdx,
- (uint32_t)converted.iface.peers[i].rateStats[j].rateInfo.rateMcsIdx);
+ (uint32_t)converted.iface.links[0].peers[i].rateStats[j].rateInfo.rateMcsIdx);
EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].tx_mpdu,
- (uint32_t)converted.iface.peers[i].rateStats[j].txMpdu);
+ (uint32_t)converted.iface.links[0].peers[i].rateStats[j].txMpdu);
EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].rx_mpdu,
- (uint32_t)converted.iface.peers[i].rateStats[j].rxMpdu);
+ (uint32_t)converted.iface.links[0].peers[i].rateStats[j].rxMpdu);
EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].mpdu_lost,
- (uint32_t)converted.iface.peers[i].rateStats[j].mpduLost);
+ (uint32_t)converted.iface.links[0].peers[i].rateStats[j].mpduLost);
EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].retries,
- (uint32_t)converted.iface.peers[i].rateStats[j].retries);
+ (uint32_t)converted.iface.links[0].peers[i].rateStats[j].retries);
}
}
}
@@ -479,6 +770,100 @@
radio_configurations_array3);
}
+void verifyRttResult(wifi_rtt_result* legacy_rtt_result_ptr, RttResult* aidl_results_ptr) {
+ EXPECT_EQ((int)legacy_rtt_result_ptr->burst_num, aidl_results_ptr->burstNum);
+ EXPECT_EQ((int)legacy_rtt_result_ptr->measurement_number, aidl_results_ptr->measurementNumber);
+ EXPECT_EQ((int)legacy_rtt_result_ptr->success_number, aidl_results_ptr->successNumber);
+ EXPECT_EQ(legacy_rtt_result_ptr->number_per_burst_peer, aidl_results_ptr->numberPerBurstPeer);
+ EXPECT_EQ(legacy_rtt_result_ptr->retry_after_duration, aidl_results_ptr->retryAfterDuration);
+ EXPECT_EQ(legacy_rtt_result_ptr->rssi, aidl_results_ptr->rssi);
+ EXPECT_EQ(legacy_rtt_result_ptr->rssi_spread, aidl_results_ptr->rssiSpread);
+ EXPECT_EQ(legacy_rtt_result_ptr->rtt, aidl_results_ptr->rtt);
+ EXPECT_EQ(legacy_rtt_result_ptr->rtt_sd, aidl_results_ptr->rttSd);
+ EXPECT_EQ(legacy_rtt_result_ptr->rtt_spread, aidl_results_ptr->rttSpread);
+ EXPECT_EQ(legacy_rtt_result_ptr->distance_mm, aidl_results_ptr->distanceInMm);
+ EXPECT_EQ(legacy_rtt_result_ptr->distance_sd_mm, aidl_results_ptr->distanceSdInMm);
+ EXPECT_EQ(legacy_rtt_result_ptr->distance_spread_mm, aidl_results_ptr->distanceSpreadInMm);
+ EXPECT_EQ(legacy_rtt_result_ptr->ts, aidl_results_ptr->timeStampInUs);
+ EXPECT_EQ(legacy_rtt_result_ptr->burst_duration, aidl_results_ptr->burstDurationInMs);
+ EXPECT_EQ(legacy_rtt_result_ptr->negotiated_burst_num, aidl_results_ptr->negotiatedBurstNum);
+ EXPECT_EQ(legacy_rtt_result_ptr->LCI->id, aidl_results_ptr->lci.id);
+ for (int i = 0; i < legacy_rtt_result_ptr->LCI->len; i++) {
+ EXPECT_EQ(legacy_rtt_result_ptr->LCI->data[i], aidl_results_ptr->lci.data[i]);
+ }
+ EXPECT_EQ(legacy_rtt_result_ptr->LCR->id, aidl_results_ptr->lcr.id);
+ for (int i = 0; i < legacy_rtt_result_ptr->LCR->len; i++) {
+ EXPECT_EQ(legacy_rtt_result_ptr->LCR->data[i], aidl_results_ptr->lcr.data[i]);
+ }
+}
+
+void fillLegacyRttResult(wifi_rtt_result* rtt_result_ptr) {
+ std::copy(std::begin(kMacAddress), std::end(kMacAddress), std::begin(rtt_result_ptr->addr));
+ rtt_result_ptr->burst_num = rand();
+ rtt_result_ptr->measurement_number = rand();
+ rtt_result_ptr->success_number = rand();
+ rtt_result_ptr->number_per_burst_peer = 0xF & rand();
+ rtt_result_ptr->status = RTT_STATUS_SUCCESS;
+ rtt_result_ptr->retry_after_duration = 0xF & rand();
+ rtt_result_ptr->type = RTT_TYPE_2_SIDED;
+ rtt_result_ptr->rssi = rand();
+ rtt_result_ptr->rssi_spread = rand();
+ rtt_result_ptr->rtt = rand();
+ rtt_result_ptr->rtt_sd = rand();
+ rtt_result_ptr->rtt_spread = rand();
+ rtt_result_ptr->distance_mm = rand();
+ rtt_result_ptr->distance_sd_mm = rand();
+ rtt_result_ptr->distance_spread_mm = rand();
+ rtt_result_ptr->burst_duration = rand();
+ rtt_result_ptr->negotiated_burst_num = rand();
+ rtt_result_ptr->LCI = (wifi_information_element*)LCI;
+ rtt_result_ptr->LCR = (wifi_information_element*)LCR;
+}
+
+TEST_F(AidlStructUtilTest, convertLegacyVectorOfRttResultToAidl) {
+ std::vector<const wifi_rtt_result*> rtt_results_vec;
+ wifi_rtt_result rttResults[2];
+
+ // fill legacy rtt results
+ for (int i = 0; i < 2; i++) {
+ fillLegacyRttResult(&rttResults[i]);
+ rtt_results_vec.push_back(&rttResults[i]);
+ }
+
+ std::vector<RttResult> aidl_results;
+ aidl_struct_util::convertLegacyVectorOfRttResultToAidl(rtt_results_vec, &aidl_results);
+
+ EXPECT_EQ(rtt_results_vec.size(), aidl_results.size());
+ for (size_t i = 0; i < rtt_results_vec.size(); i++) {
+ verifyRttResult(&rttResults[i], &aidl_results[i]);
+ EXPECT_EQ(aidl_results[i].channelFreqMHz, 0);
+ EXPECT_EQ(aidl_results[i].packetBw, RttBw::BW_UNSPECIFIED);
+ }
+}
+
+TEST_F(AidlStructUtilTest, convertLegacyVectorOfRttResultV2ToAidl) {
+ std::vector<const wifi_rtt_result_v2*> rtt_results_vec_v2;
+ wifi_rtt_result_v2 rttResults_v2[2];
+
+ // fill legacy rtt results v2
+ for (int i = 0; i < 2; i++) {
+ fillLegacyRttResult(&rttResults_v2[i].rtt_result);
+ rttResults_v2[i].frequency = 2412 + i * 5;
+ rttResults_v2[i].packet_bw = WIFI_RTT_BW_80;
+ rtt_results_vec_v2.push_back(&rttResults_v2[i]);
+ }
+
+ std::vector<RttResult> aidl_results;
+ aidl_struct_util::convertLegacyVectorOfRttResultV2ToAidl(rtt_results_vec_v2, &aidl_results);
+
+ EXPECT_EQ(rtt_results_vec_v2.size(), aidl_results.size());
+ for (size_t i = 0; i < rtt_results_vec_v2.size(); i++) {
+ verifyRttResult(&rttResults_v2[i].rtt_result, &aidl_results[i]);
+ EXPECT_EQ(aidl_results[i].channelFreqMHz, rttResults_v2[i].frequency);
+ EXPECT_EQ(aidl_results[i].packetBw, RttBw::BW_80MHZ);
+ }
+}
+
} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wifi/aidl/default/tests/wifi_nan_iface_unit_tests.cpp b/wifi/aidl/default/tests/wifi_nan_iface_unit_tests.cpp
index d40801f..f81cab3 100644
--- a/wifi/aidl/default/tests/wifi_nan_iface_unit_tests.cpp
+++ b/wifi/aidl/default/tests/wifi_nan_iface_unit_tests.cpp
@@ -122,6 +122,18 @@
MOCK_METHOD1(eventDataPathTerminated, ndk::ScopedAStatus(int32_t));
MOCK_METHOD1(eventDataPathScheduleUpdate,
ndk::ScopedAStatus(const NanDataPathScheduleUpdateInd&));
+ MOCK_METHOD1(eventPairingConfirm, ndk::ScopedAStatus(const NanPairingConfirmInd&));
+ MOCK_METHOD1(eventPairingRequest, ndk::ScopedAStatus(const NanPairingRequestInd&));
+ MOCK_METHOD1(eventBootstrappingConfirm, ndk::ScopedAStatus(const NanBootstrappingConfirmInd&));
+ MOCK_METHOD1(eventBootstrappingRequest, ndk::ScopedAStatus(const NanBootstrappingRequestInd&));
+ MOCK_METHOD3(notifyInitiatePairingResponse,
+ ndk::ScopedAStatus(char16_t, const NanStatus&, int32_t));
+ MOCK_METHOD2(notifyRespondToPairingIndicationResponse,
+ ndk::ScopedAStatus(char16_t, const NanStatus&));
+ MOCK_METHOD3(notifyInitiateBootstrappingResponse,
+ ndk::ScopedAStatus(char16_t, const NanStatus&, int32_t));
+ MOCK_METHOD2(notifyRespondToBootstrappingIndicationResponse,
+ ndk::ScopedAStatus(char16_t, const NanStatus&));
};
class WifiNanIfaceTest : public Test {
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..54e91d4 100644
--- a/wifi/aidl/default/wifi_legacy_hal.cpp
+++ b/wifi/aidl/default/wifi_legacy_hal.cpp
@@ -119,6 +119,16 @@
}
}
+// Callback to be invoked for Multi link layer stats results.
+std::function<void((wifi_request_id, wifi_iface_ml_stat*, int, wifi_radio_stat*))>
+ on_link_layer_ml_stats_result_internal_callback;
+void onSyncLinkLayerMlStatsResult(wifi_request_id id, wifi_iface_ml_stat* iface_ml_stat,
+ int num_radios, wifi_radio_stat* radio_stat) {
+ if (on_link_layer_ml_stats_result_internal_callback) {
+ on_link_layer_ml_stats_result_internal_callback(id, iface_ml_stat, num_radios, radio_stat);
+ }
+}
+
// Callback to be invoked for rssi threshold breach.
std::function<void((wifi_request_id, uint8_t*, int8_t))>
on_rssi_threshold_breached_internal_callback;
@@ -171,11 +181,28 @@
// Callback to be invoked for rtt results results.
std::function<void(wifi_request_id, unsigned num_results, wifi_rtt_result* rtt_results[])>
on_rtt_results_internal_callback;
+std::function<void(wifi_request_id, unsigned num_results, wifi_rtt_result_v2* rtt_results_v2[])>
+ on_rtt_results_internal_callback_v2;
+
+void invalidateRttResultsCallbacks() {
+ on_rtt_results_internal_callback = nullptr;
+ on_rtt_results_internal_callback_v2 = nullptr;
+};
+
void onAsyncRttResults(wifi_request_id id, unsigned num_results, wifi_rtt_result* rtt_results[]) {
const auto lock = aidl_sync_util::acquireGlobalLock();
if (on_rtt_results_internal_callback) {
on_rtt_results_internal_callback(id, num_results, rtt_results);
- on_rtt_results_internal_callback = nullptr;
+ invalidateRttResultsCallbacks();
+ }
+}
+
+void onAsyncRttResultsV2(wifi_request_id id, unsigned num_results,
+ wifi_rtt_result_v2* rtt_results_v2[]) {
+ const auto lock = aidl_sync_util::acquireGlobalLock();
+ if (on_rtt_results_internal_callback_v2) {
+ on_rtt_results_internal_callback_v2(id, num_results, rtt_results_v2);
+ invalidateRttResultsCallbacks();
}
}
@@ -324,6 +351,40 @@
}
}
+std::function<void(const NanPairingRequestInd&)> on_nan_event_pairing_request_user_callback;
+void onAsyncNanEventPairingRequest(NanPairingRequestInd* event) {
+ const auto lock = aidl_sync_util::acquireGlobalLock();
+ if (on_nan_event_pairing_request_user_callback && event) {
+ on_nan_event_pairing_request_user_callback(*event);
+ }
+}
+
+std::function<void(const NanPairingConfirmInd&)> on_nan_event_pairing_confirm_user_callback;
+void onAsyncNanEventPairingConfirm(NanPairingConfirmInd* event) {
+ const auto lock = aidl_sync_util::acquireGlobalLock();
+ if (on_nan_event_pairing_confirm_user_callback && event) {
+ on_nan_event_pairing_confirm_user_callback(*event);
+ }
+}
+
+std::function<void(const NanBootstrappingRequestInd&)>
+ on_nan_event_bootstrapping_request_user_callback;
+void onAsyncNanEventBootstrappingRequest(NanBootstrappingRequestInd* event) {
+ const auto lock = aidl_sync_util::acquireGlobalLock();
+ if (on_nan_event_bootstrapping_request_user_callback && event) {
+ on_nan_event_bootstrapping_request_user_callback(*event);
+ }
+}
+
+std::function<void(const NanBootstrappingConfirmInd&)>
+ on_nan_event_bootstrapping_confirm_user_callback;
+void onAsyncNanEventBootstrappingConfirm(NanBootstrappingConfirmInd* event) {
+ const auto lock = aidl_sync_util::acquireGlobalLock();
+ if (on_nan_event_bootstrapping_confirm_user_callback && event) {
+ on_nan_event_bootstrapping_confirm_user_callback(*event);
+ }
+}
+
// Callbacks for the various TWT operations.
std::function<void(const TwtSetupResponse&)> on_twt_event_setup_response_callback;
void onAsyncTwtEventSetupResponse(TwtSetupResponse* event) {
@@ -682,10 +743,44 @@
&clear_mask_rsp, 1, &stop_rsp);
}
-std::pair<wifi_error, LinkLayerStats> WifiLegacyHal::getLinkLayerStats(
- const std::string& iface_name) {
- LinkLayerStats link_stats{};
+// Copies wifi_peer_info* to vector<WifiPeerInfo> and returns poiner to next element.
+wifi_peer_info* WifiLegacyHal::copyPeerInfo(wifi_peer_info* peer_ptr,
+ std::vector<WifiPeerInfo> peers) {
+ WifiPeerInfo peer;
+ peer.peer_info = *peer_ptr;
+ if (peer_ptr->num_rate > 0) {
+ // Copy the rate stats.
+ peer.rate_stats.assign(peer_ptr->rate_stats, peer_ptr->rate_stats + peer_ptr->num_rate);
+ }
+ peer.peer_info.num_rate = 0;
+ // Push peer info.
+ peers.push_back(peer);
+ // Return the address of next peer info.
+ return (wifi_peer_info*)((u8*)peer_ptr + sizeof(wifi_peer_info) +
+ (sizeof(wifi_rate_stat) * peer_ptr->num_rate));
+}
+// Copies wifi_link_stat* to vector<LinkStats> and returns poiner to next element.
+wifi_link_stat* WifiLegacyHal::copyLinkStat(wifi_link_stat* stat_ptr,
+ std::vector<LinkStats> stats) {
+ LinkStats linkStat;
+ linkStat.stat = *stat_ptr;
+ wifi_peer_info* l_peer_info_stats_ptr = stat_ptr->peer_info;
+ for (uint32_t i = 0; i < linkStat.stat.num_peers; i++) {
+ l_peer_info_stats_ptr = copyPeerInfo(l_peer_info_stats_ptr, linkStat.peers);
+ }
+ // Copied all peers to linkStat.peers.
+ linkStat.stat.num_peers = 0;
+ // Push link stat.
+ stats.push_back(linkStat);
+ // Read all peers, return the address of next wifi_link_stat.
+ return (wifi_link_stat*)l_peer_info_stats_ptr;
+}
+
+wifi_error WifiLegacyHal::getLinkLayerStats(const std::string& iface_name,
+ LinkLayerStats& link_stats,
+ LinkLayerMlStats& link_ml_stats) {
LinkLayerStats* link_stats_ptr = &link_stats;
+ link_stats_ptr->valid = false;
on_link_layer_stats_result_internal_callback = [&link_stats_ptr](
wifi_request_id /* id */,
@@ -694,6 +789,7 @@
wifi_radio_stat* radio_stats_ptr) {
wifi_radio_stat* l_radio_stats_ptr;
wifi_peer_info* l_peer_info_stats_ptr;
+ link_stats_ptr->valid = true;
if (iface_stats_ptr != nullptr) {
link_stats_ptr->iface = *iface_stats_ptr;
@@ -751,10 +847,69 @@
}
};
- wifi_error status = global_func_table_.wifi_get_link_stats(0, getIfaceHandle(iface_name),
- {onSyncLinkLayerStatsResult});
+ LinkLayerMlStats* link_ml_stats_ptr = &link_ml_stats;
+ link_ml_stats_ptr->valid = false;
+
+ on_link_layer_ml_stats_result_internal_callback =
+ [this, &link_ml_stats_ptr](wifi_request_id /* id */,
+ wifi_iface_ml_stat* iface_ml_stats_ptr, int num_radios,
+ wifi_radio_stat* radio_stats_ptr) {
+ wifi_radio_stat* l_radio_stats_ptr;
+ wifi_link_stat* l_link_stat_ptr;
+ link_ml_stats_ptr->valid = true;
+
+ if (iface_ml_stats_ptr != nullptr && iface_ml_stats_ptr->num_links > 0) {
+ // Copy stats from wifi_iface_ml_stat to LinkLayerMlStats,
+ // - num_links * links[] to vector of links.
+ // - num_peers * peer_info[] to vector of links[i].peers.
+ link_ml_stats_ptr->iface = *iface_ml_stats_ptr;
+ l_link_stat_ptr = iface_ml_stats_ptr->links;
+ for (int l = 0; l < iface_ml_stats_ptr->num_links; ++l) {
+ l_link_stat_ptr = copyLinkStat(l_link_stat_ptr, link_ml_stats_ptr->links);
+ }
+ } else {
+ LOG(ERROR) << "Invalid iface stats in link layer stats";
+ }
+ if (num_radios <= 0 || radio_stats_ptr == nullptr) {
+ LOG(ERROR) << "Invalid radio stats in link layer stats";
+ return;
+ }
+ l_radio_stats_ptr = radio_stats_ptr;
+ for (int i = 0; i < num_radios; i++) {
+ LinkLayerRadioStats radio;
+
+ radio.stats = *l_radio_stats_ptr;
+ // Copy over the tx level array to the separate vector.
+ if (l_radio_stats_ptr->num_tx_levels > 0 &&
+ l_radio_stats_ptr->tx_time_per_levels != nullptr) {
+ radio.tx_time_per_levels.assign(l_radio_stats_ptr->tx_time_per_levels,
+ l_radio_stats_ptr->tx_time_per_levels +
+ l_radio_stats_ptr->num_tx_levels);
+ }
+ radio.stats.num_tx_levels = 0;
+ radio.stats.tx_time_per_levels = nullptr;
+ /* Copy over the channel stat to separate vector */
+ if (l_radio_stats_ptr->num_channels > 0) {
+ /* Copy the channel stats */
+ radio.channel_stats.assign(
+ l_radio_stats_ptr->channels,
+ l_radio_stats_ptr->channels + l_radio_stats_ptr->num_channels);
+ }
+ link_ml_stats_ptr->radios.push_back(radio);
+ l_radio_stats_ptr =
+ (wifi_radio_stat*)((u8*)l_radio_stats_ptr + sizeof(wifi_radio_stat) +
+ (sizeof(wifi_channel_stat) *
+ l_radio_stats_ptr->num_channels));
+ }
+ };
+
+ wifi_error status = global_func_table_.wifi_get_link_stats(
+ 0, getIfaceHandle(iface_name),
+ {onSyncLinkLayerStatsResult, onSyncLinkLayerMlStatsResult});
on_link_layer_stats_result_internal_callback = nullptr;
- return {status, link_stats};
+ on_link_layer_ml_stats_result_internal_callback = nullptr;
+
+ return status;
}
wifi_error WifiLegacyHal::startRssiMonitoring(
@@ -1090,8 +1245,9 @@
wifi_error WifiLegacyHal::startRttRangeRequest(
const std::string& iface_name, wifi_request_id id,
const std::vector<wifi_rtt_config>& rtt_configs,
- const on_rtt_results_callback& on_results_user_callback) {
- if (on_rtt_results_internal_callback) {
+ const on_rtt_results_callback& on_results_user_callback,
+ const on_rtt_results_callback_v2& on_results_user_callback_v2) {
+ if (on_rtt_results_internal_callback || on_rtt_results_internal_callback_v2) {
return WIFI_ERROR_NOT_AVAILABLE;
}
@@ -1108,12 +1264,26 @@
on_results_user_callback(id, rtt_results_vec);
};
+ on_rtt_results_internal_callback_v2 = [on_results_user_callback_v2](
+ wifi_request_id id, unsigned num_results,
+ wifi_rtt_result_v2* rtt_results_v2[]) {
+ if (num_results > 0 && !rtt_results_v2) {
+ LOG(ERROR) << "Unexpected nullptr in RTT results";
+ return;
+ }
+ std::vector<const wifi_rtt_result_v2*> rtt_results_vec_v2;
+ std::copy_if(rtt_results_v2, rtt_results_v2 + num_results,
+ back_inserter(rtt_results_vec_v2),
+ [](wifi_rtt_result_v2* rtt_result_v2) { return rtt_result_v2 != nullptr; });
+ on_results_user_callback_v2(id, rtt_results_vec_v2);
+ };
+
std::vector<wifi_rtt_config> rtt_configs_internal(rtt_configs);
wifi_error status = global_func_table_.wifi_rtt_range_request(
id, getIfaceHandle(iface_name), rtt_configs.size(), rtt_configs_internal.data(),
- {onAsyncRttResults});
+ {onAsyncRttResults, onAsyncRttResultsV2});
if (status != WIFI_SUCCESS) {
- on_rtt_results_internal_callback = nullptr;
+ invalidateRttResultsCallbacks();
}
return status;
}
@@ -1121,7 +1291,7 @@
wifi_error WifiLegacyHal::cancelRttRangeRequest(
const std::string& iface_name, wifi_request_id id,
const std::vector<std::array<uint8_t, ETH_ALEN>>& mac_addrs) {
- if (!on_rtt_results_internal_callback) {
+ if (!on_rtt_results_internal_callback && !on_rtt_results_internal_callback_v2) {
return WIFI_ERROR_NOT_AVAILABLE;
}
static_assert(sizeof(mac_addr) == sizeof(std::array<uint8_t, ETH_ALEN>),
@@ -1135,7 +1305,7 @@
// If the request Id is wrong, don't stop the ongoing range request. Any
// other error should be treated as the end of rtt ranging.
if (status != WIFI_ERROR_INVALID_REQUEST_ID) {
- on_rtt_results_internal_callback = nullptr;
+ invalidateRttResultsCallbacks();
}
return status;
}
@@ -1194,6 +1364,12 @@
on_nan_event_tca_user_callback = user_callbacks.on_event_tca;
on_nan_event_beacon_sdf_payload_user_callback = user_callbacks.on_event_beacon_sdf_payload;
on_nan_event_data_path_request_user_callback = user_callbacks.on_event_data_path_request;
+ on_nan_event_pairing_request_user_callback = user_callbacks.on_event_pairing_request;
+ on_nan_event_pairing_confirm_user_callback = user_callbacks.on_event_pairing_confirm;
+ on_nan_event_bootstrapping_request_user_callback =
+ user_callbacks.on_event_bootstrapping_request;
+ on_nan_event_bootstrapping_confirm_user_callback =
+ user_callbacks.on_event_bootstrapping_confirm;
on_nan_event_data_path_confirm_user_callback = user_callbacks.on_event_data_path_confirm;
on_nan_event_data_path_end_user_callback = user_callbacks.on_event_data_path_end;
on_nan_event_transmit_follow_up_user_callback = user_callbacks.on_event_transmit_follow_up;
@@ -1201,16 +1377,29 @@
on_nan_event_range_report_user_callback = user_callbacks.on_event_range_report;
on_nan_event_schedule_update_user_callback = user_callbacks.on_event_schedule_update;
- return global_func_table_.wifi_nan_register_handler(
- getIfaceHandle(iface_name),
- {onAsyncNanNotifyResponse, onAsyncNanEventPublishReplied,
- onAsyncNanEventPublishTerminated, onAsyncNanEventMatch, onAsyncNanEventMatchExpired,
- onAsyncNanEventSubscribeTerminated, onAsyncNanEventFollowup,
- onAsyncNanEventDiscEngEvent, onAsyncNanEventDisabled, onAsyncNanEventTca,
- onAsyncNanEventBeaconSdfPayload, onAsyncNanEventDataPathRequest,
- onAsyncNanEventDataPathConfirm, onAsyncNanEventDataPathEnd,
- onAsyncNanEventTransmitFollowUp, onAsyncNanEventRangeRequest,
- onAsyncNanEventRangeReport, onAsyncNanEventScheduleUpdate});
+ return global_func_table_.wifi_nan_register_handler(getIfaceHandle(iface_name),
+ {onAsyncNanNotifyResponse,
+ onAsyncNanEventPublishReplied,
+ onAsyncNanEventPublishTerminated,
+ onAsyncNanEventMatch,
+ onAsyncNanEventMatchExpired,
+ onAsyncNanEventSubscribeTerminated,
+ onAsyncNanEventFollowup,
+ onAsyncNanEventDiscEngEvent,
+ onAsyncNanEventDisabled,
+ onAsyncNanEventTca,
+ onAsyncNanEventBeaconSdfPayload,
+ onAsyncNanEventDataPathRequest,
+ onAsyncNanEventDataPathConfirm,
+ onAsyncNanEventDataPathEnd,
+ onAsyncNanEventTransmitFollowUp,
+ onAsyncNanEventRangeRequest,
+ onAsyncNanEventRangeReport,
+ onAsyncNanEventScheduleUpdate,
+ onAsyncNanEventPairingRequest,
+ onAsyncNanEventPairingConfirm,
+ onAsyncNanEventBootstrappingRequest,
+ onAsyncNanEventBootstrappingConfirm});
}
wifi_error WifiLegacyHal::nanEnableRequest(const std::string& iface_name, transaction_id id,
@@ -1325,6 +1514,36 @@
&msg_internal);
}
+wifi_error WifiLegacyHal::nanPairingRequest(const std::string& iface_name, transaction_id id,
+ const NanPairingRequest& msg) {
+ NanPairingRequest msg_internal(msg);
+ return global_func_table_.wifi_nan_pairing_request(id, getIfaceHandle(iface_name),
+ &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanPairingIndicationResponse(const std::string& iface_name,
+ transaction_id id,
+ const NanPairingIndicationResponse& msg) {
+ NanPairingIndicationResponse msg_internal(msg);
+ return global_func_table_.wifi_nan_pairing_indication_response(id, getIfaceHandle(iface_name),
+ &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanBootstrappingRequest(const std::string& iface_name, transaction_id id,
+ const NanBootstrappingRequest& msg) {
+ NanBootstrappingRequest msg_internal(msg);
+ return global_func_table_.wifi_nan_bootstrapping_request(id, getIfaceHandle(iface_name),
+ &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanBootstrappingIndicationResponse(
+ const std::string& iface_name, transaction_id id,
+ const NanBootstrappingIndicationResponse& msg) {
+ NanBootstrappingIndicationResponse msg_internal(msg);
+ return global_func_table_.wifi_nan_bootstrapping_indication_response(
+ id, getIfaceHandle(iface_name), &msg_internal);
+}
+
typedef struct {
u8 num_ndp_instances;
NanDataPathId ndp_instance_id;
@@ -1609,6 +1828,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();
@@ -1617,12 +1843,13 @@
on_gscan_event_internal_callback = nullptr;
on_gscan_full_result_internal_callback = nullptr;
on_link_layer_stats_result_internal_callback = nullptr;
+ on_link_layer_ml_stats_result_internal_callback = nullptr;
on_rssi_threshold_breached_internal_callback = nullptr;
on_ring_buffer_data_internal_callback = nullptr;
on_error_alert_internal_callback = nullptr;
on_radio_mode_change_internal_callback = nullptr;
on_subsystem_restart_internal_callback = nullptr;
- on_rtt_results_internal_callback = nullptr;
+ invalidateRttResultsCallbacks();
on_nan_notify_response_user_callback = nullptr;
on_nan_event_publish_terminated_user_callback = nullptr;
on_nan_event_match_user_callback = nullptr;
@@ -1634,6 +1861,10 @@
on_nan_event_tca_user_callback = nullptr;
on_nan_event_beacon_sdf_payload_user_callback = nullptr;
on_nan_event_data_path_request_user_callback = nullptr;
+ on_nan_event_pairing_request_user_callback = nullptr;
+ on_nan_event_pairing_confirm_user_callback = nullptr;
+ on_nan_event_bootstrapping_request_user_callback = nullptr;
+ on_nan_event_bootstrapping_confirm_user_callback = nullptr;
on_nan_event_data_path_confirm_user_callback = nullptr;
on_nan_event_data_path_end_user_callback = nullptr;
on_nan_event_transmit_follow_up_user_callback = nullptr;
diff --git a/wifi/aidl/default/wifi_legacy_hal.h b/wifi/aidl/default/wifi_legacy_hal.h
index cd8c0b1..5620280 100644
--- a/wifi/aidl/default/wifi_legacy_hal.h
+++ b/wifi/aidl/default/wifi_legacy_hal.h
@@ -36,6 +36,7 @@
namespace legacy_hal {
// Import all the types defined inside the legacy HAL header files into this
// namespace.
+using ::Akm;
using ::chre_nan_rtt_state;
using ::frame_info;
using ::frame_type;
@@ -44,6 +45,8 @@
using ::FRAME_TYPE_UNKNOWN;
using ::fw_roaming_state_t;
using ::mac_addr;
+using ::NAN_BOOTSTRAPPING_INITIATOR_RESPONSE;
+using ::NAN_BOOTSTRAPPING_RESPONDER_RESPONSE;
using ::NAN_CHANNEL_24G_BAND;
using ::NAN_CHANNEL_5G_BAND_HIGH;
using ::NAN_CHANNEL_5G_BAND_LOW;
@@ -65,6 +68,10 @@
using ::NAN_MATCH_ALG_MATCH_CONTINUOUS;
using ::NAN_MATCH_ALG_MATCH_NEVER;
using ::NAN_MATCH_ALG_MATCH_ONCE;
+using ::NAN_PAIRING_INITIATOR_RESPONSE;
+using ::NAN_PAIRING_RESPONDER_RESPONSE;
+using ::NAN_PAIRING_SETUP;
+using ::NAN_PAIRING_VERIFICATION;
using ::NAN_PUBLISH_TYPE_SOLICITED;
using ::NAN_PUBLISH_TYPE_UNSOLICITED;
using ::NAN_PUBLISH_TYPE_UNSOLICITED_SOLICITED;
@@ -97,7 +104,9 @@
using ::NAN_STATUS_ALREADY_ENABLED;
using ::NAN_STATUS_FOLLOWUP_QUEUE_FULL;
using ::NAN_STATUS_INTERNAL_FAILURE;
+using ::NAN_STATUS_INVALID_BOOTSTRAPPING_ID;
using ::NAN_STATUS_INVALID_NDP_ID;
+using ::NAN_STATUS_INVALID_PAIRING_ID;
using ::NAN_STATUS_INVALID_PARAM;
using ::NAN_STATUS_INVALID_PUBLISH_SUBSCRIBE_ID;
using ::NAN_STATUS_INVALID_REQUESTOR_INSTANCE_ID;
@@ -117,6 +126,12 @@
using ::NAN_TX_TYPE_UNICAST;
using ::NAN_USE_SRF;
using ::NanBeaconSdfPayloadInd;
+using ::NanBootstrappingConfirmInd;
+using ::NanBootstrappingIndicationResponse;
+using ::NanBootstrappingRequest;
+using ::NanBootstrappingRequestInd;
+using ::NanBootstrappingRequestResponse;
+using ::NanBootstrappingResponseCode;
using ::NanCapabilities;
using ::NanChannelInfo;
using ::NanConfigRequest;
@@ -131,9 +146,18 @@
using ::NanDiscEngEventInd;
using ::NanEnableRequest;
using ::NanFollowupInd;
+using ::NanIdentityResolutionAttribute;
using ::NanMatchAlg;
using ::NanMatchExpiredInd;
using ::NanMatchInd;
+using ::NanPairingConfig;
+using ::NanPairingConfirmInd;
+using ::NanPairingIndicationResponse;
+using ::NanPairingRequest;
+using ::NanPairingRequestInd;
+using ::NanPairingRequestResponse;
+using ::NanPairingRequestType;
+using ::NanPairingResponseCode;
using ::NanPublishCancelRequest;
using ::NanPublishRequest;
using ::NanPublishTerminatedInd;
@@ -150,6 +174,8 @@
using ::NanTransmitFollowupInd;
using ::NanTransmitFollowupRequest;
using ::NanTxType;
+using ::NpkSecurityAssociation;
+using ::PASN;
using ::ROAMING_DISABLE;
using ::ROAMING_ENABLE;
using ::RTT_PEER_AP;
@@ -189,6 +215,7 @@
using ::RX_PKT_FATE_FW_DROP_OTHER;
using ::RX_PKT_FATE_FW_QUEUED;
using ::RX_PKT_FATE_SUCCESS;
+using ::SAE;
using ::ssid_t;
using ::transaction_id;
using ::TX_PKT_FATE_ACKED;
@@ -232,6 +259,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;
@@ -304,6 +332,7 @@
using ::WIFI_RTT_BW_40;
using ::WIFI_RTT_BW_5;
using ::WIFI_RTT_BW_80;
+using ::WIFI_RTT_BW_UNSPECIFIED;
using ::wifi_rtt_capabilities;
using ::wifi_rtt_config;
using ::wifi_rtt_preamble;
@@ -314,6 +343,7 @@
using ::WIFI_RTT_PREAMBLE_VHT;
using ::wifi_rtt_responder;
using ::wifi_rtt_result;
+using ::wifi_rtt_result_v2;
using ::wifi_rtt_status;
using ::wifi_rtt_type;
using ::wifi_rx_packet_fate;
@@ -362,7 +392,21 @@
wifi_iface_stat iface;
std::vector<LinkLayerRadioStats> radios;
std::vector<WifiPeerInfo> peers;
+ bool valid;
};
+
+struct LinkStats {
+ wifi_link_stat stat;
+ std::vector<WifiPeerInfo> peers;
+};
+
+struct LinkLayerMlStats {
+ wifi_iface_ml_stat iface;
+ std::vector<LinkStats> links;
+ std::vector<LinkLayerRadioStats> radios;
+ bool valid;
+};
+
#pragma GCC diagnostic pop
// The |WLAN_DRIVER_WAKE_REASON_CNT.cmd_event_wake_cnt| and
@@ -397,6 +441,10 @@
std::function<void(const NanRangeRequestInd&)> on_event_range_request;
std::function<void(const NanRangeReportInd&)> on_event_range_report;
std::function<void(const NanDataPathScheduleUpdateInd&)> on_event_schedule_update;
+ std::function<void(const NanPairingRequestInd&)> on_event_pairing_request;
+ std::function<void(const NanPairingConfirmInd&)> on_event_pairing_confirm;
+ std::function<void(const NanBootstrappingRequestInd&)> on_event_bootstrapping_request;
+ std::function<void(const NanBootstrappingConfirmInd&)> on_event_bootstrapping_confirm;
};
// Full scan results contain IE info and are hence passed by reference, to
@@ -419,6 +467,8 @@
// the pointer.
using on_rtt_results_callback =
std::function<void(wifi_request_id, const std::vector<const wifi_rtt_result*>&)>;
+using on_rtt_results_callback_v2 =
+ std::function<void(wifi_request_id, const std::vector<const wifi_rtt_result_v2*>&)>;
// Callback for ring buffer data.
using on_ring_buffer_data_callback = std::function<void(
@@ -536,7 +586,9 @@
// Link layer stats functions.
wifi_error enableLinkLayerStats(const std::string& iface_name, bool debug);
wifi_error disableLinkLayerStats(const std::string& iface_name);
- std::pair<wifi_error, LinkLayerStats> getLinkLayerStats(const std::string& iface_name);
+ wifi_error getLinkLayerStats(const std::string& iface_name,
+ legacy_hal::LinkLayerStats& legacy_stats,
+ legacy_hal::LinkLayerMlStats& legacy_ml_stats);
// RSSI monitor functions.
wifi_error startRssiMonitoring(
const std::string& iface_name, wifi_request_id id, int8_t max_rssi, int8_t min_rssi,
@@ -589,7 +641,8 @@
// RTT functions.
wifi_error startRttRangeRequest(const std::string& iface_name, wifi_request_id id,
const std::vector<wifi_rtt_config>& rtt_configs,
- const on_rtt_results_callback& on_results_callback);
+ const on_rtt_results_callback& on_results_callback,
+ const on_rtt_results_callback_v2& on_results_callback_v2);
wifi_error cancelRttRangeRequest(const std::string& iface_name, wifi_request_id id,
const std::vector<std::array<uint8_t, ETH_ALEN>>& mac_addrs);
std::pair<wifi_error, wifi_rtt_capabilities> getRttCapabilities(const std::string& iface_name);
@@ -636,6 +689,14 @@
const NanDataPathInitiatorRequest& msg);
wifi_error nanDataIndicationResponse(const std::string& iface_name, transaction_id id,
const NanDataPathIndicationResponse& msg);
+ wifi_error nanPairingRequest(const std::string& iface_name, transaction_id id,
+ const NanPairingRequest& msg);
+ wifi_error nanPairingIndicationResponse(const std::string& iface_name, transaction_id id,
+ const NanPairingIndicationResponse& msg);
+ wifi_error nanBootstrappingRequest(const std::string& iface_name, transaction_id id,
+ const NanBootstrappingRequest& msg);
+ wifi_error nanBootstrappingIndicationResponse(const std::string& iface_name, transaction_id id,
+ const NanBootstrappingIndicationResponse& msg);
wifi_error nanDataEnd(const std::string& iface_name, transaction_id id, uint32_t ndpInstanceId);
// AP functions.
wifi_error setCountryCode(const std::string& iface_name, const std::array<uint8_t, 2> code);
@@ -693,6 +754,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.
@@ -708,6 +770,8 @@
// Handles wifi (error) status of Virtual interface create/delete
wifi_error handleVirtualInterfaceCreateOrDeleteStatus(const std::string& ifname,
wifi_error status);
+ wifi_link_stat* copyLinkStat(wifi_link_stat* stat_ptr, std::vector<LinkStats> stats);
+ wifi_peer_info* copyPeerInfo(wifi_peer_info* peer_ptr, std::vector<WifiPeerInfo> peers);
// Global function table of legacy HAL.
wifi_hal_fn global_func_table_;
diff --git a/wifi/aidl/default/wifi_legacy_hal_stubs.cpp b/wifi/aidl/default/wifi_legacy_hal_stubs.cpp
index cff7f69..a0cb2c0 100644
--- a/wifi/aidl/default/wifi_legacy_hal_stubs.cpp
+++ b/wifi/aidl/default/wifi_legacy_hal_stubs.cpp
@@ -126,6 +126,10 @@
populateStubFor(&hal_fn->wifi_nan_data_interface_delete);
populateStubFor(&hal_fn->wifi_nan_data_request_initiator);
populateStubFor(&hal_fn->wifi_nan_data_indication_response);
+ populateStubFor(&hal_fn->wifi_nan_pairing_request);
+ populateStubFor(&hal_fn->wifi_nan_pairing_indication_response);
+ populateStubFor(&hal_fn->wifi_nan_bootstrapping_request);
+ populateStubFor(&hal_fn->wifi_nan_bootstrapping_indication_response);
populateStubFor(&hal_fn->wifi_nan_data_end);
populateStubFor(&hal_fn->wifi_get_packet_filter_capabilities);
populateStubFor(&hal_fn->wifi_set_packet_filter);
@@ -167,6 +171,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_nan_iface.cpp b/wifi/aidl/default/wifi_nan_iface.cpp
index 9edef09..ce6902d 100644
--- a/wifi/aidl/default/wifi_nan_iface.cpp
+++ b/wifi/aidl/default/wifi_nan_iface.cpp
@@ -205,6 +205,46 @@
}
break;
}
+ case legacy_hal::NAN_PAIRING_INITIATOR_RESPONSE: {
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->notifyInitiatePairingResponse(
+ id, nanStatus,
+ msg.body.pairing_request_response.paring_instance_id)
+ .isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ break;
+ }
+ case legacy_hal::NAN_PAIRING_RESPONDER_RESPONSE: {
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->notifyRespondToPairingIndicationResponse(id, nanStatus).isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ break;
+ }
+ case legacy_hal::NAN_BOOTSTRAPPING_INITIATOR_RESPONSE: {
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->notifyInitiateBootstrappingResponse(
+ id, nanStatus,
+ msg.body.bootstrapping_request_response
+ .bootstrapping_instance_id)
+ .isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ break;
+ }
+ case legacy_hal::NAN_BOOTSTRAPPING_RESPONDER_RESPONSE: {
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->notifyRespondToBootstrappingIndicationResponse(id, nanStatus)
+ .isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ break;
+ }
case legacy_hal::NAN_RESPONSE_BEACON_SDF_PAYLOAD:
/* fall through */
case legacy_hal::NAN_RESPONSE_TCA:
@@ -421,6 +461,85 @@
}
};
+ callback_handlers.on_event_pairing_request =
+ [weak_ptr_this](const legacy_hal::NanPairingRequestInd& msg) {
+ const auto shared_ptr_this = weak_ptr_this.lock();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ NanPairingRequestInd aidl_struct;
+ if (!aidl_struct_util::convertLegacyNanPairingRequestIndToAidl(msg, &aidl_struct)) {
+ LOG(ERROR) << "Failed to convert nan capabilities response";
+ return;
+ }
+
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->eventPairingRequest(aidl_struct).isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ };
+ callback_handlers.on_event_pairing_confirm =
+ [weak_ptr_this](const legacy_hal::NanPairingConfirmInd& msg) {
+ const auto shared_ptr_this = weak_ptr_this.lock();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ NanPairingConfirmInd aidl_struct;
+ if (!aidl_struct_util::convertLegacyNanPairingConfirmIndToAidl(msg, &aidl_struct)) {
+ LOG(ERROR) << "Failed to convert nan capabilities response";
+ return;
+ }
+
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->eventPairingConfirm(aidl_struct).isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ };
+ callback_handlers.on_event_bootstrapping_request =
+ [weak_ptr_this](const legacy_hal::NanBootstrappingRequestInd& msg) {
+ const auto shared_ptr_this = weak_ptr_this.lock();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ NanBootstrappingRequestInd aidl_struct;
+ if (!aidl_struct_util::convertLegacyNanBootstrappingRequestIndToAidl(
+ msg, &aidl_struct)) {
+ LOG(ERROR) << "Failed to convert nan capabilities response";
+ return;
+ }
+
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->eventBootstrappingRequest(aidl_struct).isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ };
+ callback_handlers.on_event_bootstrapping_confirm =
+ [weak_ptr_this](const legacy_hal::NanBootstrappingConfirmInd& msg) {
+ const auto shared_ptr_this = weak_ptr_this.lock();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "Callback invoked on an invalid object";
+ return;
+ }
+ NanBootstrappingConfirmInd aidl_struct;
+ if (!aidl_struct_util::convertLegacyNanBootstrappingConfirmIndToAidl(
+ msg, &aidl_struct)) {
+ LOG(ERROR) << "Failed to convert nan capabilities response";
+ return;
+ }
+
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->eventBootstrappingConfirm(aidl_struct).isOk()) {
+ LOG(ERROR) << "Failed to invoke the callback";
+ }
+ }
+ };
+
callback_handlers.on_event_beacon_sdf_payload =
[](const legacy_hal::NanBeaconSdfPayloadInd& /* msg */) {
LOG(ERROR) << "on_event_beacon_sdf_payload - should not be called";
@@ -611,6 +730,32 @@
in_ndpInstanceId);
}
+ndk::ScopedAStatus WifiNanIface::initiatePairingRequest(char16_t in_cmdId,
+ const NanPairingRequest& in_msg) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::initiatePairingRequestInternal, in_cmdId, in_msg);
+}
+
+ndk::ScopedAStatus WifiNanIface::respondToPairingIndicationRequest(
+ char16_t in_cmdId, const NanRespondToPairingIndicationRequest& in_msg) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::respondToPairingIndicationRequestInternal, in_cmdId,
+ in_msg);
+}
+
+ndk::ScopedAStatus WifiNanIface::initiateBootstrappingRequest(
+ char16_t in_cmdId, const NanBootstrappingRequest& in_msg) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::initiateBootstrappingRequestInternal, in_cmdId, in_msg);
+}
+
+ndk::ScopedAStatus WifiNanIface::respondToBootstrappingIndicationRequest(
+ char16_t in_cmdId, const NanBootstrappingResponse& in_msg) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiNanIface::respondToBootstrappingIndicationRequestInternal, in_cmdId,
+ in_msg);
+}
+
std::pair<std::string, ndk::ScopedAStatus> WifiNanIface::getNameInternal() {
return {ifname_, ndk::ScopedAStatus::ok()};
}
@@ -744,6 +889,47 @@
legacy_hal_.lock()->nanDataEnd(ifname_, cmd_id, ndpInstanceId);
return createWifiStatusFromLegacyError(legacy_status);
}
+ndk::ScopedAStatus WifiNanIface::initiatePairingRequestInternal(char16_t cmd_id,
+ const NanPairingRequest& msg) {
+ legacy_hal::NanPairingRequest legacy_msg;
+ if (!aidl_struct_util::convertAidlNanPairingInitiatorRequestToLegacy(msg, &legacy_msg)) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->nanPairingRequest(ifname_, cmd_id, legacy_msg);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+ndk::ScopedAStatus WifiNanIface::respondToPairingIndicationRequestInternal(
+ char16_t cmd_id, const NanRespondToPairingIndicationRequest& msg) {
+ legacy_hal::NanPairingIndicationResponse legacy_msg;
+ if (!aidl_struct_util::convertAidlNanPairingIndicationResponseToLegacy(msg, &legacy_msg)) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->nanPairingIndicationResponse(ifname_, cmd_id, legacy_msg);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+ndk::ScopedAStatus WifiNanIface::initiateBootstrappingRequestInternal(
+ char16_t cmd_id, const NanBootstrappingRequest& msg) {
+ legacy_hal::NanBootstrappingRequest legacy_msg;
+ if (!aidl_struct_util::convertAidlNanBootstrappingInitiatorRequestToLegacy(msg, &legacy_msg)) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->nanBootstrappingRequest(ifname_, cmd_id, legacy_msg);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+ndk::ScopedAStatus WifiNanIface::respondToBootstrappingIndicationRequestInternal(
+ char16_t cmd_id, const NanBootstrappingResponse& msg) {
+ legacy_hal::NanBootstrappingIndicationResponse legacy_msg;
+ if (!aidl_struct_util::convertAidlNanBootstrappingIndicationResponseToLegacy(msg,
+ &legacy_msg)) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->nanBootstrappingIndicationResponse(ifname_, cmd_id, legacy_msg);
+ return createWifiStatusFromLegacyError(legacy_status);
+}
} // namespace wifi
} // namespace hardware
diff --git a/wifi/aidl/default/wifi_nan_iface.h b/wifi/aidl/default/wifi_nan_iface.h
index 1018905..591eca9 100644
--- a/wifi/aidl/default/wifi_nan_iface.h
+++ b/wifi/aidl/default/wifi_nan_iface.h
@@ -78,6 +78,14 @@
char16_t in_cmdId, const NanRespondToDataPathIndicationRequest& in_msg) override;
ndk::ScopedAStatus terminateDataPathRequest(char16_t in_cmdId,
int32_t in_ndpInstanceId) override;
+ ndk::ScopedAStatus initiatePairingRequest(char16_t in_cmdId,
+ const NanPairingRequest& in_msg) override;
+ ndk::ScopedAStatus respondToPairingIndicationRequest(
+ char16_t in_cmdId, const NanRespondToPairingIndicationRequest& in_msg) override;
+ ndk::ScopedAStatus initiateBootstrappingRequest(char16_t in_cmdId,
+ const NanBootstrappingRequest& in_msg) override;
+ ndk::ScopedAStatus respondToBootstrappingIndicationRequest(
+ char16_t in_cmdId, const NanBootstrappingResponse& in_msg) override;
protected:
// Accessible to child class in the gTest suite.
@@ -111,6 +119,14 @@
ndk::ScopedAStatus respondToDataPathIndicationRequestInternal(
char16_t cmd_id, const NanRespondToDataPathIndicationRequest& msg);
ndk::ScopedAStatus terminateDataPathRequestInternal(char16_t cmd_id, int32_t ndpInstanceId);
+ ndk::ScopedAStatus initiatePairingRequestInternal(char16_t cmd_id,
+ const NanPairingRequest& msg);
+ ndk::ScopedAStatus respondToPairingIndicationRequestInternal(
+ char16_t cmd_id, const NanRespondToPairingIndicationRequest& msg);
+ ndk::ScopedAStatus initiateBootstrappingRequestInternal(char16_t cmd_id,
+ const NanBootstrappingRequest& msg);
+ ndk::ScopedAStatus respondToBootstrappingIndicationRequestInternal(
+ char16_t cmd_id, const NanBootstrappingResponse& msg);
// Overridden in the gTest suite.
virtual std::set<std::shared_ptr<IWifiNanIfaceEventCallback>> getEventCallbacks();
diff --git a/wifi/aidl/default/wifi_rtt_controller.cpp b/wifi/aidl/default/wifi_rtt_controller.cpp
index 856c3cd..a5f6768 100644
--- a/wifi/aidl/default/wifi_rtt_controller.cpp
+++ b/wifi/aidl/default/wifi_rtt_controller.cpp
@@ -161,8 +161,28 @@
}
}
};
+ const auto& on_results_callback_v2 =
+ [weak_ptr_this](legacy_hal::wifi_request_id id,
+ const std::vector<const legacy_hal::wifi_rtt_result_v2*>& results) {
+ const auto shared_ptr_this = weak_ptr_this.lock();
+ if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+ LOG(ERROR) << "v2 Callback invoked on an invalid object";
+ return;
+ }
+ std::vector<RttResult> aidl_results;
+ if (!aidl_struct_util::convertLegacyVectorOfRttResultV2ToAidl(results,
+ &aidl_results)) {
+ LOG(ERROR) << "Failed to convert rtt results v2 to AIDL structs";
+ return;
+ }
+ for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+ if (!callback->onResults(id, aidl_results).isOk()) {
+ LOG(ERROR) << "Failed to invoke the v2 callback";
+ }
+ }
+ };
legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->startRttRangeRequest(
- ifname_, cmd_id, legacy_configs, on_results_callback);
+ ifname_, cmd_id, legacy_configs, on_results_callback, on_results_callback_v2);
return createWifiStatusFromLegacyError(legacy_status);
}
diff --git a/wifi/aidl/default/wifi_sta_iface.cpp b/wifi/aidl/default/wifi_sta_iface.cpp
index ce90349..08ed9d2 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()};
}
@@ -399,13 +404,22 @@
std::pair<StaLinkLayerStats, ndk::ScopedAStatus> WifiStaIface::getLinkLayerStatsInternal() {
legacy_hal::wifi_error legacy_status;
- legacy_hal::LinkLayerStats legacy_stats;
- std::tie(legacy_status, legacy_stats) = legacy_hal_.lock()->getLinkLayerStats(ifname_);
+ legacy_hal::LinkLayerStats legacy_stats{};
+ legacy_hal::LinkLayerMlStats legacy_ml_stats{};
+ legacy_status = legacy_hal_.lock()->getLinkLayerStats(ifname_, legacy_stats, legacy_ml_stats);
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
return {StaLinkLayerStats{}, createWifiStatusFromLegacyError(legacy_status)};
}
StaLinkLayerStats aidl_stats;
- if (!aidl_struct_util::convertLegacyLinkLayerStatsToAidl(legacy_stats, &aidl_stats)) {
+ if (legacy_stats.valid) {
+ if (!aidl_struct_util::convertLegacyLinkLayerStatsToAidl(legacy_stats, &aidl_stats)) {
+ return {StaLinkLayerStats{}, createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)};
+ }
+ } else if (legacy_ml_stats.valid) {
+ if (!aidl_struct_util::convertLegacyLinkLayerMlStatsToAidl(legacy_ml_stats, &aidl_stats)) {
+ return {StaLinkLayerStats{}, createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)};
+ }
+ } else {
return {StaLinkLayerStats{}, createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)};
}
return {aidl_stats, ndk::ScopedAStatus::ok()};
@@ -552,6 +566,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/aidl/vts/functional/wifi_aidl_test_utils.cpp b/wifi/aidl/vts/functional/wifi_aidl_test_utils.cpp
index 6722f36..463545b 100644
--- a/wifi/aidl/vts/functional/wifi_aidl_test_utils.cpp
+++ b/wifi/aidl/vts/functional/wifi_aidl_test_utils.cpp
@@ -214,3 +214,7 @@
}
return 0;
}
+
+bool isAidlServiceAvailable(const char* instance_name) {
+ return AServiceManager_isDeclared(instance_name);
+}
diff --git a/wifi/aidl/vts/functional/wifi_aidl_test_utils.h b/wifi/aidl/vts/functional/wifi_aidl_test_utils.h
index ad16603..2eac950 100644
--- a/wifi/aidl/vts/functional/wifi_aidl_test_utils.h
+++ b/wifi/aidl/vts/functional/wifi_aidl_test_utils.h
@@ -46,3 +46,4 @@
void stopWifiService(const char* instance_name);
int32_t getChipCapabilities(const std::shared_ptr<IWifiChip>& wifi_chip);
bool checkStatusCode(ndk::ScopedAStatus* status, WifiStatusCode expected_code);
+bool isAidlServiceAvailable(const char* instance_name);
diff --git a/wifi/aidl/vts/functional/wifi_nan_iface_aidl_test.cpp b/wifi/aidl/vts/functional/wifi_nan_iface_aidl_test.cpp
index 457d57a..654eb02 100644
--- a/wifi/aidl/vts/functional/wifi_nan_iface_aidl_test.cpp
+++ b/wifi/aidl/vts/functional/wifi_nan_iface_aidl_test.cpp
@@ -33,6 +33,8 @@
using aidl::android::hardware::wifi::IWifiNanIface;
using aidl::android::hardware::wifi::NanBandIndex;
using aidl::android::hardware::wifi::NanBandSpecificConfig;
+using aidl::android::hardware::wifi::NanBootstrappingConfirmInd;
+using aidl::android::hardware::wifi::NanBootstrappingRequestInd;
using aidl::android::hardware::wifi::NanCapabilities;
using aidl::android::hardware::wifi::NanClusterEventInd;
using aidl::android::hardware::wifi::NanConfigRequest;
@@ -46,6 +48,8 @@
using aidl::android::hardware::wifi::NanInitiateDataPathRequest;
using aidl::android::hardware::wifi::NanMatchAlg;
using aidl::android::hardware::wifi::NanMatchInd;
+using aidl::android::hardware::wifi::NanPairingConfirmInd;
+using aidl::android::hardware::wifi::NanPairingRequestInd;
using aidl::android::hardware::wifi::NanPublishRequest;
using aidl::android::hardware::wifi::NanPublishType;
using aidl::android::hardware::wifi::NanRespondToDataPathIndicationRequest;
@@ -96,6 +100,10 @@
NOTIFY_INITIATE_DATA_PATH_RESPONSE,
NOTIFY_RESPOND_TO_DATA_PATH_INDICATION_RESPONSE,
NOTIFY_TERMINATE_DATA_PATH_RESPONSE,
+ NOTIFY_INITIATE_PAIRING_RESPONSE,
+ NOTIFY_RESPOND_TO_PAIRING_INDICATION_RESPONSE,
+ NOTIFY_INITIATE_BOOTSTRAPPING_RESPONSE,
+ NOTIFY_RESPOND_TO_BOOTSTRAPPING_INDICATION_RESPONSE,
EVENT_CLUSTER_EVENT,
EVENT_DISABLED,
@@ -109,6 +117,10 @@
EVENT_DATA_PATH_CONFIRM,
EVENT_DATA_PATH_TERMINATED,
EVENT_DATA_PATH_SCHEDULE_UPDATE,
+ EVENT_PAIRING_REQUEST,
+ EVENT_PAIRING_CONFIRM,
+ EVENT_BOOTSTRAPPING_REQUEST,
+ EVENT_BOOTSTRAPPING_CONFIRM,
};
// Test code calls this function to wait for data/event callback.
@@ -214,6 +226,32 @@
parent_.notify();
return ndk::ScopedAStatus::ok();
}
+ ::ndk::ScopedAStatus eventPairingConfirm(const NanPairingConfirmInd& event) override {
+ parent_.callback_type_ = EVENT_PAIRING_CONFIRM;
+ parent_.nan_pairing_confirm_ind_ = event;
+ parent_.notify();
+ return ndk::ScopedAStatus::ok();
+ }
+ ::ndk::ScopedAStatus eventPairingRequest(const NanPairingRequestInd& event) override {
+ parent_.callback_type_ = EVENT_PAIRING_REQUEST;
+ parent_.nan_pairing_request_ind_ = event;
+ parent_.notify();
+ return ndk::ScopedAStatus::ok();
+ }
+ ::ndk::ScopedAStatus eventBootstrappingConfirm(
+ const NanBootstrappingConfirmInd& event) override {
+ parent_.callback_type_ = EVENT_BOOTSTRAPPING_CONFIRM;
+ parent_.nan_bootstrapping_confirm_ind_ = event;
+ parent_.notify();
+ return ndk::ScopedAStatus::ok();
+ }
+ ::ndk::ScopedAStatus eventBootstrappingRequest(
+ const NanBootstrappingRequestInd& event) override {
+ parent_.callback_type_ = EVENT_BOOTSTRAPPING_REQUEST;
+ parent_.nan_bootstrapping_request_ind_ = event;
+ parent_.notify();
+ return ndk::ScopedAStatus::ok();
+ }
::ndk::ScopedAStatus notifyCapabilitiesResponse(
char16_t id, const NanStatus& status,
const NanCapabilities& capabilities) override {
@@ -328,6 +366,40 @@
parent_.notify();
return ndk::ScopedAStatus::ok();
}
+ ::ndk::ScopedAStatus notifyInitiatePairingResponse(char16_t id, const NanStatus& status,
+ int32_t pairingInstanceId) override {
+ parent_.callback_type_ = NOTIFY_INITIATE_PAIRING_RESPONSE;
+ parent_.id_ = id;
+ parent_.status_ = status;
+ parent_.pairing_instance_id_ = pairingInstanceId;
+ parent_.notify();
+ return ndk::ScopedAStatus::ok();
+ }
+ ::ndk::ScopedAStatus notifyRespondToPairingIndicationResponse(
+ char16_t id, const NanStatus& status) override {
+ parent_.callback_type_ = NOTIFY_RESPOND_TO_PAIRING_INDICATION_RESPONSE;
+ parent_.id_ = id;
+ parent_.status_ = status;
+ parent_.notify();
+ return ndk::ScopedAStatus::ok();
+ }
+ ::ndk::ScopedAStatus notifyInitiateBootstrappingResponse(
+ char16_t id, const NanStatus& status, int32_t bootstrapppingInstanceId) override {
+ parent_.callback_type_ = NOTIFY_INITIATE_BOOTSTRAPPING_RESPONSE;
+ parent_.id_ = id;
+ parent_.status_ = status;
+ parent_.bootstrappping_instance_id_ = bootstrapppingInstanceId;
+ parent_.notify();
+ return ndk::ScopedAStatus::ok();
+ }
+ ::ndk::ScopedAStatus notifyRespondToBootstrappingIndicationResponse(
+ char16_t id, const NanStatus& status) override {
+ parent_.callback_type_ = NOTIFY_RESPOND_TO_BOOTSTRAPPING_INDICATION_RESPONSE;
+ parent_.id_ = id;
+ parent_.status_ = status;
+ parent_.notify();
+ return ndk::ScopedAStatus::ok();
+ }
private:
WifiNanIfaceAidlTest& parent_;
@@ -339,6 +411,8 @@
uint16_t id_;
uint8_t session_id_;
uint32_t ndp_instance_id_;
+ uint32_t pairing_instance_id_;
+ uint32_t bootstrappping_instance_id_;
uint32_t peer_id_;
NanCapabilities capabilities_;
NanClusterEventInd nan_cluster_event_ind_;
@@ -348,6 +422,10 @@
NanFollowupReceivedInd nan_followup_received_ind_;
NanMatchInd nan_match_ind_;
NanStatus status_;
+ NanPairingRequestInd nan_pairing_request_ind_;
+ NanPairingConfirmInd nan_pairing_confirm_ind_;
+ NanBootstrappingRequestInd nan_bootstrapping_request_ind_;
+ NanBootstrappingConfirmInd nan_bootstrapping_confirm_ind_;
const char* getInstanceName() { return GetParam().c_str(); }
diff --git a/wifi/aidl/vts/functional/wifi_sta_iface_aidl_test.cpp b/wifi/aidl/vts/functional/wifi_sta_iface_aidl_test.cpp
index ef7e274..5e55315 100644
--- a/wifi/aidl/vts/functional/wifi_sta_iface_aidl_test.cpp
+++ b/wifi/aidl/vts/functional/wifi_sta_iface_aidl_test.cpp
@@ -145,7 +145,7 @@
std::shared_ptr<IWifiStaIface> iface;
auto status = createStaIface(&iface);
if (status.isOk()) {
- EXPECT_GT(link_layer_stats.iface.timeSliceDutyCycleInPercent, 0);
+ EXPECT_GT(link_layer_stats.iface.links[0].timeSliceDutyCycleInPercent, 0);
}
// Disable link layer stats collection.
diff --git a/wifi/hostapd/aidl/vts/functional/Android.bp b/wifi/hostapd/aidl/vts/functional/Android.bp
index a9fdec8..1942db1 100644
--- a/wifi/hostapd/aidl/vts/functional/Android.bp
+++ b/wifi/hostapd/aidl/vts/functional/Android.bp
@@ -20,8 +20,21 @@
"libvndksupport",
],
static_libs: [
- "android.hardware.wifi-V1-ndk",
"android.hardware.wifi.hostapd-V1-ndk",
+ "VtsHalWifiV1_0TargetTestUtil",
+ "VtsHalWifiV1_5TargetTestUtil",
+ "VtsHalWifiHostapdV1_0TargetTestUtil",
+ "android.hardware.wifi.hostapd@1.0",
+ "android.hardware.wifi.hostapd@1.1",
+ "android.hardware.wifi.hostapd@1.2",
+ "android.hardware.wifi.hostapd@1.3",
+ "android.hardware.wifi@1.0",
+ "android.hardware.wifi@1.1",
+ "android.hardware.wifi@1.2",
+ "android.hardware.wifi@1.3",
+ "android.hardware.wifi@1.4",
+ "android.hardware.wifi@1.5",
+ "android.hardware.wifi-V1-ndk",
"libwifi-system-iface",
"VtsHalWifiTargetTestUtil",
],
diff --git a/wifi/hostapd/aidl/vts/functional/VtsHalHostapdTargetTest.cpp b/wifi/hostapd/aidl/vts/functional/VtsHalHostapdTargetTest.cpp
index 65ffa7b..69f1b76 100644
--- a/wifi/hostapd/aidl/vts/functional/VtsHalHostapdTargetTest.cpp
+++ b/wifi/hostapd/aidl/vts/functional/VtsHalHostapdTargetTest.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
#include <aidl/android/hardware/wifi/IWifi.h>
+#include <android/hardware/wifi/1.0/IWifi.h>
+#include <android/hardware/wifi/hostapd/1.3/IHostapd.h>
#include <VtsCoreUtil.h>
#include <aidl/Gtest.h>
@@ -23,11 +25,14 @@
#include <android/binder_manager.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
+#include <hidl/ServiceManagement.h>
+#include <hostapd_hidl_call_util.h>
+#include <hostapd_hidl_test_utils.h>
+#include <wifi_hidl_test_utils.h>
+#include <wifi_hidl_test_utils_1_5.h>
#include "wifi_aidl_test_utils.h"
-using aidl::android::hardware::wifi::IWifi;
-using aidl::android::hardware::wifi::IWifiApIface;
using aidl::android::hardware::wifi::hostapd::BandMask;
using aidl::android::hardware::wifi::hostapd::BnHostapdCallback;
using aidl::android::hardware::wifi::hostapd::ChannelBandwidth;
@@ -42,8 +47,6 @@
using android::ProcessState;
namespace {
-const std::string kWifiInstanceNameStr = std::string() + IWifi::descriptor + "/default";
-const char* kWifiInstanceName = kWifiInstanceNameStr.c_str();
const unsigned char kNwSsid[] = {'t', 'e', 's', 't', '1', '2', '3', '4', '5'};
const std::string kPassphrase = "test12345";
const std::string kInvalidMinPassphrase = "test";
@@ -54,6 +57,8 @@
const std::vector<uint8_t> kTestZeroMacAddr(6, 0x0);
const Ieee80211ReasonCode kTestDisconnectReasonCode =
Ieee80211ReasonCode::WLAN_REASON_UNSPECIFIED;
+const std::string kWifiAidlInstanceNameStr = std::string() + IWifi::descriptor + "/default";
+const char* kWifiAidlInstanceName = kWifiAidlInstanceNameStr.c_str();
inline BandMask operator|(BandMask a, BandMask b) {
return static_cast<BandMask>(static_cast<int32_t>(a) |
@@ -75,30 +80,57 @@
"/system/bin/cmd wifi get-softap-supported-features",
"wifi_softap_wpa3_sae_supported");
isBridgedSupport = testing::checkSubstringInCommandOutput(
- "/system/bin/cmd wifi get-softap-supported-features",
- "wifi_softap_bridged_ap_supported");
+ "/system/bin/cmd wifi get-softap-supported-features",
+ "wifi_softap_bridged_ap_supported");
+ if (!isAidlServiceAvailable(kWifiAidlInstanceName)) {
+ const std::vector<std::string> instances = android::hardware::getAllHalInstanceNames(
+ ::android::hardware::wifi::V1_0::IWifi::descriptor);
+ EXPECT_NE(0, instances.size());
+ wifiHidlInstanceName = instances[0];
+ }
}
virtual void TearDown() override {
- if (getWifi(kWifiInstanceName) != nullptr) {
- stopWifiService(kWifiInstanceName);
- }
+ stopVendorHal();
hostapd->terminate();
// Wait 3 seconds to allow terminate to complete
sleep(3);
}
std::shared_ptr<IHostapd> hostapd;
+ std::string wifiHidlInstanceName;
bool isAcsSupport;
bool isWpa3SaeSupport;
bool isBridgedSupport;
+ void stopVendorHal() {
+ if (isAidlServiceAvailable(kWifiAidlInstanceName)) {
+ // HIDL and AIDL versions of getWifi() take different arguments
+ // i.e. const char* vs string
+ if (getWifi(kWifiAidlInstanceName) != nullptr) {
+ stopWifiService(kWifiAidlInstanceName);
+ }
+ } else {
+ if (getWifi(wifiHidlInstanceName) != nullptr) {
+ stopWifi(wifiHidlInstanceName);
+ }
+ }
+ }
+
std::string setupApIfaceAndGetName(bool isBridged) {
+ if (isAidlServiceAvailable(kWifiAidlInstanceName)) {
+ return setupApIfaceAndGetNameAidl(isBridged);
+ } else {
+ return setupApIfaceAndGetNameHidl(isBridged);
+ }
+ }
+
+ std::string setupApIfaceAndGetNameAidl(bool isBridged) {
std::shared_ptr<IWifiApIface> wifi_ap_iface;
if (isBridged) {
- wifi_ap_iface = getBridgedWifiApIface(kWifiInstanceName);
+ wifi_ap_iface = getBridgedWifiApIface(kWifiAidlInstanceName);
} else {
- wifi_ap_iface = getWifiApIface(kWifiInstanceName);
+ wifi_ap_iface = getWifiApIface(kWifiAidlInstanceName);
}
EXPECT_NE(nullptr, wifi_ap_iface.get());
@@ -108,6 +140,21 @@
return ap_iface_name;
}
+ std::string setupApIfaceAndGetNameHidl(bool isBridged) {
+ android::sp<::android::hardware::wifi::V1_0::IWifiApIface> wifi_ap_iface;
+ if (isBridged) {
+ wifi_ap_iface = getBridgedWifiApIface_1_5(wifiHidlInstanceName);
+ } else {
+ wifi_ap_iface = getWifiApIface_1_5(wifiHidlInstanceName);
+ }
+ EXPECT_NE(nullptr, wifi_ap_iface.get());
+
+ const auto& status_and_name = HIDL_INVOKE(wifi_ap_iface, getName);
+ EXPECT_EQ(android::hardware::wifi::V1_0::WifiStatusCode::SUCCESS,
+ status_and_name.first.code);
+ return status_and_name.second;
+ }
+
IfaceParams getIfaceParamsWithoutAcs(std::string iface_name) {
IfaceParams iface_params;
ChannelParams channelParams;
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppConfigurationData.aidl
similarity index 75%
copy from audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
copy to wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppConfigurationData.aidl
index 8ad4848..2225330 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppConfigurationData.aidl
@@ -31,27 +31,13 @@
// with such a backward incompatible 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.supplicant;
@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 DppConfigurationData {
+ byte[] ssid;
+ String password;
+ byte[] psk;
+ android.hardware.wifi.supplicant.DppAkm securityAkm;
+ android.hardware.wifi.supplicant.DppConnectionKeys dppConnectionKeys;
+ boolean connStatusRequested;
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppStatusErrorCode.aidl
similarity index 75%
copy from audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
copy to wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppStatusErrorCode.aidl
index 8ad4848..d72633b 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppStatusErrorCode.aidl
@@ -31,27 +31,23 @@
// with such a backward incompatible 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.wifi.supplicant;
+@Backing(type="int") @VintfStability
+enum DppStatusErrorCode {
+ UNKNOWN = -1,
+ SUCCESS = 0,
+ NOT_COMPATIBLE = 1,
+ AUTH_FAILURE = 2,
+ UNWRAP_FAILURE = 3,
+ BAD_GROUP = 4,
+ CONFIGURE_FAILURE = 5,
+ RESPONSE_PENDING = 6,
+ INVALID_CONNECTOR = 7,
+ NO_MATCH = 8,
+ CONFIG_REJECTED = 9,
+ NO_AP = 10,
+ CONFIGURE_PENDING = 11,
+ CSR_NEEDED = 12,
+ CSR_BAD = 13,
+ NEW_KEY_NEEDED = 14,
}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIface.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIface.aidl
index 53d5770..3740a10 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIface.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIface.aidl
@@ -95,4 +95,5 @@
void stopDppInitiator();
void stopDppResponder(in int ownBootstrapId);
void stopRxFilter();
+ android.hardware.wifi.supplicant.SignalPollResult[] getSignalPollResults();
}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
index c7dd584..b54f04d 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
@@ -44,6 +44,9 @@
oneway void onDppFailure(in android.hardware.wifi.supplicant.DppFailureCode code, in String ssid, in String channelList, in char[] bandList);
oneway void onDppProgress(in android.hardware.wifi.supplicant.DppProgressCode code);
oneway void onDppSuccess(in android.hardware.wifi.supplicant.DppEventType event);
+ /**
+ * @deprecated This callback is deprecated from AIDL v2, newer HAL should call onDppConfigReceived.
+ */
oneway void onDppSuccessConfigReceived(in byte[] ssid, in String password, in byte[] psk, in android.hardware.wifi.supplicant.DppAkm securityAkm, in android.hardware.wifi.supplicant.DppConnectionKeys dppConnectionKeys);
oneway void onDppSuccessConfigSent();
oneway void onEapFailure(in byte[] bssid, in int errorCode);
@@ -57,11 +60,23 @@
oneway void onNetworkNotFound(in byte[] ssid);
oneway void onNetworkRemoved(in int id);
oneway void onPmkCacheAdded(in long expirationTimeInSec, in byte[] serializedEntry);
+ /**
+ * @deprecated This callback is deprecated from AIDL v2, newer HAL should call onSupplicantStateChanged()
+ */
oneway void onStateChanged(in android.hardware.wifi.supplicant.StaIfaceCallbackState newState, in byte[] bssid, in int id, in byte[] ssid, in boolean filsHlpSent);
oneway void onWpsEventFail(in byte[] bssid, in android.hardware.wifi.supplicant.WpsConfigError configError, in android.hardware.wifi.supplicant.WpsErrorIndication errorInd);
oneway void onWpsEventPbcOverlap();
oneway void onWpsEventSuccess();
oneway void onQosPolicyReset();
oneway void onQosPolicyRequest(in int qosPolicyRequestId, in android.hardware.wifi.supplicant.QosPolicyData[] qosPolicyData);
- oneway void onStateChangedWithAkm(in android.hardware.wifi.supplicant.StaIfaceCallbackState newState, in byte[] bssid, in int id, in byte[] ssid, in boolean filsHlpSent, in android.hardware.wifi.supplicant.KeyMgmtMask keyMgmtMask);
+ oneway void onMloLinksInfoChanged(in android.hardware.wifi.supplicant.ISupplicantStaIfaceCallback.MloLinkInfoChangeReason reason);
+ oneway void onDppConfigReceived(in android.hardware.wifi.supplicant.DppConfigurationData configData);
+ oneway void onDppConnectionStatusResultSent(in android.hardware.wifi.supplicant.DppStatusErrorCode code);
+ oneway void onBssFrequencyChanged(in int frequencyMhz);
+ oneway void onSupplicantStateChanged(in android.hardware.wifi.supplicant.SupplicantStateChangeData stateChangeData);
+ @Backing(type="int") @VintfStability
+ enum MloLinkInfoChangeReason {
+ TID_TO_LINK_MAP = 0,
+ MULTI_LINK_RECONFIG_AP_REMOVAL = 1,
+ }
}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl
index 0bdec34..bfc05a4 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl
@@ -128,6 +128,7 @@
void setWepTxKeyIdx(in int keyIdx);
void setRoamingConsortiumSelection(in byte[] selectedRcoi);
void setMinimumTlsVersionEapPhase1Param(android.hardware.wifi.supplicant.TlsVersion tlsVersion);
+ void setStrictConservativePeerMode(in boolean enable);
const int SSID_MAX_LEN_IN_BYTES = 32;
const int PSK_PASSPHRASE_MIN_LEN_IN_BYTES = 8;
const int PSK_PASSPHRASE_MAX_LEN_IN_BYTES = 63;
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/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/MloLink.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/MloLink.aidl
index 5e2c47b..f30ca94 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/MloLink.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/MloLink.aidl
@@ -36,4 +36,6 @@
parcelable MloLink {
byte linkId;
byte[] staLinkMacAddress;
+ byte tidsUplinkMap;
+ byte tidsDownlinkMap;
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/SignalPollResult.aidl
similarity index 75%
copy from audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
copy to wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/SignalPollResult.aidl
index 8ad4848..52d3f24 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/SignalPollResult.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.wifi.supplicant;
@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 SignalPollResult {
+ int linkId;
+ int currentRssiDbm;
+ int txBitrateMbps;
+ int rxBitrateMbps;
+ int frequencyMhz;
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/SupplicantStateChangeData.aidl
similarity index 75%
copy from audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
copy to wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/SupplicantStateChangeData.aidl
index 8ad4848..e6bb859 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/SupplicantStateChangeData.aidl
@@ -31,27 +31,14 @@
// with such a backward incompatible 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.supplicant;
@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 SupplicantStateChangeData {
+ android.hardware.wifi.supplicant.StaIfaceCallbackState newState;
+ int id;
+ byte[] ssid;
+ byte[] bssid;
+ android.hardware.wifi.supplicant.KeyMgmtMask keyMgmtMask;
+ int frequencyMhz;
+ boolean filsHlpSent;
}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/DppConfigurationData.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/DppConfigurationData.aidl
new file mode 100644
index 0000000..b25bc40
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/DppConfigurationData.aidl
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.wifi.supplicant;
+
+import android.hardware.wifi.supplicant.DppAkm;
+import android.hardware.wifi.supplicant.DppConnectionKeys;
+
+/**
+ * DPP configuration related information.
+ */
+@VintfStability
+parcelable DppConfigurationData {
+ /*
+ * SSID of the network.
+ */
+ byte[] ssid;
+ /*
+ * WPA2 or SAE passphrase.
+ */
+ String password;
+ /*
+ * Pre-shared key encoded in hex.
+ */
+ byte[] psk;
+ /*
+ * AKM that can be provisioned using DPP.
+ */
+ DppAkm securityAkm;
+ /*
+ * Connection keys that are used for DPP network connection.
+ */
+ DppConnectionKeys dppConnectionKeys;
+ /*
+ * Optional flag to indicate that the configurator requested connection status
+ * result.
+ * This flag is set to true if the enrollee receives the configuration response
+ * frame with sendConnStatus attribute.
+ */
+ boolean connStatusRequested;
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/DppStatusErrorCode.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/DppStatusErrorCode.aidl
new file mode 100644
index 0000000..30965d6
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/DppStatusErrorCode.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * DppStatusErrorCode: The possible values for the DPP status and error codes
+ * in the DPP protocol.
+ * See Easy Connect specification V2.0 section 8.3.4 for details.
+ */
+@VintfStability
+@Backing(type="int")
+enum DppStatusErrorCode {
+ UNKNOWN = -1,
+ SUCCESS = 0,
+ NOT_COMPATIBLE = 1,
+ AUTH_FAILURE = 2,
+ UNWRAP_FAILURE = 3,
+ BAD_GROUP = 4,
+ CONFIGURE_FAILURE = 5,
+ RESPONSE_PENDING = 6,
+ INVALID_CONNECTOR = 7,
+ NO_MATCH = 8,
+ CONFIG_REJECTED = 9,
+ NO_AP = 10,
+ CONFIGURE_PENDING = 11,
+ CSR_NEEDED = 12,
+ CSR_BAD = 13,
+ NEW_KEY_NEEDED = 14,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIface.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIface.aidl
index 9edf210..9ceb3c0 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIface.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIface.aidl
@@ -31,6 +31,7 @@
import android.hardware.wifi.supplicant.MloLinksInfo;
import android.hardware.wifi.supplicant.QosPolicyStatus;
import android.hardware.wifi.supplicant.RxFilterType;
+import android.hardware.wifi.supplicant.SignalPollResult;
import android.hardware.wifi.supplicant.WpaDriverCapabilitiesMask;
import android.hardware.wifi.supplicant.WpsConfigMethods;
@@ -781,4 +782,15 @@
* |SupplicantStatusCode.FAILURE_IFACE_INVALID|
*/
void stopRxFilter();
+
+ /**
+ * This method returns the signal poll results. Results will be for each
+ * link in case of Multiple Link Operation (MLO).
+ *
+ * @return Signal Poll Results per link.
+ * @throws ServiceSpecificException with one of the following values:
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|
+ * |SupplicantStatusCode.FAILURE_UNSUPPORTED|
+ */
+ SignalPollResult[] getSignalPollResults();
}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
index c7961fa..5001800 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
@@ -22,16 +22,18 @@
import android.hardware.wifi.supplicant.BssTmData;
import android.hardware.wifi.supplicant.BssidChangeReason;
import android.hardware.wifi.supplicant.DppAkm;
+import android.hardware.wifi.supplicant.DppConfigurationData;
import android.hardware.wifi.supplicant.DppConnectionKeys;
import android.hardware.wifi.supplicant.DppEventType;
import android.hardware.wifi.supplicant.DppFailureCode;
import android.hardware.wifi.supplicant.DppProgressCode;
+import android.hardware.wifi.supplicant.DppStatusErrorCode;
import android.hardware.wifi.supplicant.Hs20AnqpData;
-import android.hardware.wifi.supplicant.KeyMgmtMask;
import android.hardware.wifi.supplicant.OsuMethod;
import android.hardware.wifi.supplicant.QosPolicyData;
import android.hardware.wifi.supplicant.StaIfaceCallbackState;
import android.hardware.wifi.supplicant.StaIfaceReasonCode;
+import android.hardware.wifi.supplicant.SupplicantStateChangeData;
import android.hardware.wifi.supplicant.WpsConfigError;
import android.hardware.wifi.supplicant.WpsErrorIndication;
@@ -144,6 +146,9 @@
* Indicates DPP configuration received success event in Enrolee mode.
* This is also triggered when Configurator generates credentials for itself
* using generateSelfDppConfiguration() API
+ * <p>
+ * @deprecated This callback is deprecated from AIDL v2, newer HAL should call
+ * onDppConfigReceived.
*/
void onDppSuccessConfigReceived(in byte[] ssid, in String password, in byte[] psk,
in DppAkm securityAkm, in DppConnectionKeys dppConnectionKeys);
@@ -254,7 +259,8 @@
* |ssid|, |bssid| parameters must indicate the parameters of the network/AP
* which caused this state transition.
* <p>
- * This callback is deprecated from AIDL v2, newer HAL should call onStateChangedWithAkm().
+ * @deprecated This callback is deprecated from AIDL v2, newer HAL should call
+ * onSupplicantStateChanged()
*
* @param newState New State of the interface. This must be one of the |State|
* values above.
@@ -308,25 +314,68 @@
void onQosPolicyRequest(in int qosPolicyRequestId, in QosPolicyData[] qosPolicyData);
/**
- * Used to indicate a state change event on this particular iface. If this
- * event is triggered by a particular network, the |id|,
- * |ssid|, |bssid| parameters must indicate the parameters of the network/AP
- * which caused this state transition.
- *
- * @param newState New State of the interface. This must be one of the
- * |StaIfaceCallbackState| values above.
- * @param bssid BSSID of the corresponding AP which caused this state
- * change event. This must be zero'ed if this event is not
- * specific to a particular network.
- * @param id ID of the corresponding network which caused this
- * state change event. This must be invalid (-1) if this
- * event is not specific to a particular network.
- * @param ssid SSID of the corresponding network which caused this state
- * change event. This must be empty if this event is not specific
- * to a particular network.
- * @param filsHlpSent Whether FILS HLP IEs were included in this association.
- * @param keyMgmtMask current used key mgmt mask.
+ * Reason codes to be used with the callback |ISupplicantStaIfaceCallback.onMloLinksInfoChanged|
*/
- void onStateChangedWithAkm(in StaIfaceCallbackState newState, in byte[] bssid, in int id,
- in byte[] ssid, in boolean filsHlpSent, in KeyMgmtMask keyMgmtMask);
+ @VintfStability
+ @Backing(type="int")
+ enum MloLinkInfoChangeReason {
+ /**
+ * TID-to-link mapping has changed. Updated mappings will be set in
+ * |MloLinksInfo.MloLink[].tids_downlink_map| and
+ * |MloLinksInfo.MloLink[].tids_uplink_map| for each of the links.
+ *
+ * STA MLD will operate in default mode if a TID-to-link mapping is not
+ * indicated by the callback. In default mode, all TIDs are mapped to
+ * all setup links in downlink and uplink directions.
+ */
+ TID_TO_LINK_MAP = 0,
+ /**
+ * Multi-link reconfiguration - AP removal as described in
+ * IEEE 802.11be spec, section 35.3.6. This is a mandatory feature for
+ * station.
+ *
+ * Removed link will not be present in |ISupplicantStaIface.getConnectionMloLinksInfo|.
+ */
+ MULTI_LINK_RECONFIG_AP_REMOVAL = 1,
+ }
+
+ /**
+ * Used to indicate that Multi Link status has changed due to the provided
+ * reason. Upadted MLO link status can be fetched using
+ * |ISupplicantStaIface.getConnectionMloLinksInfo|
+ *
+ * |MloLink.linkId| and |MloLink.staLinkMacAddress| are not expected
+ * to change.
+ *
+ * @param reason Reason as given in MloLinkInfoChangeReason.
+ */
+ void onMloLinksInfoChanged(in MloLinkInfoChangeReason reason);
+
+ /**
+ * Indicates DPP configuration received success event in Enrollee mode.
+ * This is also triggered when Configurator generates credentials for itself
+ * using generateSelfDppConfiguration() API
+ */
+ void onDppConfigReceived(in DppConfigurationData configData);
+
+ /**
+ * Indicates that DPP connection status result frame is sent.
+ */
+ void onDppConnectionStatusResultSent(in DppStatusErrorCode code);
+
+ /**
+ * Used to indicate that the operating frequency has changed for this BSS.
+ * This event is triggered when STA switches the channel due to channel
+ * switch announcement from the connected access point.
+ *
+ * @param frequencyMhz New operating frequency in MHz.
+ */
+ void onBssFrequencyChanged(in int frequencyMhz);
+
+ /**
+ * Used to indicate a state change event on this particular iface.
+ *
+ * @param stateChangeData Supplicant state change related information.
+ */
+ void onSupplicantStateChanged(in SupplicantStateChangeData stateChangeData);
}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl
index 44512a9..750cf72 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl
@@ -1131,4 +1131,14 @@
* |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
*/
void setMinimumTlsVersionEapPhase1Param(TlsVersion tlsVersion);
+
+ /**
+ * Enable the strict conservative peer mode for EAP-SIM/AKA/AKA'
+ *
+ * @param enable true to enable, false to disable.
+ * @throws ServiceSpecificException with one of the following values:
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+ */
+ void setStrictConservativePeerMode(in boolean enable);
}
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/android/hardware/wifi/supplicant/MloLink.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/MloLink.aidl
index 0e23728..7608e0a 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/MloLink.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/MloLink.aidl
@@ -30,4 +30,32 @@
* STA Link MAC Address
*/
byte[/* 6 */] staLinkMacAddress;
+ /**
+ * Bitset where each bit indicates TID mapped to this link in uplink and
+ * downlink direction.
+ *
+ * Traffic Identifier (TID) is an identifier used to classify a packet. It
+ * is represented as a four bit number identifying the QoS traffic within
+ * MAC data service. There are 16 possible values for TID, out of only 8 are
+ * practically used to identify differentiated services.
+ *
+ * A TID-to-link mapping indicates links on which frames belonging to each
+ * TID can be exchanged. IEEE 802.11be draft 2.0 defines the mapping for TID
+ * values between 0 to 7 only. Once associated, an MLO link state is
+ * considered as active if at least one TID is mapped to the link. Link
+ * state is considered as idle if no TID is mapped to the link.
+ *
+ * TIDs can be mapped to uplink, downlink or both directions.
+ * e.g.
+ * - TID 4 is mapped to this link in uplink direction, if bit 4 in
+ * MloLink#tids_uplink_map is set.
+ * - TID 2 is mapped to both directions for this link, if bit 2 of both
+ * MloLink#tids_uplink_map and MloLink#tids_downlink_map are set.
+ *
+ * In case of default link mapping, tids_uplink_map and tids_downlink_map
+ * is set to 0xFF for all the links.
+ *
+ */
+ byte tidsUplinkMap;
+ byte tidsDownlinkMap;
}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/SignalPollResult.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/SignalPollResult.aidl
new file mode 100644
index 0000000..a3b11a0
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/SignalPollResult.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * Signal polling results.
+ */
+@VintfStability
+parcelable SignalPollResult {
+ /**
+ * Link identifier.
+ */
+ int linkId;
+ /**
+ * RSSI value in dBM.
+ */
+ int currentRssiDbm;
+ /**
+ * Last transmitted packet bit rate in Mbps.
+ */
+ int txBitrateMbps;
+ /**
+ * Last received packet bit rate in Mbps.
+ */
+ int rxBitrateMbps;
+ /**
+ * Frequency in MHz.
+ */
+ int frequencyMhz;
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/SupplicantStateChangeData.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/SupplicantStateChangeData.aidl
new file mode 100644
index 0000000..8fa5dc7
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/SupplicantStateChangeData.aidl
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+import android.hardware.wifi.supplicant.KeyMgmtMask;
+import android.hardware.wifi.supplicant.StaIfaceCallbackState;
+
+/**
+ * Supplicant state change related information.
+ */
+@VintfStability
+parcelable SupplicantStateChangeData {
+ /**
+ * New State of the interface. This must be one of the
+ * |StaIfaceCallbackState| values.
+ */
+ StaIfaceCallbackState newState;
+ /**
+ * ID of the corresponding network which caused this
+ * state change event. This must be invalid (-1) if this
+ * event is not specific to a particular network.
+ */
+ int id;
+ /**
+ * SSID of the corresponding network which caused this state
+ * change event. This must be empty if this event is not specific
+ * to a particular network.
+ */
+ byte[] ssid;
+ /**
+ * BSSID of the corresponding AP which caused this state
+ * change event. This must be zero'ed if this event is not
+ * specific to a particular network.
+ */
+ byte[/* 6 */] bssid;
+
+ /**
+ * Currently used key mgmt mask.
+ */
+ KeyMgmtMask keyMgmtMask;
+ /*
+ * Frequency of the connected channel in MHz. This must be zero if this
+ * event is not specific to a particular network.
+ */
+ int frequencyMhz;
+ /*
+ * Flag to indicate that FILS HLP IEs were included in this association.
+ * This flag is valid only for WPA_COMPLETED state change.
+ */
+ boolean filsHlpSent;
+}
diff --git a/wifi/supplicant/aidl/vts/functional/Android.bp b/wifi/supplicant/aidl/vts/functional/Android.bp
index 937fdc7..f7c619a 100644
--- a/wifi/supplicant/aidl/vts/functional/Android.bp
+++ b/wifi/supplicant/aidl/vts/functional/Android.bp
@@ -36,10 +36,21 @@
"libvndksupport",
],
static_libs: [
- "android.hardware.wifi-V1-ndk",
+ "android.hardware.wifi@1.0",
+ "android.hardware.wifi@1.1",
+ "android.hardware.wifi@1.2",
+ "android.hardware.wifi@1.3",
+ "android.hardware.wifi@1.4",
+ "android.hardware.wifi@1.5",
+ "android.hardware.wifi.supplicant@1.0",
+ "android.hardware.wifi.supplicant@1.1",
"android.hardware.wifi.supplicant-V2-ndk",
"libwifi-system",
"libwifi-system-iface",
+ "VtsHalWifiV1_0TargetTestUtil",
+ "VtsHalWifiV1_5TargetTestUtil",
+ "VtsHalWifiSupplicantV1_0TargetTestUtil",
+ "android.hardware.wifi-V1-ndk",
"VtsHalWifiTargetTestUtil",
],
test_suites: [
@@ -61,10 +72,21 @@
"libvndksupport",
],
static_libs: [
- "android.hardware.wifi-V1-ndk",
+ "android.hardware.wifi@1.0",
+ "android.hardware.wifi@1.1",
+ "android.hardware.wifi@1.2",
+ "android.hardware.wifi@1.3",
+ "android.hardware.wifi@1.4",
+ "android.hardware.wifi@1.5",
+ "android.hardware.wifi.supplicant@1.0",
+ "android.hardware.wifi.supplicant@1.1",
"android.hardware.wifi.supplicant-V2-ndk",
"libwifi-system",
"libwifi-system-iface",
+ "VtsHalWifiV1_0TargetTestUtil",
+ "VtsHalWifiV1_5TargetTestUtil",
+ "VtsHalWifiSupplicantV1_0TargetTestUtil",
+ "android.hardware.wifi-V1-ndk",
"VtsHalWifiTargetTestUtil",
],
test_suites: [
@@ -86,10 +108,21 @@
"libvndksupport",
],
static_libs: [
- "android.hardware.wifi-V1-ndk",
+ "android.hardware.wifi@1.0",
+ "android.hardware.wifi@1.1",
+ "android.hardware.wifi@1.2",
+ "android.hardware.wifi@1.3",
+ "android.hardware.wifi@1.4",
+ "android.hardware.wifi@1.5",
+ "android.hardware.wifi.supplicant@1.0",
+ "android.hardware.wifi.supplicant@1.1",
"android.hardware.wifi.supplicant-V2-ndk",
"libwifi-system",
"libwifi-system-iface",
+ "VtsHalWifiV1_0TargetTestUtil",
+ "VtsHalWifiV1_5TargetTestUtil",
+ "VtsHalWifiSupplicantV1_0TargetTestUtil",
+ "android.hardware.wifi-V1-ndk",
"VtsHalWifiTargetTestUtil",
],
test_suites: [
diff --git a/wifi/supplicant/aidl/vts/functional/supplicant_aidl_test_utils.h b/wifi/supplicant/aidl/vts/functional/supplicant_aidl_test_utils.h
new file mode 100644
index 0000000..a850e50
--- /dev/null
+++ b/wifi/supplicant/aidl/vts/functional/supplicant_aidl_test_utils.h
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <VtsCoreUtil.h>
+#include <aidl/android/hardware/wifi/IWifi.h>
+#include <android-base/logging.h>
+#include <wifi_system/supplicant_manager.h>
+
+#include "wifi_aidl_test_utils.h"
+
+using android::wifi_system::SupplicantManager;
+
+// Helper methods to interact with wifi_aidl_test_utils
+namespace SupplicantAidlTestUtils {
+const std::string kWifiInstanceNameStr = std::string() + IWifi::descriptor + "/default";
+const char* kWifiInstanceName = kWifiInstanceNameStr.c_str();
+
+// Initialize the driver and firmware to STA mode using the vendor HAL.
+void initializeDriverAndFirmware(const std::string& wifi_instance_name) {
+ // Skip if wifi instance is not set.
+ if (wifi_instance_name == "") {
+ return;
+ }
+ if (getWifi(wifi_instance_name.c_str()) != nullptr) {
+ std::shared_ptr<IWifiChip> wifi_chip = getWifiChip(wifi_instance_name.c_str());
+ int mode_id;
+ EXPECT_TRUE(configureChipToSupportConcurrencyType(wifi_chip, IfaceConcurrencyType::STA,
+ &mode_id));
+ } else {
+ LOG(WARNING) << __func__ << ": Vendor HAL not supported";
+ }
+}
+
+// Deinitialize the driver and firmware using the vendor HAL.
+void deInitializeDriverAndFirmware(const std::string& wifi_instance_name) {
+ // Skip if wifi instance is not set.
+ if (wifi_instance_name == "") {
+ return;
+ }
+ if (getWifi(wifi_instance_name.c_str()) != nullptr) {
+ stopWifiService(wifi_instance_name.c_str());
+ } else {
+ LOG(WARNING) << __func__ << ": Vendor HAL not supported";
+ }
+}
+
+bool waitForSupplicantState(bool is_running) {
+ SupplicantManager supplicant_manager;
+ int count = 50; /* wait at most 5 seconds for completion */
+ while (count-- > 0) {
+ if (supplicant_manager.IsSupplicantRunning() == is_running) {
+ return true;
+ }
+ usleep(100000);
+ }
+ LOG(ERROR) << "Unable to " << (is_running ? "start" : "stop") << " supplicant";
+ return false;
+}
+
+bool waitForSupplicantStart() {
+ return waitForSupplicantState(true);
+}
+
+bool waitForSupplicantStop() {
+ return waitForSupplicantState(false);
+}
+
+bool waitForWifiHalStop(const std::string& wifi_instance_name) {
+ std::shared_ptr<IWifi> wifi = getWifi(wifi_instance_name.c_str());
+ int count = 50; /* wait at most 5 seconds for completion */
+ while (count-- > 0) {
+ if (wifi != nullptr) {
+ bool started = false;
+ auto status = wifi->isStarted(&started);
+ if (status.isOk() && !started) {
+ return true;
+ }
+ }
+ usleep(100000);
+ wifi = getWifi(wifi_instance_name.c_str());
+ }
+ LOG(ERROR) << "Wifi HAL was not stopped";
+ return false;
+}
+
+bool waitForFrameworkReady() {
+ int waitCount = 15;
+ do {
+ // Check whether package service is ready or not.
+ if (!testing::checkSubstringInCommandOutput("/system/bin/service check package",
+ ": not found")) {
+ return true;
+ }
+ LOG(INFO) << "Framework is not ready";
+ sleep(1);
+ } while (waitCount-- > 0);
+ return false;
+}
+
+bool useAidlService() {
+ return isAidlServiceAvailable(kWifiInstanceName);
+}
+
+void startSupplicant() {
+ initializeDriverAndFirmware(kWifiInstanceName);
+ SupplicantManager supplicant_manager;
+ ASSERT_TRUE(supplicant_manager.StartSupplicant());
+ ASSERT_TRUE(supplicant_manager.IsSupplicantRunning());
+}
+
+void stopSupplicantService() {
+ SupplicantManager supplicant_manager;
+ ASSERT_TRUE(supplicant_manager.StopSupplicant());
+ deInitializeDriverAndFirmware(kWifiInstanceName);
+ ASSERT_FALSE(supplicant_manager.IsSupplicantRunning());
+}
+
+bool stopWifiFramework(const std::string& wifi_instance_name) {
+ std::system("svc wifi disable");
+ std::system("cmd wifi set-scan-always-available disabled");
+ return waitForSupplicantStop() && waitForWifiHalStop(wifi_instance_name);
+}
+
+void initializeService() {
+ ASSERT_TRUE(stopWifiFramework(kWifiInstanceName));
+ std::system("/system/bin/start");
+ ASSERT_TRUE(waitForFrameworkReady());
+ stopSupplicantService();
+ startSupplicant();
+}
+} // namespace SupplicantAidlTestUtils
diff --git a/wifi/supplicant/aidl/vts/functional/supplicant_legacy_test_utils.h b/wifi/supplicant/aidl/vts/functional/supplicant_legacy_test_utils.h
new file mode 100644
index 0000000..a20a458
--- /dev/null
+++ b/wifi/supplicant/aidl/vts/functional/supplicant_legacy_test_utils.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <VtsCoreUtil.h>
+#include <android-base/logging.h>
+#include <android/hardware/wifi/1.0/IWifi.h>
+#include <hidl/ServiceManagement.h>
+#include <supplicant_hidl_test_utils.h>
+#include <wifi_system/supplicant_manager.h>
+
+using android::wifi_system::SupplicantManager;
+
+// Helper methods to interact with supplicant_hidl_test_utils
+namespace SupplicantLegacyTestUtils {
+std::string getWifiInstanceName() {
+ const std::vector<std::string> instances = android::hardware::getAllHalInstanceNames(
+ ::android::hardware::wifi::V1_0::IWifi::descriptor);
+ EXPECT_NE(0, instances.size());
+ return instances.size() != 0 ? instances[0] : "";
+}
+
+void stopSupplicantService() {
+ stopSupplicant(getWifiInstanceName());
+}
+
+void startSupplicant() {
+ initializeDriverAndFirmware(getWifiInstanceName());
+ SupplicantManager supplicant_manager;
+ ASSERT_TRUE(supplicant_manager.StartSupplicant());
+ ASSERT_TRUE(supplicant_manager.IsSupplicantRunning());
+}
+
+void initializeService() {
+ ASSERT_TRUE(stopWifiFramework(getWifiInstanceName()));
+ std::system("/system/bin/start");
+ ASSERT_TRUE(waitForFrameworkReady());
+ stopSupplicantService();
+ startSupplicant();
+}
+} // namespace SupplicantLegacyTestUtils
diff --git a/wifi/supplicant/aidl/vts/functional/supplicant_sta_iface_aidl_test.cpp b/wifi/supplicant/aidl/vts/functional/supplicant_sta_iface_aidl_test.cpp
index d57f539..d536618 100644
--- a/wifi/supplicant/aidl/vts/functional/supplicant_sta_iface_aidl_test.cpp
+++ b/wifi/supplicant/aidl/vts/functional/supplicant_sta_iface_aidl_test.cpp
@@ -206,11 +206,26 @@
QosPolicyData /* qosPolicyData */>&) override {
return ndk::ScopedAStatus::ok();
}
- ::ndk::ScopedAStatus onStateChangedWithAkm(
- ::aidl::android::hardware::wifi::supplicant::StaIfaceCallbackState /* newState */,
- const std::vector<uint8_t>& /* bssid */, int32_t /* id */,
- const std::vector<uint8_t>& /* ssid */, bool /* filsHlpSent */,
- ::aidl::android::hardware::wifi::supplicant::KeyMgmtMask /* keyMgmtMask*/) override {
+ ::ndk::ScopedAStatus onSupplicantStateChanged(
+ const ::aidl::android::hardware::wifi::supplicant::
+ SupplicantStateChangeData& /* stateChangeData */) override {
+ return ndk::ScopedAStatus::ok();
+ }
+ ::ndk::ScopedAStatus onMloLinksInfoChanged(
+ ::aidl::android::hardware::wifi::supplicant::ISupplicantStaIfaceCallback::
+ MloLinkInfoChangeReason /* reason */) override {
+ return ndk::ScopedAStatus::ok();
+ }
+ ::ndk::ScopedAStatus onDppConfigReceived(
+ const ::aidl::android::hardware::wifi::supplicant::
+ DppConfigurationData& /* configData */) override {
+ return ndk::ScopedAStatus::ok();
+ }
+ ::ndk::ScopedAStatus onDppConnectionStatusResultSent(
+ ::aidl::android::hardware::wifi::supplicant::DppStatusErrorCode /* code */) override {
+ return ndk::ScopedAStatus::ok();
+ }
+ ::ndk::ScopedAStatus onBssFrequencyChanged(int32_t /* frequencyMhz */) override {
return ndk::ScopedAStatus::ok();
}
};
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 e5d976c..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
@@ -650,6 +651,14 @@
}
/*
+ * SetStrictConservativePeerMode
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SetStrictConversativePeerMode) {
+ EXPECT_TRUE(sta_network_->setStrictConservativePeerMode(true).isOk());
+ EXPECT_TRUE(sta_network_->setStrictConservativePeerMode(false).isOk());
+}
+
+/*
* SendNetworkEapIdentityResponse
*/
TEST_P(SupplicantStaNetworkAidlTest, SendNetworkEapIdentityResponse) {
diff --git a/wifi/supplicant/aidl/vts/functional/supplicant_test_utils.h b/wifi/supplicant/aidl/vts/functional/supplicant_test_utils.h
index 740dc9f..7eeab68 100644
--- a/wifi/supplicant/aidl/vts/functional/supplicant_test_utils.h
+++ b/wifi/supplicant/aidl/vts/functional/supplicant_test_utils.h
@@ -16,106 +16,14 @@
#pragma once
-#include <VtsCoreUtil.h>
-#include <aidl/android/hardware/wifi/IWifi.h>
-#include <android-base/logging.h>
-#include <wifi_system/supplicant_manager.h>
+#include "supplicant_aidl_test_utils.h"
+#include "supplicant_legacy_test_utils.h"
-#include "wifi_aidl_test_utils.h"
-
-using aidl::android::hardware::wifi::IfaceConcurrencyType;
-using aidl::android::hardware::wifi::IWifi;
-using aidl::android::hardware::wifi::IWifiChip;
using aidl::android::hardware::wifi::supplicant::IfaceInfo;
using aidl::android::hardware::wifi::supplicant::ISupplicant;
using aidl::android::hardware::wifi::supplicant::ISupplicantP2pIface;
using aidl::android::hardware::wifi::supplicant::ISupplicantStaIface;
using aidl::android::hardware::wifi::supplicant::KeyMgmtMask;
-using android::wifi_system::SupplicantManager;
-
-const std::string kWifiInstanceName = std::string() + IWifi::descriptor + "/default";
-
-// Initialize the driver and firmware to STA mode using the vendor HAL.
-void initializeDriverAndFirmware(const std::string& wifi_instance_name) {
- // Skip if wifi instance is not set.
- if (wifi_instance_name == "") {
- return;
- }
- if (getWifi(wifi_instance_name.c_str()) != nullptr) {
- std::shared_ptr<IWifiChip> wifi_chip = getWifiChip(wifi_instance_name.c_str());
- int mode_id;
- EXPECT_TRUE(configureChipToSupportConcurrencyType(wifi_chip, IfaceConcurrencyType::STA,
- &mode_id));
- } else {
- LOG(WARNING) << __func__ << ": Vendor HAL not supported";
- }
-}
-
-// Deinitialize the driver and firmware using the vendor HAL.
-void deInitializeDriverAndFirmware(const std::string& wifi_instance_name) {
- // Skip if wifi instance is not set.
- if (wifi_instance_name == "") {
- return;
- }
- if (getWifi(wifi_instance_name.c_str()) != nullptr) {
- stopWifiService(wifi_instance_name.c_str());
- } else {
- LOG(WARNING) << __func__ << ": Vendor HAL not supported";
- }
-}
-
-bool waitForSupplicantState(bool is_running) {
- SupplicantManager supplicant_manager;
- int count = 50; /* wait at most 5 seconds for completion */
- while (count-- > 0) {
- if (supplicant_manager.IsSupplicantRunning() == is_running) {
- return true;
- }
- usleep(100000);
- }
- LOG(ERROR) << "Supplicant not " << is_running ? "running" : "stopped";
- return false;
-}
-
-bool waitForSupplicantStart() {
- return waitForSupplicantState(true);
-}
-
-bool waitForSupplicantStop() {
- return waitForSupplicantState(false);
-}
-
-bool waitForWifiHalStop(const std::string& wifi_instance_name) {
- std::shared_ptr<IWifi> wifi = getWifi(wifi_instance_name.c_str());
- int count = 50; /* wait at most 5 seconds for completion */
- while (count-- > 0) {
- if (wifi != nullptr) {
- bool started = false;
- auto status = wifi->isStarted(&started);
- if (status.isOk() && !started) {
- return true;
- }
- }
- usleep(100000);
- wifi = getWifi(wifi_instance_name.c_str());
- }
- LOG(ERROR) << "Wifi HAL was not stopped";
- return false;
-}
-
-bool waitForFrameworkReady() {
- int waitCount = 15;
- do {
- // Check whether package service is ready or not.
- if (!testing::checkSubstringInCommandOutput("/system/bin/service check package",
- ": not found")) {
- return true;
- }
- LOG(INFO) << "Framework is not ready";
- sleep(1);
- } while (waitCount-- > 0);
- return false;
-}
std::string getStaIfaceName() {
std::array<char, PROPERTY_VALUE_MAX> buffer;
@@ -129,8 +37,7 @@
return std::string(buffer.data());
}
-bool keyMgmtSupported(std::shared_ptr<ISupplicantStaIface> iface,
- KeyMgmtMask expected) {
+bool keyMgmtSupported(std::shared_ptr<ISupplicantStaIface> iface, KeyMgmtMask expected) {
KeyMgmtMask caps;
if (!iface->getKeyMgmtCapabilities(&caps).isOk()) {
return false;
@@ -145,38 +52,22 @@
return keyMgmtSupported(iface, filsMask);
}
-void startSupplicant() {
- initializeDriverAndFirmware(kWifiInstanceName);
- SupplicantManager supplicant_manager;
- ASSERT_TRUE(supplicant_manager.StartSupplicant());
- ASSERT_TRUE(supplicant_manager.IsSupplicantRunning());
-}
-
void stopSupplicantService() {
- SupplicantManager supplicant_manager;
- ASSERT_TRUE(supplicant_manager.StopSupplicant());
- deInitializeDriverAndFirmware(kWifiInstanceName);
- ASSERT_FALSE(supplicant_manager.IsSupplicantRunning());
-}
-
-bool startWifiFramework() {
- std::system("svc wifi enable");
- std::system("cmd wifi set-scan-always-available enabled");
- return waitForSupplicantStart(); // wait for wifi to start.
-}
-
-bool stopWifiFramework(const std::string& wifi_instance_name) {
- std::system("svc wifi disable");
- std::system("cmd wifi set-scan-always-available disabled");
- return waitForSupplicantStop() && waitForWifiHalStop(wifi_instance_name);
+ // Select method based on whether the HIDL or AIDL
+ // Vendor HAL is available.
+ if (SupplicantAidlTestUtils::useAidlService()) {
+ SupplicantAidlTestUtils::stopSupplicantService();
+ } else {
+ SupplicantLegacyTestUtils::stopSupplicantService();
+ }
}
void initializeService() {
- ASSERT_TRUE(stopWifiFramework(kWifiInstanceName));
- std::system("/system/bin/start");
- ASSERT_TRUE(waitForFrameworkReady());
- stopSupplicantService();
- startSupplicant();
+ if (SupplicantAidlTestUtils::useAidlService()) {
+ SupplicantAidlTestUtils::stopSupplicantService();
+ } else {
+ SupplicantLegacyTestUtils::stopSupplicantService();
+ }
}
void addStaIface(const std::shared_ptr<ISupplicant> supplicant) {